web-dev-qa-db-ja.com

OpenCVcvFindContours-輪郭のコンポーネントを分離するにはどうすればよいですか

私はOpenCVで遊んでいて、たくさんの試行錯誤を繰り返して、写真の円(コイン)を検出する方法を学ぶことができました。コインを直接並べて配置する場合を除いて、すべてがうまく機能しています(以下に示すように、2番目の画像が上下逆になっているという事実は無視してください)。

Original PhotoContours Found

コインが非常に接近しているため、cvFindContoursはそれらが同じオブジェクトであると考えているようです。私の質問は、これらの輪郭を別々のオブジェクトに分離する方法、またはすでに分離されている輪郭のリストを取得する方法です。

CvFindContoursに使用したパラメーターは次のとおりです。

cvFindContours( img, storage, &contour, sizeof(CvContour), CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, cvPoint(0, 0) );

どんな助けやアドバイスも大歓迎です。

13
Grinneh

これは素晴らしいことではありませんが、そこに到達する方法を示しています。

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

enter image description here

13
karlphillip

画像をしきい値処理( cvThreshold )してから、結果のバイナリ画像を侵食( cvErode )して、コインを分離することができます。次に、侵食された画像の輪郭を見つけます。

3
Karl Voigtland