OpenCV cvFindContours - 如何分离轮廓的组成部分

13

我一直在研究OpenCV,并且通过反复尝试已经成功学习了如何在照片中检测圆形(硬币)。一切都工作得很好,只有当我把硬币直接放在一起时出现问题(如下图所示,请忽略第二幅图像颠倒的事实)。

原始照片 找到的轮廓

看起来由于硬币之间距离太近,cvFindContours认为它们是同一个对象。我的问题是如何将这些轮廓分开为不同的对象,或获取已经分开的轮廓列表。

我用于cvFindContours的参数是:

cvFindContours( img, storage, &contour, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0) );
任何帮助或建议将不胜感激。

3
从您的“after”图像中,您可以使用修改后的霍夫变换(http://opencv.willowgarage.com/documentation/STRAWMAN/cpp/feature_detection.html#cv-houghcircles)来在图像中检测圆形,它应该会给出合理的结果。 - etarion
2个回答

13

这不是很好,但它展示了如何到达那里:

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);

在此输入图片描述


谢谢您的回复,我在第一篇帖子中没有提到的是保留每个硬币的大小很重要,因为该项目旨在根据硬币的大小确定其价值。我会尝试进行一些调整以提高准确性。再次感谢。 - Grinneh

3

您可以尝试对图像进行阈值处理 (cvThreshold),然后腐蚀 (cvErode) 生成的二进制图像以分离硬币。 然后找到腐蚀图像的轮廓。


1
谢谢您的建议,但我发现将图像侵蚀到可以分离轮廓的程度会导致硬币不再看起来像圆形。稍微失去一点圆形的准确性是可以接受的,但总体上我想尽可能地保留它。 - Grinneh
是的,在OpenCV书中,这种方法也被建议用于分离显微镜图像上的细胞。 - Valentin H

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接