opencv学习之轮廓高级应用(轮廓匹配,几何直方图)
来源:互联网 发布:apache启动级别和顺序 编辑:程序博客网 时间:2024/06/02 02:53
最近再次用到了opencv轮廓,在这里结合作者冰山一角的博客(http://www.cnblogs.com/slysky/)以及自己的体会在此稍加说明。其程序主要参见冰山一角的Blog,遗憾的是代码是OpenCV1.0写的,等有时间再用2.4.2改写一篇。
1.轮廓的多边形逼近
2.轮廓的关键点
3.轮廓的周长和面积
4.轮廓的边界框
5.轮廓的矩
在连续情况下,图像函数为 f(x,y),那么图像的p+q阶几何矩(标准矩)定义为:
p ,q = 0,1,2……
p+q阶中心距定义为:
其中和代表图像的重心,
,
对于离散的数字图像,采用求和号代替积分:
,,p,q = 0,1,2 ……
N和M分别是图像的高度和宽度;
归一化的中心距定义为:;其中
在公式中,p对应x维度上的矩,q对应y维度上的矩,阶数表示对应的部分的指数。该计算是对轮廓界上所有像素(数目为n)进行求和。如果p和q全部为0,那么m00实际上对应轮廓边界上点的数目。
虽然可以直接计算出轮廓的矩,但是经常会用到归一化的矩(因此不同大小但是形状相同的物体会有相同的值)。同样,简单的矩依赖于所选坐标系,这意味着物体旋转后就无法正确匹配。
于是就产生了Hu矩以及其他归一化矩的函数。
Hu矩是归一化中心矩的线性组合。之所以这样做是为了能够获取代表图像某个特征的矩函数。这些矩函数对缩放,旋转和镜像映射出了(h1)具有不变性。
Hu矩是从中心矩中计算得到。即七个由归一化中心矩组合成的矩:
6.轮廓的轮廓树
结果的二分树最终将原始轮廓的形状性比编码。每个节点被它所对应的三角形的信息所注释。
这样建立的轮廓树并不太鲁棒,因为轮廓上小的改变也可能会彻底改变结果的树,同时最初的三角形是任意选取的。为了得到较好的描述需要首先使用函数cvApproxPoly()之后将轮廓排列(运用循环移动)成最初的三角形不怎么收到旋转影响的状态。
轮廓的匹配
1.Hu矩匹配
2.轮廓树匹配
3.成对几何直方图匹配
轮廓匹配源码1:
轮廓匹配源码1
几何直方图匹配方:
#include "gesrec.h"#include <stdio.h>//////////////////////////////////////////#define PI 3.14159f//轮廓面积比较函数static int gesContourCompFunc(const void* _a, const void* _b, void* userdata){int retval;double s1, s2;CvContour* a = (CvContour*)_a;CvContour* b = (CvContour*)_b;s1 = fabs(cvContourArea(a));s2 = fabs(cvContourArea(b));//s1 = a->rect.height * a->rect.width;//s2 = b->rect.height * b->rect.width;if(s1 < s2){retval = 1;}else if(s1 == s2){retval = 0;}else{retval = -1;}return retval;}//src:BGR dst:void gesFindContours(IplImage* src, IplImage* dst, CvSeq** templateContour, CvMemStorage* templateStorage, int flag){int count;//轮廓数IplImage* gray;CvMemStorage* first_sto;CvMemStorage* all_sto;CvSeq* first_cont;CvSeq* all_cont;CvSeq* cur_cont;//初始化动态内存first_sto = cvCreateMemStorage(0);first_cont = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), first_sto);all_sto = cvCreateMemStorage(0);all_cont = cvCreateSeq(0, sizeof(CvSeq), sizeof(CvSeq), all_sto);//创建源图像对应的灰度图像gray = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);cvCvtColor(src, gray, CV_BGR2GRAY);//得到图像的外层轮廓count = cvFindContours(gray, first_sto, &first_cont, sizeof(CvContour), CV_RETR_EXTERNAL, CV_CHAIN_APPROX_SIMPLE);//如果没有检测到轮廓则返回if(first_sto == NULL){return;}//将所有的轮廓都放到first_cont中for(;first_cont != 0;first_cont = first_cont->h_next){if(((CvContour* )first_cont)->rect.height * ((CvContour* )first_cont)->rect.width >=625)cvSeqPush(all_cont, first_cont);}//对轮廓按照面积进行排序cvSeqSort(all_cont, gesContourCompFunc, 0);//在dst中画出轮廓cvZero(dst);for(int i = 0;i < min(all_cont->total, 3);i++)///////////////////////次数待改{cur_cont = (CvSeq* )cvGetSeqElem(all_cont, i);if(flag != 0 && i == 0){*templateContour = cvCloneSeq(cur_cont, templateStorage);}CvScalar color = CV_RGB(rand()&255, rand()&255, rand()&255);cvDrawContours(dst, (CvSeq* )cur_cont, color, color, -1, 1, 8);}//判断原点位置以确定是否需要反转图像if(src->origin == 1){cvFlip(dst);}//释放内存cvReleaseMemStorage(&first_sto);cvReleaseMemStorage(&all_sto);cvReleaseImage(&gray);}void gesMatchContoursTemplate(IplImage* src, IplImage* dst, CvSeq** templateContour){CvSeq* contour;CvMemStorage* storage;//初始化动态内存 storage = cvCreateMemStorage(0);contour = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);//得到轮廓并进行匹配gesFindContours(src, dst, &contour, storage, 1);if(contour->total != 0)//如果得到的轮廓不为空{double result = cvMatchShapes((CvContour* )contour, (CvContour* )(*templateContour), CV_CONTOURS_MATCH_I3);printf("%.2f\n", result);/////////////////////////////////////////////}//释放内存cvReleaseMemStorage(&storage);}//模版匹配法的完整实现int gesMatchContoursTemplate2(IplImage* src, IplImage* dst, CvSeq* templateContour){CvSeq* contour;CvSeq* cur_cont;CvMemStorage* storage;double minValue, tempValue;int i, minIndex;//初始化动态内存 storage = cvCreateMemStorage(0);contour = cvCreateSeq(CV_SEQ_ELTYPE_POINT, sizeof(CvSeq), sizeof(CvPoint), storage);//得到轮廓并进行匹配minIndex = -1;gesFindContours(src, dst, &contour, storage, 1);if(contour->total != 0)//如果得到的轮廓不为空{if(templateContour->total != 0){cur_cont = (CvSeq* )cvGetSeqElem(templateContour, 0);minValue = cvMatchShapes((CvContour* )contour, (CvContour* )cur_cont, CV_CONTOURS_MATCH_I3);minIndex = 0;printf("0:%.2f\n", minValue);}for(i = 1;i < templateContour->total;i++){cur_cont = (CvSeq* )cvGetSeqElem(templateContour, i);tempValue = cvMatchShapes((CvContour* )contour, (CvContour* )cur_cont, CV_CONTOURS_MATCH_I3);if(tempValue < minValue){minValue = tempValue;minIndex = i;}printf("%d:%.2f\n", i, tempValue);}if(minValue >= 0.3){minIndex = -1;}}//打印匹配结果printf("the result is %d\n", minIndex);//释放内存cvReleaseMemStorage(&storage);return minIndex;}//找出轮廓最大的5个极大值点void gesFindContourMaxs(CvSeq* contour){int i;CvScalar center;//重心位置CvPoint* p;CvMat max;//存储5个极大值的数组double initMax[] = {-1, -1, -1, -1, -1};//初始极大值设置为-1double minValue, maxValue;//5个极大值中的最大值与最小值CvPoint minLoc;//最小值的位置double preDistance = 0;bool isCandidate = false;//是否是候选的极大值点//初始化重心位置center = cvScalarAll(0);//初始化极大值矩阵max = cvMat(1, 5, CV_64FC1, initMax);//首先求出轮廓的重心for(i = 0;i < contour->total;i++){p = (CvPoint* )cvGetSeqElem(contour, i);center.val[0] += p->x;center.val[1] += p->y;}center.val[0] /= contour->total;center.val[1] /= contour->total;//遍历轮廓,找出所有的极大值点for(i = 0;i < contour->total;i++){p = (CvPoint* )cvGetSeqElem(contour, i);double distance = sqrt(pow(center.val[0] - p->x, 2) + pow(center.val[1] - p->y, 2));if(distance > preDistance){isCandidate = true;}else if(distance < preDistance && isCandidate == true){cvMinMaxLoc(&max, &minValue, &maxValue, &minLoc);if(distance > minValue){cvmSet(&max, minLoc.y, minLoc.x, distance);}isCandidate = false;}else{isCandidate = false;}preDistance = distance;}//打印5个极大值printf("%.2f %.2f %.2f %.2f %.2f\n", cvmGet(&max, 0, 0), cvmGet(&max, 0, 1), cvmGet(&max, 0, 2), cvmGet(&max, 0, 3), cvmGet(&max, 0, 4));}//计算轮廓的pair-wise几何直方图CvHistogram* gesCalcContoursPGH(CvSeq* contour){CvHistogram* hist;//成对几何直方图CvContour* tempCont;//得到成对几何直方图第二个维度上的范围tempCont = (CvContour* )contour;cvBoundingRect(tempCont, 1);int sizes[2] = {60, 200};float ranges[2][2] = {{0,PI}, {0,200}};float** rangesPtr = new float* [2];rangesPtr[0] = ranges[0];rangesPtr[1] = ranges[1];//初始化几何直方图hist = cvCreateHist(2, sizes, CV_HIST_ARRAY, rangesPtr, 1);//计算轮廓的成对几何直方图cvCalcPGH(contour, hist);return hist;}//对轮廓的pair-wise几何直方图进行匹配void gesMatchContoursPGH(CvSeq* contour, CvHistogram* templateHist){CvHistogram* hist;//得到轮廓的成对几何直方图hist = gesCalcContoursPGH(contour);//归一化直方图cvNormalizeHist(templateHist, 1);cvNormalizeHist(hist, 1);//直方图匹配double result = cvCompareHist(hist, templateHist, CV_COMP_INTERSECT);printf("result:%.2f\n", result);//释放内存cvReleaseHist(&hist);}
- opencv学习之轮廓高级应用(轮廓匹配,几何直方图)
- OpenCv轮廓高级应用(轮廓匹配,几何直方图)
- opencv轮廓高级应用(轮廓匹配,几何直方图)
- opencv轮廓高级应用(轮廓匹配,几何直方图)
- OpenCv轮廓高级应用(轮廓匹配,几何直方图)
- opencv轮廓高级应用(轮廓匹配,几何直方图)
- (转)opencv轮廓高级应用(轮廓匹配,几何直方图)
- opencv轮廓高级应用(轮廓匹…
- opencv轮廓高级应用(轮廓匹…
- opencv的轮廓高级应用
- OpenCV轮廓、多边形逼近、关键点、周长和面积、边界框、矩、轮廓树、凹凸包、几何直方图、匹配
- OpenCV轮廓、多边形逼近、关键点、周长和面积、边界框、矩、轮廓树、凹凸包、几何直方图、匹配
- 【OpenCV学习笔记】三十、轮廓特征属性及应用(七)—位置关系及轮廓匹配
- openCV学习笔记(3):opencv轮廓检测应用例子
- opencv学习之寻找轮廓并绘制轮廓
- opencv 轮廓应用
- opencv之轮廓特征属性及应用
- opencv之轮廓特征属性及应用
- java 异步转同步工具类
- IIS站点禁用WebDav
- openfire3.10.3版 源码编译部署到本地eclipse
- [Android实例] 带clean按钮的输入框
- iOS crash log 解析 symbol address = stack address - slide 运行时获取slide的api 利用dwarfdump从dsym文件中得到symbol
- opencv学习之轮廓高级应用(轮廓匹配,几何直方图)
- ios系统获取ssid
- 基于jquery封装的一个简单web右键菜单
- fastboot 卡在 waiting for device
- C语言概览
- bzoj2728: [HNOI2012]与非
- 控制精灵以相同的速度在不同设备上移动
- Spark源码系列之Spark内核——Storage模块
- 猜数字游戏的提示