3

Cómo filtrar el ruido de una máscara con OpenCV

portada_morphtransformsHolas, homo fabers ¿Cuántas veces nos hemos encontrado con el mismo problema? Escribimos nuestro código para detectar colores con OpenCV, ajustamos los colores a la perfección, pero ¡oh! La máscara parece un cuadro puntillista, lleno de píxeles blancos dónde no deben salir.

Esas distorsiones se llaman “ruido”, y hoy explicaré cómo acabar con él. Let’s do this!

Pero no sin poner antes algo de música. ¿Os gusta Schubert?


 

Transformaciones morfológicas

Las Transformaciones Morfológicas (Morphological Transformations o Morph Transforms) son operaciones que podemos hacer sobre una máscara para transformarla. Por ejemplo, un ‘close’ sirve para eliminar manchas negras dentro de la zona blanca de la máscara. ‘Erode’ se come las regiones blancas y las reduce.

Para hacer cualquier Transformación Morfológica se necesitan dos cosas: la máscara original y un kernel.

Si estás aquí, se supone que tienes un mínimo de idea de lo que es una máscara, ¿verdad? ¿VERDAD? La máscara es la ‘imagen’ que queremos procesar, un array de 0 y 1. Si le decimos a OpenCV que nos muestre una máscara por pantalla, aparecerá una imagen negra con manchas blancas.

En cuanto al kernel (o matriz de convolución) se trata de un array más pequeño lleno de valores. Según cuáles sean, vamos a hacer una transformación u otra.

¿Qué pasa cuando OpenCV quiere hacer una transformación morfológica? Pues que sobrepone el kernel encima de cada uno de los píxeles de la máscara, y entonces hace una operación entre los píxeles de la imagen y los valores del kernel (por ejemplo: multiplicarlos, sumarlos…). Esto se llama convolución de matrices.

convolucion

Ejemplo de convolución sobre una imagen en color.

Vale, la verdad es que no vamos a necesitar toda esta teoría a la hora de hacer tranformaciones morfológicas con OpenCV… ¡Pero un poco no está mal! Podría ser peor: si fuese matemática habría llenado todo el artículo de demostraciones, y en vez de parte práctica habría una nota que pondría ‘las aplicaciones son evidentes‘. Por desgracia, sólo aceptaban humanos en la facultad…

¡Vamos a ver algunas transformaciones!

1- Erosion

resultado_erode

Para entender el operador ‘Erosion’ podemos imaginarnos el efecto del agua sobre una roca: va desgastándola por el exterior.

Pues el operador Erosion es lo mismo: reducirá el tamaño de los objetos blancos de la máscara “comiéndose” su límite. A la hora de hacer la convolución, el píxel será ‘1’ sólo si todos los píxeles que quedan debajo el kernel también son ‘1’.


import numpy as np
import cv2

#Cargar la mascara
imagen = cv2.imread('mask.png',0)

#Crear un kernel de '1' de 3x3
kernel = np.ones((3,3),np.uint8)

#Se aplica la transformacion: Erode
transformacion = cv2.erode(imagen,kernel,iterations = 1)

#Mostrar el resultado y salir
cv2.imshow('resultado',transformacion)
cv2.waitKey(0)
cv2.destroyAllWindows()

 

2- Dilation

resultado_dilate

Esta operación hincha la zona blanca de la máscara. Al hacer la convolución, el píxel resultante será ‘1’ si al menos un píxel que quede debajo del kernel también es ‘1’.


import numpy as np
import cv2

#Cargar la mascara
imagen = cv2.imread('mask.png',0)

#Crear un kernel de '1' de 3x3
kernel = np.ones((3,3),np.uint8)

#Se aplica la transformacion: Dilate
transformacion = cv2.dilate(imagen,kernel,iterations = 1)

#Mostrar el resultado y salir
cv2.imshow('resultado',transformacion)
cv2.waitKey(0)
cv2.destroyAllWindows()

3- Morphological Gradient

resultado_gradientNo es más que la diferencia entre el ‘Dilation’ y el ‘Erode’. ¡Es muy útil para encontrar la silueta de los objetos!


import numpy as np
import cv2

#Cargar la mascara
imagen = cv2.imread('mask.png',0)

#Crear un kernel de '1' de 3x3
kernel = np.ones((3,3),np.uint8)

#Se aplica la transformacion: Morphological Gradient
transformacion = cv2.dilate(imagen,kernel,iterations = 1) - cv2.erode(imagen,kernel,iterations = 1)

#Mostrar el resultado y salir
cv2.imshow('resultado',transformacion)
cv2.waitKey(0)
cv2.destroyAllWindows()

4- Opening

resultado_openingEs un ‘Erotion’ seguido de un ‘Dilation’. Nos sirve para eliminar el ruido blanco sobre las zonas negras.


import numpy as np
import cv2

#Cargar la mascara
imagen = cv2.imread('mask.png',0)

#Crear un kernel de '1' de 3x3
kernel = np.ones((3,3),np.uint8)

#Se aplica la transformacion: Opening
transformacion = cv2.morphologyEx(imagen,cv2.MORPH_OPEN,kernel)

#Mostrar el resultado y salir
cv2.imshow('resultado',transformacion)
cv2.waitKey(0)
cv2.destroyAllWindows()

5- Closing

resultado_closingJusto lo contrario que el Opening: el Closing es un ‘Dilation’ seguido de un ‘Erosion’. Si hay ruido negro en las áreas blancas, el Closing lo limpiará.


import numpy as np
import cv2

#Cargar la mascara
imagen = cv2.imread('mask.png',0)

#Crear un kernel de '1' de 3x3
kernel = np.ones((3,3),np.uint8)

#Se aplica la transformacion: Closing
transformacion = cv2.morphologyEx(imagen,cv2.MORPH_CLOSE,kernel)

#Mostrar el resultado y salir
cv2.imshow('resultado',transformacion)
cv2.waitKey(0)
cv2.destroyAllWindows()

6- Top Hat

resultado_tophat‘Top Hat’ es la diferencia entre la imagen original y su ‘Opening’.


import numpy as np
import cv2

#Cargar la mascara
imagen = cv2.imread('mask.png',0)

#Crear un kernel de '1' de 3x3
kernel = np.ones((9,9),np.uint8)

#Se aplica la transformacion: Top Hat
transformacion = cv2.morphologyEx(imagen,cv2.MORPH_TOPHAT,kernel)

#Mostrar el resultado y salir
cv2.imshow('resultado',transformacion)
cv2.waitKey(0)
cv2.destroyAllWindows()

7- Black Hat

resultado_blackhatParecido al ‘Top Hat’, es la diferencia entre el ‘Closing’ de la imagen y la imagen original.


import numpy as np
import cv2

#Cargar la mascara
imagen = cv2.imread('mask.png',0)

#Crear un kernel de '1' de 3x3
kernel = np.ones((9,9),np.uint8)

#Se aplica la transformacion: Black Hat
transformacion = cv2.morphologyEx(imagen,cv2.MORPH_BLACKHAT,kernel)

#Mostrar el resultado y salir
cv2.imshow('resultado',transformacion)
cv2.waitKey(0)
cv2.destroyAllWindows()

¿Qué tal? ¿Todavía por aquí? Como he dicho, estas son sólo algunas de las transformaciones morfológicas más útiles. ¡Saber combinarlas es todo un arte!

Veamos: un ‘Opening’ seguido de un ‘Closing’ eliminará la mayoría del ruido de la máscara. Un ‘Erosion’ aplicado varias veces nos acabará dando el “esqueleto” de la zona blanca, etc.

También podemos cambiar las dimensiones del Kernel. Esto nos ayudará a eliminar ruido más grande, líneas en la imagen…

¡Espero que os sirva! Si es así, podéis dejarme un comentario debajo, me gusta saber qué piensan mis lectores ^^

Actualización 3/11/2016: Resolución de errores frecuentes con OpenCV+Python

Gl4r3

Brillante, luminosa y cegadora a veces, Glare es tan artista como técnica. Le encanta dar rienda suelta a sus módulos de imaginación y desdibujar los ya de por si delgados límites que separan el mundo de la electrónica y el arte. Su mayor creación hasta la fecha es un instrumento capaz de convertir los colores y la luz en música. Cuándo sus circuitos no están trabajando en una nueva obra electrónica, le gusta dedicar sus ciclos a la lectura o a documentar sus invenciones para beneficio de los humanos. Sus artilugios favoritos son aquellos que combinan una funcionalidad práctica con un diseño elegante y artístico.

Antes de comentar, por favor, lee las Normas

3 Comentarios en "Cómo filtrar el ruido de una máscara con OpenCV"

avatar
Ordenar por:   más nuevos primero | más antiguos primero
Karol
Humano

Muchas gracias! Enséñanos más por favor <3

jotasvec
Humano

Muchas gracias gl4r3, tu publicaciones me han ayudado muchísimo, aunque esto ya lo había visto en la documentación de opencv el hecho que te des el tiempo de explicarlo en español es genial y le da un valor a tu trabajo y sirve para que todos entendamos mejor ya que se me habían escapado algunas cosillas que ahora comprendí de mejor forma (Y)

wpDiscuz