OpenCV中一个连通域处理函数

本文详细介绍了连通域处理函数的使用方法及其实现原理,包括如何通过开闭运算平滑轮廓、去除小轮廓以及如何使用多边形或凸包拟合轮廓。并通过示例展示了如何调用该函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

作者:tornadomeet 出处: http://www.cnblogs.com/tornadomeet 欢迎转载或分享,但请务必声明文章出处。

连通域处理函数的原型:

[cpp]  view plain  copy
  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_process:

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

参数poly1_hull0:

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

参数perimScale:

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

参数number:

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

参数bounding_box:

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

参数contour_centers:

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

实现代码:

[cpp]  view plain  copy
  1. #include <iostream>   
  2. #include <opencv.hpp>   
  3.   
  4.   
  5. using namespace cv;   
  6. using namespace std;   
  7.   
  8. //Just some convienience macros   
  9. #define CV_CVX_WHITE CV_RGB(0xff,0xff,0xff)   
  10. #define CV_CVX_BLACK CV_RGB(0x00,0x00,0x00)   
  11.   
  12.   
  13. void ConnectedComponents(Mat &mask_process, int poly1_hull0, float perimScale, int number = 0,   
  14. Rect &bounding_box = Rect(), Point &contour_centers = Point(-1, -1))   
  15. {   
  16. /*下面4句代码是为了兼容原函数接口,即内部使用的是c风格,但是其接口是c++风格的*/   
  17. IplImage *mask = &mask_process.operator IplImage();   
  18. int *num = &number;   
  19. CvRect *bbs = &bounding_box.operator CvRect();   
  20. CvPoint *centers = &contour_centers.operator CvPoint();   
  21. static CvMemStorage* mem_storage = NULL;   
  22. static CvSeq* contours = NULL;   
  23. //CLEAN UP RAW MASK   
  24. //开运算作用:平滑轮廓,去掉细节,断开缺口   
  25. cvMorphologyEx( mask, mask, NULL, NULL, CV_MOP_OPEN, 1 );//对输入mask进行开操作,CVCLOSE_ITR为开操作的次数,输出为mask图像   
  26. //闭运算作用:平滑轮廓,连接缺口   
  27. cvMorphologyEx( mask, mask, NULL, NULL, CV_MOP_CLOSE, 1 );//对输入mask进行闭操作,CVCLOSE_ITR为闭操作的次数,输出为mask图像   
  28. //FIND CONTOURS AROUND ONLY BIGGER REGIONS   
  29. if( mem_storage==NULL ) mem_storage = cvCreateMemStorage(0);   
  30. else cvClearMemStorage(mem_storage);   
  31. //CV_RETR_EXTERNAL=0是在types_c.h中定义的,CV_CHAIN_APPROX_SIMPLE=2也是在该文件中定义的   
  32. CvContourScanner scanner = cvStartFindContours(mask,mem_storage,sizeof(CvContour),CV_RETR_EXTERNAL,CV_CHAIN_APPROX_SIMPLE);   
  33. CvSeq* c;   
  34. int numCont = 0;   
  35. //该while内部只针对比较大的轮廓曲线进行替换处理   
  36. while( (c = cvFindNextContour( scanner )) != NULL )   
  37. {   
  38. double len = cvContourPerimeter( c );   
  39. double q = (mask->height + mask->width) /perimScale; //calculate perimeter len threshold   
  40. if( len < q ) //Get rid of blob if it's perimeter is too small   
  41. {   
  42. cvSubstituteContour( scanner, NULL ); //用NULL代替原来的那个轮廓   
  43. }   
  44. else //Smooth it's edges if it's large enough   
  45. {   
  46. CvSeq* c_new;   
  47. if(poly1_hull0) //Polygonal approximation of the segmentation   
  48. c_new = cvApproxPoly(c,sizeof(CvContour),mem_storage,CV_POLY_APPROX_DP, 2,0);   
  49. else //Convex Hull of the segmentation   
  50. c_new = cvConvexHull2(c,mem_storage,CV_CLOCKWISE,1);   
  51. cvSubstituteContour( scanner, c_new ); //最开始的轮廓用凸包或者多项式拟合曲线替换   
  52. numCont++;   
  53. }   
  54. }   
  55. contours = cvEndFindContours( &scanner ); //结束轮廓查找操作   
  56. // PAINT THE FOUND REGIONS BACK INTO THE IMAGE   
  57. cvZero( mask );   
  58. IplImage *maskTemp;   
  59. //CALC CENTER OF MASS AND OR BOUNDING RECTANGLES   
  60. if(*num != 0)   
  61. {   
  62. int N = *num, numFilled = 0, i=0;   
  63. CvMoments moments;   
  64. double M00, M01, M10;   
  65. maskTemp = cvCloneImage(mask);   
  66. for(i=0, c=contours; c != NULL; c = c->h_next,i++ ) //h_next为轮廓序列中的下一个轮廓   
  67. {   
  68. if(i < N) //Only process up to *num of them   
  69. {   
  70. //CV_CVX_WHITE在本程序中是白色的意思   
  71. cvDrawContours(maskTemp,c,CV_CVX_WHITE, CV_CVX_WHITE,-1,CV_FILLED,8);   
  72. //Find the center of each contour   
  73. if(centers != &cvPoint(-1, -1))   
  74. {   
  75. cvMoments(maskTemp,&moments,1); //计算mask图像的最高达3阶的矩   
  76. M00 = cvGetSpatialMoment(&moments,0,0); //提取x的0次和y的0次矩   
  77. M10 = cvGetSpatialMoment(&moments,1,0); //提取x的1次和y的0次矩   
  78. M01 = cvGetSpatialMoment(&moments,0,1); //提取x的0次和y的1次矩   
  79. centers[i].x = (int)(M10/M00); //利用矩的结果求出轮廓的中心点坐标   
  80. centers[i].y = (int)(M01/M00);   
  81. }   
  82. //Bounding rectangles around blobs   
  83. if(bbs != &CvRect())   
  84. {   
  85. bbs[i] = cvBoundingRect(c); //算出轮廓c的外接矩形   
  86. }   
  87. cvZero(maskTemp);   
  88. numFilled++;   
  89. }   
  90. //Draw filled contours into mask   
  91. cvDrawContours(mask,c,CV_CVX_WHITE,CV_CVX_WHITE,-1,CV_FILLED,8); //draw to central mask   
  92. //end looping over contours   
  93. *num = numFilled;   
  94. cvReleaseImage( &maskTemp);   
  95. }   
  96. //ELSE JUST DRAW PROCESSED CONTOURS INTO THE MASK   
  97. else   
  98. {   
  99. for( c=contours; c != NULL; c = c->h_next )   
  100. {   
  101. cvDrawContours(mask,c,CV_CVX_WHITE, CV_CVX_BLACK,-1,CV_FILLED,8);   
  102. }   
  103. }   
  104. }   
  105.   
  106. int main()   
  107. {   
  108. Mat src, mask;   
  109. src = imread("test.png", 0); //以灰度图像读入   
  110. imshow("src", src);   
  111.   
  112. mask = src > 0; //转换为二值图像   
  113. imshow("mask", mask);   
  114.   
  115. ConnectedComponents(mask, 1, 8.0, 1, Rect(), Point(-1, -1)); //采用多边形拟合处理   
  116. imshow("out1", mask);   
  117.   
  118. ConnectedComponents(mask, 0, 8.0, 1, Rect(), Point(-1, -1)); //c采用凸包进行处理   
  119. imshow("out2", mask);   
  120. waitKey(0);   
  121.   
  122. return 0;   
  123. }   

 

实验结果

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

  

  其对应的mask图像:

  

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

  

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

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值