2011-05-18 8 views
12

He estado jugando con OpenCV y con una gran cantidad de intentos de prueba y error he podido aprender a detectar círculos (monedas) en una foto. Todo funciona muy bien, excepto cuando coloco monedas directamente una al lado de la otra (como se ve a continuación, ignore el hecho de que la segunda imagen está boca abajo).OpenCV cvFindContours - cómo separe los componentes de un contorno

Original Photo Contours Found

Parece pues que las monedas están tan cerca cvFindContours piensan que son el mismo objeto. Mi pregunta es cómo puedo separar estos contornos en objetos separados u obtener una lista de contornos que ya están separados.

Los parámetros que utilicé para cvFindContours son:

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

Cualquier ayuda o consejo sería muy apreciada.

+3

Desde el "después" de la imagen, se puede utilizar un Hough modificada transformar (http: //opencv.willowgarage .com/documentation/STRAWMAN/cpp/feature_detection.html # cv-houghcircles) para detectar círculos en su imagen, debería proporcionarle resultados razonables – etarion

Respuesta

13

Esto no es grande, pero muestra cómo llegar:

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

+0

Gracias por su respuesta, lo que no mencioné en la primera publicación es que preservar el tamaño de cada moneda era importante, ya que el proyecto debía determinar el valor de cada moneda en función de su tamaño. Veré si puedo ajustarlo de alguna manera para mayor precisión. Gracias de nuevo – Grinneh

+0

Ok, genial. Cada vez que encuentres una respuesta interesante, puedes votarla. Disfruta nuestro sitio – karlphillip

3

Puede probar el umbral (cvThreshold) de la imagen y luego erosionar (cvErode) la imagen binaria resultante para separar las monedas. Luego encuentra los contornos de la imagen erosionada.

+1

Gracias por la sugerencia, pero descubrí que erosionaba la imagen hasta el punto en que podía separarla los contornos dieron como resultado que las monedas ya no se vean como círculos. Perder un poco la precisión del círculo está bien, pero en general quiero preservarlo tanto como sea posible – Grinneh

+0

Sí, de esta manera también se sugiere en el libro de OpenCV para separar las células en una imagen de microscopio. –

Cuestiones relacionadas