OpenCV cvFindContours - 如何分离轮廓的组件
Posted
技术标签:
【中文标题】OpenCV cvFindContours - 如何分离轮廓的组件【英文标题】:OpenCV cvFindContours - how do I separate components of a contour 【发布时间】:2011-08-27 23:56:55 【问题描述】:我一直在使用 OpenCV,并且通过大量的试验和错误设法学会了如何检测照片中的圆圈(硬币)。一切都很好,除了我将硬币直接放在彼此旁边(如下所示,忽略第二张图片倒置的事实)。
似乎是因为硬币靠得很近,cvFindContours 认为它们是同一个物体。我的问题是如何将这些轮廓分成单独的对象,或者获取已经分离的轮廓列表。
我用于 cvFindContours 的参数是:
cvFindContours( img, storage, &contour, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0) );
任何帮助或建议将不胜感激。
【问题讨论】:
从您的“后”图像中,您可以使用修改后的霍夫变换 (opencv.willowgarage.com/documentation/STRAWMAN/cpp/…) 来检测图像中的圆圈,它应该会给您合理的结果 【参考方案1】:这不是很好,但它显示了如何到达那里:
IplImage* src = cvLoadImage(argv[1], CV_LOAD_IMAGE_UNCHANGED);
IplImage* gray = cvCreateImage(cvGetSize(src), IPL_DEPTH_8U, 1);
cvCvtColor(src, gray, CV_BGR2GRAY);
cvSmooth(gray, gray, CV_GAUSSIAN, 7, 7);
IplImage* cc_img = cvCreateImage(cvGetSize(gray), gray->depth, 3);
cvSetZero(cc_img);
CvScalar(ext_color);
cvCanny(gray, gray, 10, 30, 3);
CvMemStorage* storage = cvCreateMemStorage(0);
CvSeq* circles = cvHoughCircles(gray, storage, CV_HOUGH_GRADIENT, 1, src->height/6, 100, 50);
cvCvtColor(gray, src, CV_GRAY2BGR);
for (size_t i = 0; i < circles->total; i++)
// round the floats to an int
float* p = (float*)cvGetSeqElem(circles, i);
cv::Point center(cvRound(p[0]), cvRound(p[1]));
int radius = cvRound(p[2]);
// draw the circle center
//cvCircle(cc_img, center, 3, CV_RGB(0,255,0), -1, 8, 0 );
// draw the circle outline
cvCircle(cc_img, center, radius+1, CV_RGB(0,0,255), 2, 8, 0 );
//printf("x: %d y: %d r: %d\n", center.x, center.y, radius);
CvMemStorage *mem;
mem = cvCreateMemStorage(0);
CvSeq *contours = 0;
cvCvtColor(cc_img, gray, CV_BGR2GRAY);
// Use either this:
int n = cvFindContours(gray, mem, &contours, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE, cvPoint(0,0));
// Or this:
//int n = cvFindContours(gray, mem, &contours, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0,0));
for (; contours != 0; contours = contours->h_next)
ext_color = CV_RGB( rand()&255, rand()&255, rand()&255 ); //randomly coloring different contours
cvDrawContours(cc_img, contours, ext_color, CV_RGB(0,0,0), -1, CV_FILLED, 8, cvPoint(0,0));
cvSaveImage("out.png", cc_img);
【讨论】:
感谢您的回复,我在第一篇文章中没有提到的是保持每枚硬币的大小很重要,因为该项目旨在根据其大小确定每枚硬币的价值。我会看看我是否可以以某种方式调整它以提高准确性。再次感谢【参考方案2】:您可以尝试对图像进行阈值处理 (cvThreshold),然后腐蚀 (cvErode) 生成的二进制图像以分离硬币。然后找到侵蚀图像的轮廓。
【讨论】:
感谢您的建议,但我发现将图像腐蚀到可以分离轮廓的程度,导致硬币不再看起来像圆形。失去一点圆精度是可以的,但总的来说我想尽可能地保留它 是的,OpenCV 书中也建议使用这种方法在显微镜图像上分离细胞。以上是关于OpenCV cvFindContours - 如何分离轮廓的组件的主要内容,如果未能解决你的问题,请参考以下文章
cvCalcPGH 与 cvFindContours 的使用
用C++编写的图像处理函数,使用opencv2.3.1a,在Eclipse下编译,但cvFindContours函数报错