提取轮廓在OpenCV里有一个函数
cvFindContours
:
- int
cvFindContours( CvArr* image, CvMemStorage* storage, CvSeq** first_contour,int header_size=sizeof(CvContour),int mode=CV_RETR_LIST,int method=CV_CHAIN_APPROX_SIMPLE, CvPoint offset=cvPoint(0,0) );
这个函数用起来很方便,但是随着你使用的深入,你会发现有一些迷惑在这里。比如当你提取轮廓时只需要最外围的一个轮廓,但是你会发现当轮廓画出来时是好几个;当你需要找一个最大轮廓时却发现找出来的却根本就不是你想要的那个。带着这样问题我们再来仔细看看
cvFindContours这个函数。
下边的是一位仁兄写的测试程序和测试图片,说明提取轮廓的两种方法及绘制轮廓中最大等级分析
的问题,非常感谢他的分享,原文戳
这里:
-
-
-
- #include
"stdafx.h" - #include
"cv.h" - #include
"highgui.h" -
- int
main() - {
-
IplImage* img = cvLoadImage("lena.jpg", CV_LOAD_IMAGE_GRAYSCALE); -
IplImage* img_temp = cvCreateImage(cvGetSize(img), 8, 1); -
-
cvThreshold(img, img, 128, 255, CV_THRESH_BINARY); -
-
CvMemStorage* mem_storage = cvCreateMemStorage(0); -
CvSeq *first_contour = NULL, *c = NULL; -
-
// -
// 1、 -
cvNamedWindow("contour1"); -
cvCopyImage(img, img_temp); -
double t = (double)cvGetTickCount(); -
cvFindContours(img_temp, mem_storage, &first_contour); -
cvZero(img_temp); -
cvDrawContours( -
img_temp, -
first_contour, -
cvScalar(100), -
cvScalar(100), -
1 -
); -
t = (double)cvGetTickCount() - t; -
cvShowImage("contour1", img_temp); -
-
printf("run1 = %gms\n", t/(cvGetTickFrequency()*1000.)); -
-
cvClearMemStorage(mem_storage); -
-
// -
// 2、 -
cvNamedWindow("contour2"); -
cvCopyImage(img, img_temp); -
t = (double)cvGetTickCount(); -
CvContourScanner scanner = cvStartFindContours(img_temp, mem_storage); -
while (cvFindNextContour(scanner)); -
first_contour = cvEndFindContours(&scanner); -
-
cvZero(img_temp); -
cvDrawContours( -
img_temp, -
first_contour, -
cvScalar(100), -
cvScalar(100), -
1 -
); -
t = (double)cvGetTickCount() - t; -
cvShowImage("contour2", img_temp); -
-
printf("run2 = %gms\n", t/(cvGetTickFrequency()*1000.)); -
-
cvClearMemStorage(mem_storage); -
cvReleaseImage(&img); -
cvReleaseImage(&img_temp); -
-
cvWaitKey(); -
-
-
-
-
-
// -
// 上述两种方法完成了对轮廓的提取,如想绘制轮廓都得配合cvDrawContours来使用 -
// 而cvDrawContours 函数第5个参数为 max_level 经查ICVL含义如下: -
// -
// 绘制轮廓的最大等级。如果等级为0,绘制单独的轮廓。如果为1,绘制轮廓及在其后的相同的级别下轮廓。 -
// 如果值为2,所有的轮廓。如果等级为2,绘制所有同级轮廓及所有低一级轮廓,诸此种种。如果值为负数, -
// 函数不绘制同级轮廓,但会升序绘制直到级别为abs(max_level)-1的子轮廓。 -
// -
// 相信好多读者初次都无法理解等级的含义,而且测试时候输入>=1 的整数效果几乎一样 -
// 只有提取轮廓时候的提取模式设为 CV_RETR_CCOMP CV_RETR_TREE 时这个参数才有意义 -
// -
// 经查FindContours 函数里面这样介绍提取模式(mode)的这两个参数: -
// CV_RETR_CCOMP - 提取所有轮廓,并且将其组织为两层的 hierarchy: 顶层为连通域的外围边界,次层为洞的内层边界。 -
// CV_RETR_TREE - 提取所有轮廓,并且重构嵌套轮廓的全部 hierarchy -
// -
// 下面用第一种方法进行测试 -
-
cvNamedWindow("contour_test"); -
cvNamedWindow("contour_raw"); -
img = cvLoadImage("contour.jpg", CV_LOAD_IMAGE_GRAYSCALE); -
cvShowImage("contour_raw", img); -
cvThreshold(img, img, 128, 255, CV_THRESH_BINARY); -
img_temp = cvCloneImage(img); -
cvFindContours( -
img_temp, -
mem_storage, -
&first_contour, -
sizeof(CvContour), -
CV_RETR_CCOMP //#1 需更改区域 -
); -
-
cvZero(img_temp); -
cvDrawContours( -
img_temp, -
first_contour, -
cvScalar(100), -
cvScalar(100), -
1 //#2 需更改区域 -
); -
cvShowImage("contour_test", img_temp); -
-
-
-
-
cvWaitKey(); -
cvReleaseImage(&img); -
cvReleaseImage(&img_temp); -
cvReleaseMemStorage(&mem_storage); -
cvDestroyAllWindows(); -
return 0; - }
原图
图一
图二
图三
图四
图五