OpenCV cvFindContours — как мне разделить компоненты контура

#c #opencv #image-processing #geometry #object-detection

#c #opencv #обработка изображений #геометрия #обнаружение объекта

Вопрос:

Я поиграл с OpenCV и с помощью множества проб и ошибок сумел научиться определять круги (монеты) на фотографии. Все работает отлично, за исключением того, что я размещаю монеты непосредственно рядом друг с другом (как показано ниже, игнорируйте тот факт, что 2-е изображение перевернуто).

Оригинальное фото
Контуры найдены

Похоже, из-за того, что монеты расположены так близко друг к другу, cvFindContours считают, что это один и тот же объект. Мой вопрос в том, как я могу разделить эти контуры на их отдельные объекты или получить список контуров, которые уже разделены.

Параметры, которые я использовал для cvFindContours, следующие:

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

Буду признателен за любую помощь или совет.

Комментарии:

1. Исходя из вашего изображения «после», вы могли бы использовать модифицированное преобразование Хафа ( 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: %dn", 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, amp;contours, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_NONE, cvPoint(0,0));
// Or this:
//int n = cvFindContours(gray, mem, amp;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()amp;255, rand()amp;255, rand()amp;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);
  

введите описание изображения здесь

Комментарии:

1. Спасибо за ваш ответ, чего я не упомянул в первом сообщении, так это того, что сохранение размера каждой монеты было важно, поскольку проект должен был определять, какая ценность каждой монеты основана на ее размере. Я посмотрю, смогу ли я как-то настроить это для точности. Еще раз спасибо

Ответ №2:

Вы могли бы попробовать установить пороговое значение (cvThreshold) изображения, а затем стереть (cvErode) полученное двоичное изображение, чтобы разделить монеты. Затем найдите контуры размытого изображения.

Комментарии:

1. Спасибо за предложение, но я обнаружил, что стирание изображения до такой степени, чтобы я мог отделять контуры, привело к тому, что монеты больше не выглядели как круги. Небольшая потеря точности окружности — это нормально, но в целом я хочу сохранить ее как можно больше

2. Да, этот способ также предлагается в книге OpenCV для разделения ячеек на изображении под микроскопом .