agosto 3, 2019 6:00 pm

Jesús

?? Read in English

¿No odias cuando aún después de haber preparado minuciosamente la toma perfecta, tus fotos salen borrosas? Lo que debía ser un compendio fotográfico de los mejores momentos de tu fiesta de cumpleaños terminó siendo la perspectiva de una persona sin sus gafas. 

Te entiendo. Todos hemos pasado por una situación similar. 

Las fotos borrosas son lo peor, ¿cierto? Pues, realmente depende de a quień le preguntes. Por ejemplo, para los aficionados a la visión computarizada como nosotros, difuminar y suavizar las fotos puede ser un paso necesario para analizar, entender, y procesar su contenido.

Raro, ¿no? Sí, lo admito, pero como veremos a lo largo de este artículo, existen muchas técnicas que deliberadamente ocasionan este efecto en las imágenes, las cuales son tan importantes como las que hemos estudiado hasta los momentos.

Sin más dilación, pues, empecemos.

Suavizado y Difuminado

Ya sabemos cómo luce una imagen borrosa, pero ¿qué es lo que sucede a nivel de los píxeles? 

Cuando una imagen se difumina, en la práctica lo que ocurre es que el valor o intensidad de cada píxel se mezcló con la de los píxeles circundantes, restando presencia o claridad a los bordes o límites entre objetos, facciones, detalles y demás elementos presentes en la foto.

Como establecimos en la introducción, éste efecto resulta útil en diversas tareas de procesamiento de imágenes, como la detección de bordes (la cual estudiaremos en un artículo futuro).

OpenCV nos provee varios mecanismos para difuminar una imagen. Sin embargo, los que estudiaremos el día de hoy, son:

  • Promedio: Definiremos una ventana, región o kernel de KxK píxeles, donde K tiene que ser un número impar para garantizar que hay exactamente un píxel en el centro de dicha región. El valor del píxel central será el promedio del valor de los demás píxeles en la ventana.
  • Gaussiano: El difuminado Gaussiano funciona de la misma manera que el promediado, sólo que en vez de calcular la media de los demás píxeles, computa un promedio con pesos, donde los píxeles más cercanos al centro tienen una mayor incidencia que aquellos en la periferia. El resultado de este método es una imagen menos borrosa, pero cuyo desenfoque es más natural que utilizando un promedio simple.
  • Mediana: Similar a los anteriores, sólo que el valor del píxel central será la mediana de los píxeles en la vecindad. Por definición, el píxel central tendrá un valor que necesariamente existe en alguno de los otros píxeles que lo rodean, mientras que éste no es el caso para los métodos que utilizan la media. Utilizar la mediana en el difuminado es especialmente útil para eliminar el conocido ruido “sal y pimienta” en las imágenes, el cual se produce cuando hay píxeles negros o blancos esparcidos en la imagen, como si, en efecto, ésta se encontrara cubierta de granos de sal y pimienta.
  • Bilateral: Éste mecanismo es similar al Gaussiano, sólo que en vez de usar una, se apoya en dos distribuciones normales: La primera considera los píxeles que aparecen espacialmente cerca al centro (es decir, en el espacio (X, Y) de coordenadas de la imagen), y la segunda aquellos cuya intensidad es similar, asegurando que sólo los píxeles cercanos en ubicación y en color son incluidos en el cálculo. El difuminado bilateral tiene la gran ventaja de preservar los bordes de la imagen, a la vez que produce el efecto borroso deseado, algo que no ocurre con los otros tres métodos.

Con estas definiciones en mente, prosigamos a analizar el script del día de hoy:

La primera sección del programa importa las librerías, define el ArgumentParser y carga la imagen en memoria. Este procedimiento debería ser familiar para ti a estas alturas.

En la línea 12 llevamos a cabo un difuminado promediado, usando la función cv2.blur() de OpenCV. El primer parámetro que recibe es la imagen, y el segundo es una tupla de KxK, correspondiente a las dimensiones de la ventana o kernel que iremos deslizando a lo largo de la foto para producir el efecto borroso que buscamos.

Como notarás, estamos utilizando kernels de tamaño 3×3, 5×5 y 7×7. Mientras más grande es el kernel, más borroso será el resultado.

En las líneas 18-19 mostramos las tres imágenes resultantes, una junto a la otra, mientras que esperamos que el usuario presione cualquier tecla para continuar con el programa.

En la línea 21 ejecutamos un difuminado Gaussiano, mediante la función cv2.GaussianBlur(). Su primer parámetro es la imagen, el segundo la tupla KxK con las dimensiones del kernel, y el tercero es la desviación estándar en la dirección del eje X. Al colocar éste parámetro en cero, le estamos indicando a OpenCV que debe calcularlo automáticamente con base al tamaño de nuestro kernel.

Una vez más, usamos ventanas de tamaño 3×3, 5×5 y 7×7. El resultado se muestra en la línea 26.

Seguidamente, calculamos un difuminado con mediana, con la función cv2.medianBlur() (línea 29). El primer parámetro es la imagen, y el segundo, el tamaño del kernel (por alguna razón, para esta función sólo necesitamos proveer un número, en vez de una tupla).  

Como en los dos casos anteriores, haremos uso de kernels de tamaño 3×3, 5×5 y 7×7. El resultado es desplegado en pantalla en la línea 34.

Finalmente, llegamos al difuminado bilateral, en la línea 37, donde a la función cv2.bilateralFilter() debemos proporcionar la imagen, el tamaño del kernel (un número, no una tupla), la desviación estándar del color y la desviación estándar de la distancia. Mientras más grandes sean las desviaciones, más píxeles serán considerados en el cálculo del difuminado.

En esta ocasión, realizaremos tres experimentos: El primero con un kernel de 5×5, desviación estándar de color igual a 21 y desviación estándar de la distancia igual a 21; el segundo con un kernel de 7×7, desviación estándar de color igual a 31 y desviación estándar de la distancia igual a 31; el tercero con un kernel de 9×9, desviación estándar de color igual a 41 y desviación estándar de la distancia igual a 41.

El resultado se muestra en la línea 42.

Podemos ejecutar éste programa con el siguiente comando:

Lo primero que observamos es la foto original. En ella vemos un paisaje montañoso con alto nivel de detalle:

Seguidamente, vemos el resultado de la difuminación promediada. A medida que aumentamos el tamaño del kernel, el desenfoque se acentúa.

Luego, la difuminación Gaussiana ofrece un efecto similar al anterior, pero conservando más detalles.

La difuminación con mediana es bastante interesante. En vez de un desenfoque generalizado, vemos cómo las formas de los objetos en la foto pierden detalle, y se asemejan cada vez más figuras geométricas.

En último lugar tenemos el resultado del difuminado bilateral. Aunque las fotografías se ven fuera de foco, es indudable que éste método es el que más detalles preserva de la imagen original, especialmente en lo que a los bordes de los objetos respecta. No obstante, es el mecanismo más lento de todos.

Esto es todo. Hoy aprendimos diversas maneras de, deliberadamente, desenfocar o suavizar una imagen. Dependiendo de las necesidades de nuestro proyecto, nos decantaremos por algunas de las opciones estudiadas. Lo importante es saber cómo y cuando utilizarlas.

Nos vemos en otra ocasión.

Sobre el Autor

Jesús Martínez es el creador de DataSmarts, un lugar para los apasionados por computer vision y machine learning. Cuando no se encuentra bloggeando, jugando con algún algoritmo o trabajando en un proyecto (muy) cool, disfruta escuchar a The Beatles, leer o viajar por carretera.

Paso 2/2: Celebra tu NUEVO EMPLEO en Machine Learning ?

A %d blogueros les gusta esto: