Python y OpenCV. ¿Cómo detecto todos los círculos (rellenos) / objetos redondos en una imagen?

Estoy tratando de hacer un progtwig que abra una imagen, la escanee en busca de círculos / formas redondas y devuelva las coordenadas para que pueda usar la función cv.Circle para dibujar círculos sobre el círculo detectado.

Mi pregunta es: ¿Cómo obtengo las coordenadas / radios de los círculos detectados en una imagen usando cv.HoughCircles() ?

Al usar esta página, descubrí cómo detectar los círculos (lo cual me tomó mucho tiempo para averiguarlo ya que no entiendo términos como umbral y la documentación de OpenCV para Python es realmente mala, casi ninguno). Desafortunadamente, en esa página no se muestra cómo extraer la información de cada círculo detectado desde el CvMat creado. ¿Cómo extraigo esa información / hay alguna otra forma (por ejemplo, con MemoryStorage() )?

Este es mi código hasta ahora:

 import cv, opencv def main(): im = cv.LoadImageM("Proba.jpg") gray = cv.CreateImage(cv.GetSize(im), 8, 1) edges = cv.CreateImage(cv.GetSize(im), 8, 1) cv.CvtColor(im, gray, cv.CV_BGR2GRAY) cv.Canny(gray, edges, 50, 200, 3) cv.Smooth(gray, gray, cv.CV_GAUSSIAN, 9, 9) storage = cv.CreateMat(im.rows, 1, cv.CV_32FC3) cv.HoughCircles(edges, storage, cv.CV_HOUGH_GRADIENT, 2, gray.height/4, 200, 100) # Now, supposing it found circles, how do I extract the information? print storage.r if __name__ == '__main__': main() 

Además, ¿qué valor deben tener los dos últimos parámetros de HoughCircles para que pueda detectar círculos realmente pequeños (como 3 mm en la pantalla)?

¡Gracias a todos por su tiempo y esfuerzo tratando de ayudarme!

La imagen con la que estoy trabajando es la siguiente: introduzca la descripción de la imagen aquí

Los dos últimos parámetros son los que parecen pasarse a cv.Canny() , lo que implica que se llama a cv.HoughCircles() desde dentro de cv.HoughCircles() . No estoy muy seguro de eso.

En cuanto a los tamaños, parece que los dos parámetros siguientes (después de 200, 100) ponen por defecto en 0 , lo que podría significar que se detectan todos los tamaños.

De la fuente del ejemplo de C ++, también puedo suponer que no es necesario hacer una detección de borde de Canny:

 #include  #include  #include  using namespace cv; int main(int argc, char** argv) { Mat img, gray; if( argc != 2 && !(img=imread(argv[1], 1)).data) return -1; cvtColor(img, gray, CV_BGR2GRAY); // smooth it, otherwise a lot of false circles may be detected GaussianBlur( gray, gray, Size(9, 9), 2, 2 ); vector circles; HoughCircles(gray, circles, CV_HOUGH_GRADIENT, 2, gray->rows/4, 200, 100 ); for( size_t i = 0; i < circles.size(); i++ ) { Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); int radius = cvRound(circles[i][2]); // draw the circle center circle( img, center, 3, Scalar(0,255,0), -1, 8, 0 ); // draw the circle outline circle( img, center, radius, Scalar(0,0,255), 3, 8, 0 ); } namedWindow( "circles", 1 ); imshow( "circles", img ); return 0; } 

¿Estás intentando convertir este código C ++ en Python, supongo?

 for( size_t i = 0; i < circles.size(); i++ ) { Point center(cvRound(circles[i][0]), cvRound(circles[i][1])); int radius = cvRound(circles[i][2]); // draw the circle center circle( img, center, 3, Scalar(0,255,0), -1, 8, 0 ); // draw the circle outline circle( img, center, radius, Scalar(0,0,255), 3, 8, 0 ); } 

Por lo que puedo decir, los objetos CvMat son iterables, como una lista:

 for circle in storage: radius = circle[2] center = (circle[0], circle[1]) cv.Circle(im, center, radius, (0, 0, 255), 3, 8, 0) 

No tengo ninguna imagen de prueba, así que no tome mi palabra de que esto funciona. Su código completo podría ser:

 import cv def main(): im = cv.LoadImage('Proba.jpg') gray = cv.CreateImage(cv.GetSize(im), 8, 1) edges = cv.CreateImage(cv.GetSize(im), 8, 1) cv.CvtColor(im, gray, cv.CV_BGR2GRAY) #cv.Canny(gray, edges, 20, 55, 3) storage = cv.CreateMat(im.width, 1, cv.CV_32FC3) cv.HoughCircles(edges, storage, cv.CV_HOUGH_GRADIENT, 5, 25, 200, 10) for i in xrange(storage.width - 1): radius = storage[i, 2] center = (storage[i, 0], storage[i, 1]) print (radius, center) cv.Circle(im, center, radius, (0, 0, 255), 3, 8, 0) cv.NamedWindow('Circles') cv.ShowImage('Circles', im) cv.WaitKey(0) if __name__ == '__main__': main() 

Eche un vistazo a mi respuesta a esta pregunta para ver un código fuente que funciona (es C, pero utilicé un comstackdor de C ++ porque es más indulgente).

Primero, recorté su imagen (para obtener algo conveniente para trabajar con ella) y apliqué un umbral a su imagen para separar el primer plano del fondo:

introduzca la descripción de la imagen aquí

Luego apliqué directamente el código fuente a la imagen con umbral. Aquí está la salida de texto:

 center x: 330 y: 507 A: 13 B: 4 center x: 78 y: 507 A: 22 B: 4 center x: 270 y: 503 A: 8 B: 8 center x: 222 y: 493 A: 21 B: 17 center x: 140 y: 484 A: 17 B: 18 center x: 394 y: 478 A: 17 B: 15 center x: 311 y: 468 A: 8 B: 8 center x: 107 y: 472 A: 12 B: 12 center x: 7 y: 472 A: 6 B: 19 center x: 337 y: 442 A: 10 B: 9 center x: 98 y: 432 A: 10 B: 10 center x: 357 y: 421 A: 7 B: 7 center x: 488 y: 429 A: 22 B: 23 center x: 411 y: 400 A: 13 B: 12 center x: 42 y: 400 A: 11 B: 12 center x: 365 y: 391 A: 14 B: 13 center x: 141 y: 396 A: 19 B: 19 center x: 9 y: 379 A: 8 B: 18 center x: 192 y: 365 A: 10 B: 9 center x: 347 y: 340 A: 20 B: 20 center x: 8 y: 305 A: 7 B: 13 center x: 95 y: 308 A: 23 B: 24 center x: 318 y: 297 A: 15 B: 15 center x: 159 y: 285 A: 10 B: 10 center x: 412 y: 291 A: 26 B: 27 center x: 504 y: 278 A: 6 B: 16 center x: 233 y: 277 A: 20 B: 20 center x: 459 y: 256 A: 15 B: 15 center x: 7 y: 239 A: 6 B: 9 center x: 377 y: 239 A: 14 B: 14 center x: 197 y: 228 A: 12 B: 12 center x: 302 y: 237 A: 12 B: 22 center x: 98 y: 224 A: 24 B: 23 center x: 265 y: 203 A: 18 B: 18 center x: 359 y: 202 A: 22 B: 22 center x: 149 y: 201 A: 20 B: 21 center x: 219 y: 169 A: 7 B: 9 center x: 458 y: 172 A: 20 B: 20 center x: 497 y: 157 A: 13 B: 21 center x: 151 y: 125 A: 18 B: 17 center x: 39 y: 109 A: 9 B: 10 center x: 81 y: 116 A: 20 B: 19 center x: 249 y: 104 A: 14 B: 13 center x: 429 y: 76 A: 23 B: 24 center x: 493 y: 33 A: 11 B: 10 center x: 334 y: 26 A: 12 B: 14 

Y aquí está la imagen de salida:

introduzca la descripción de la imagen aquí

El problema principal es que los círculos que se han fusionado no se han detectado en absoluto. El código se escribió originalmente solo para detectar puntos suspensivos rellenos, por lo que probablemente pueda resolver este problema al modificar el código.

Una solución similar en python. Originalmente intenté ejecutar una detección de contorno descrita aquí , pero no funcionó bien. Así que primero fue necesario un cierto umbral. El código para el umbral está aquí:

  fimg = misc.imread("boubles.jpg") gimg = color.colorconv.rgb2grey(fimg) vimg = [] for l in gimg: l2 = sign(l - 0.50) / 2 + 0.5 vimg.append(l2) img = array(vimg) imshow(img) 

Con esto me sale una imagen como esta:

imagen de umbral

Y después de la detección de bordes descrita en el enlace anterior, obtuve esto:

encontrar contornos

Si verifica el código, encontrará que es realmente fácil contar los objetos. El único problema es que algunas de las burbujas se cuentan dos veces. Y supongo que la función de umbral también se puede mejorar. Pero sugiero que usar skimage es fácil de usar y tiene buenas muestras en su página web.