Rellenar agujeros dentro de un objeto binario

Tengo un problema con llenar agujeros blancos dentro de monedas negras para poder tener solo una imagen binaria de 0-255 con monedas negras llenas. He usado el filtro Median para lograrlo, pero en ese caso el puente de conexión entre las monedas crece y resulta imposible. para reconocerlos después de varias veces de erosión … Necesito un método simple como floodFill en opencv

Aquí está mi imagen con agujeros:

enter image description here

EDITAR: la función de relleno de inundación debe llenar los agujeros en los componentes grandes sin solicitar coordenadas X e Y como una semilla …

EDITAR: Intenté usar la función cvDrawContours pero no llené los contornos dentro de los más grandes.

Aquí está mi código:

CvMemStorage mem = cvCreateMemStorage(0); CvSeq contours = new CvSeq(); CvSeq ptr = new CvSeq(); int sizeofCvContour = Loader.sizeof(CvContour.class); cvThreshold(gray, gray, 150, 255, CV_THRESH_BINARY_INV); int numOfContours = cvFindContours(gray, mem, contours, sizeofCvContour, CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE); System.out.println("The num of contours: "+numOfContours); //prints 87, ok Random rand = new Random(); for (ptr = contours; ptr != null; ptr = ptr.h_next()) { Color randomColor = new Color(rand.nextFloat(), rand.nextFloat(), rand.nextFloat()); CvScalar color = CV_RGB( randomColor.getRed(), randomColor.getGreen(), randomColor.getBlue()); cvDrawContours(gray, ptr, color, color, -1, CV_FILLED, 8); } CanvasFrame canvas6 = new CanvasFrame("drawContours"); canvas6.showImage(gray); 

Resultado: (puedes ver agujeros negros dentro de cada moneda)

enter image description here

Hay dos métodos para hacer esto:

1) Relleno de contorno:

Primero invierta la imagen, encuentre los contornos en la imagen, llénela de negro e invierta la parte posterior.

 des = cv2.bitwise_not(gray) contour,hier = cv2.findContours(des,cv2.RETR_CCOMP,cv2.CHAIN_APPROX_SIMPLE) for cnt in contour: cv2.drawContours(des,[cnt],0,255,-1) gray = cv2.bitwise_not(des) 

Imagen resultante:

enter image description here

2) Apertura de la imagen:

 kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(3,3)) res = cv2.morphologyEx(gray,cv2.MORPH_OPEN,kernel) 

La imagen resultante de la siguiente manera:

enter image description here

Como puede ver, no hay mucha diferencia en ambos casos.

NB : gris – imagen en escala de grises, todos los códigos están en OpenCV-Python

Un simple dilatar y erosionar cerraría las lagunas bastante bien, me imagino. Creo que tal vez esto es lo que estás buscando.

Una solución más robusta sería hacer una detección de bordes en toda la imagen, y luego una transformación en los círculos. Un rápido Google muestra que hay ejemplos de código disponibles en varios idiomas para la detección de círculos invariantes utilizando una transformada Hough, por lo que con suerte eso le dará algo para seguir.

El beneficio de usar la transformada de Hough es que el algoritmo en realidad le dará una estimación del tamaño y la ubicación de cada círculo, por lo que puede reconstruir una imagen ideal basada en ese modelo. También debería ser muy robusto para superponer, especialmente teniendo en cuenta la calidad de la imagen de entrada aquí (es decir, menos preocupación por los falsos positivos, por lo que puede reducir el umbral de resultados).

Es posible que esté buscando la transformación Fillhole , una aplicación de reconstrucción de imágenes morfológicas.

Esta transformación llenará los agujeros en sus monedas, aunque a costa de llenar también todos los agujeros entre grupos de monedas adyacentes. El espacio Hough o las soluciones basadas en la apertura sugeridas por los otros pósters probablemente le darán mejores resultados de reconocimiento de alto nivel.

Intenta usar la función cvFindContours () . Puede usarlo para encontrar componentes conectados. Con los parámetros correctos, esta función devuelve una lista con los contornos de cada componente conectado.

Encuentra los contornos que representan un hoyo. Luego use cvDrawContours () para rellenar el contorno seleccionado por el color de primer plano, cerrando así los agujeros.

Creo que si los objetos son tocados o llenos, habrá algunos problemas al usar los contornos y la apertura de la morfología matemática. En cambio, se encuentra y prueba la siguiente solución simple. Está funcionando muy bien, y no solo para estas imágenes, sino también para cualquier otra imagen.

aquí están los pasos (optimizados) como se ve en http://blogs.mathworks.com/steve/2008/08/05/filling-small-holes/

déjame: la imagen de entrada

 1. filled_I = floodfill(I). // fill every hole in the image. 2. inverted_I = invert(I)`. 3. holes_I = filled_I AND inverted_I. // finds all holes 4. cc_list = connectedcomponent(holes_I) // list of all connected component in holes_I. 5. holes_I = remove(cc_list,holes_I, smallholes_threshold_size) // remove all holes from holes_I having size > smallholes_threshold_size. 6. out_I = I OR holes_I. // fill only the small holes. 

En resumen, el algoritmo es solo para encontrar todos los agujeros, eliminar los grandes y luego escribir los pequeños solo en la imagen original.

He estado buscando en internet para encontrar una función de relleno adecuada (como la de Matlab) pero trabajando en C con OpenCV. Después de algunos reaserches, finalmente se me ocurrió una solución:

 IplImage* imfill(IplImage* src) { CvScalar white = CV_RGB( 255, 255, 255 ); IplImage* dst = cvCreateImage( cvGetSize(src), 8, 3); CvMemStorage* storage = cvCreateMemStorage(0); CvSeq* contour = 0; cvFindContours(src, storage, &contour, sizeof(CvContour), CV_RETR_CCOMP, CV_CHAIN_APPROX_SIMPLE ); cvZero( dst ); for( ; contour != 0; contour = contour->h_next ) { cvDrawContours( dst, contour, white, white, 0, CV_FILLED); } IplImage* bin_imgFilled = cvCreateImage(cvGetSize(src), 8, 1); cvInRangeS(dst, white, white, bin_imgFilled); return bin_imgFilled; } 

Para esto: Imagen Binaria Original

El resultado es: Imagen Binaria Final

El truco está en la configuración de parámetros de la función cvDrawContours: cvDrawContours (dst, contour, white, white, 0, CV_FILLED);

  • dst = imagen de destino
  • contorno = puntero al primer contorno
  • blanco = color utilizado para rellenar el contorno
  • 0 = nivel máximo para contornos dibujados. Si es 0, solo se dibuja el contorno
  • CV_FILLED = Grosor de las líneas con las que se dibujan los contornos. Si es negativo (Por ejemplo, = CV_FILLED), se dibujan los interiores del contorno.

Más información en la documentación de openCV.

Probablemente haya una manera de obtener “dst” directamente como una imagen binaria, pero no pude encontrar cómo usar la función cvDrawContours con valores binarios.

    Intereting Posts