python opencv 连通域_OpenCV中一个连通域处理函数

作者:tornadomeet 出处:http://www.cnblogs.com/tornadomeet 欢迎转载或分享,但请务必声明文章出处。连通域处理函数的原型

前言

在图像处理过程中,经常会遇到这样一部分图像,图像的整体部分如果人来看的话一眼就能看出,但是它的内部由于有各种小缺口,导致断开了,这样在 计算机“眼”里就被认为是断开的,为了使图像达到适应人眼的感觉,需要将这些缺口和断开的口给连接上去,这就需要用到计算机图形学中的连通域处理技术。本 文给出一个简单的连通域处理函数,当然这个函数是来自OpenCV著名教程Learning OpenCV中,只不过它的接口是基于c版本的OpenCV,而到目前为止,基于C++接口的OpenCV已经是主流,所以我将其接口改成了c++版的, 但是其内部一些代码基本没有动它。

开发环境:OpenCV2.4.3+QtCreator2.5.1

实验基础

首先来看这个连通域处理函数的形式:

void ConnectedComponents(Mat &mask_process,  int poly1_hull0,  float perimScale,  int number = 0,  Rect &bounding_box = Rect(),  Point &contour_centers = Point(-1, -1));

参数mask表示的是需要进行连通域处理二值图像。

参数poly1_hull0表示轮廓边缘是否采用多边形拟合,如果该参数为1,则表示采用多边形拟合,否则采用凸包拟合。

参数perimScale是用来将那些小的轮廓去掉,那些小的轮廓时指它的周长小于(mask长+宽)/perimScale。当然你在其内部代码也可以该为面积来判断。

参数num表示实际需要处理最多的轮廓的个数(如果输入的mask有多个轮廓的话),这里的处理是指计算出这些轮廓的外接矩形和中心点。默认值为0,表示函数内部不需要处理这些外接矩形和中心点。

参数bbs表示的是处理完后对应轮廓的外接矩形,默认值为Rect(),表示不需要返回这些外接矩形。

参数centers表示处理完后对应轮廓的中心点坐标,默认值为Point(-1, -1),表示不需要返回这些中心点。

C/C++知识点总结:

如果一些函数需要默认值的话,可以直接在函数定义的时候指定,该指定并不一定是具体的某个值,也可以是空值等等。另外在函数内部实现时,有时候要注意默认值的特殊性。

实验结果

所需处理原始图像的灰度图:

其对应的mask图像:

使用多项式拟合的连通域处理后图像:

使用凸包集拟合的连通域处理后的图像:

实验代码及注释(附录有工程code下载地址):

main.cpp:

#include #include using namespacecv;using namespacestd;//Just some convienience macros #define CV_CVX_WHITE CV_RGB(0xff,0xff,0xff) #define CV_CVX_BLACK CV_RGB(0x00,0x00,0x00) void ConnectedComponents(Mat &mask_process, int poly1_hull0, float perimScale, int number = 0, Rect&bounding_box = Rect(), Point &contour_centers = Point(-1, -1)) {/*下面4句代码是为了兼容原函数接口,即内部使用的是c风格,但是其接口是c++风格的*/IplImage*mask = &mask_process.operatorIplImage();int *num = &number; CvRect*bbs = &bounding_box.operatorCvRect(); CvPoint*centers = &contour_centers.operatorCvPoint();static CvMemStorage* mem_storage =NULL;static CvSeq* contours =NULL;//CLEAN UP RAW MASK//开运算作用:平滑轮廓,去掉细节,断开缺口 cvMorphologyEx( mask, mask, NULL, NULL, CV_MOP_OPEN, 1 );//对输入mask进行开操作,CVCLOSE_ITR为开操作的次数,输出为mask图像//闭运算作用:平滑轮廓,连接缺口 cvMorphologyEx( mask, mask, NULL, NULL, CV_MOP_CLOSE, 1 );//对输入mask进行闭操作,CVCLOSE_ITR为闭操作的次数,输出为mask图像//FIND CONTOURS AROUND ONLY BIGGER REGIONS if( mem_storage==NULL ) mem_storage = cvCreateMemStorage(0);elsecvClearMemStorage(mem_storage);//CV_RETR_EXTERNAL=0是在types_c.h中定义的,CV_CHAIN_APPROX_SIMPLE=2也是在该文件中定义的 CvContourScanner scanner = cvStartFindContours(mask,mem_storage,sizeof(CvContour),CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE); CvSeq*c;int numCont = 0;//该while内部只针对比较大的轮廓曲线进行替换处理 while( (c = cvFindNextContour( scanner )) !=NULL ) {double len =cvContourPerimeter( c );double q = (mask->height + mask->width) /perimScale; //calculate perimeter len threshold if( len < q ) //Get rid of blob if it's perimeter is too small { cvSubstituteContour( scanner, NULL );//用NULL代替原来的那个轮廓 }else //Smooth it's edges if it's large enough { CvSeq*c_new;if(poly1_hull0) //Polygonal approximation of the segmentation c_new = cvApproxPoly(c,sizeof(CvContour),mem_storage,CV_POLY_APPROX_DP, 2,0);else //Convex Hull of the segmentation c_new = cvConvexHull2(c,mem_storage,CV_CLOCKWISE,1); cvSubstituteContour( scanner, c_new );//最开始的轮廓用凸包或者多项式拟合曲线替换 numCont++; } } contours= cvEndFindContours( &scanner ); //结束轮廓查找操作//PAINT THE FOUND REGIONS BACK INTO THE IMAGE cvZero( mask ); IplImage*maskTemp;//CALC CENTER OF MASS AND OR BOUNDING RECTANGLES if(*num != 0) {int N = *num, numFilled = 0, i=0; CvMoments moments;doubleM00, M01, M10; maskTemp=cvCloneImage(mask);for(i=0, c=contours; c != NULL; c = c->h_next,i++ ) //h_next为轮廓序列中的下一个轮廓 {if(i < N) //Only process up to *num of them {//CV_CVX_WHITE在本程序中是白色的意思 cvDrawContours(maskTemp,c,CV_CVX_WHITE, CV_CVX_WHITE,-1,CV_FILLED,8);//Find the center of each contour if(centers != &cvPoint(-1, -1)) { cvMoments(maskTemp,&moments,1); //计算mask图像的最高达3阶的矩 M00 = cvGetSpatialMoment(&moments,0,0); //提取x的0次和y的0次矩 M10 = cvGetSpatialMoment(&moments,1,0); //提取x的1次和y的0次矩 M01 = cvGetSpatialMoment(&moments,0,1); //提取x的0次和y的1次矩 centers[i].x = (int)(M10/M00); //利用矩的结果求出轮廓的中心点坐标 centers[i].y = (int)(M01/M00); }//Bounding rectangles around blobs if(bbs != &CvRect()) { bbs[i]= cvBoundingRect(c); //算出轮廓c的外接矩形 } cvZero(maskTemp); numFilled++; }//Draw filled contours into mask cvDrawContours(mask,c,CV_CVX_WHITE,CV_CVX_WHITE,-1,CV_FILLED,8); //draw to central mask } //end looping over contours *num =numFilled; cvReleaseImage(&maskTemp); }//ELSE JUST DRAW PROCESSED CONTOURS INTO THE MASK else{for( c=contours; c != NULL; c = c->h_next ) { cvDrawContours(mask,c,CV_CVX_WHITE, CV_CVX_BLACK,-1,CV_FILLED,8); } } }intmain() { Mat src, mask; src= imread("test.png", 0); //以灰度图像读入 imshow("src", src); mask= src > 0; //转换为二值图像 imshow("mask", mask); ConnectedComponents(mask,1, 8.0, 1, Rect(), Point(-1, -1)); //采用多边形拟合处理 imshow("out1", mask); ConnectedComponents(mask,0, 8.0, 1, Rect(), Point(-1, -1)); //c采用凸包进行处理 imshow("out2", mask); waitKey(0);return 0; }

实验总结:通过该连通域处理,能够达到一定效果。

参考资料:

Bradski, G. and A. Kaehler (2008). Learning OpenCV: Computer vision with the OpenCV library, O'Reilly Media.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值