octubre 6, 2021 10:00 am

Jesús

Una de las primeras y más comunes aplicaciones del procesamiento de imágenes es la detección de bordes en imágenes.

En la mayoría de los casos, usaremos el ya clásico algoritmo de Canny para llevar a cabo esta tarea.

No obstante, como sucede con buena parte de las técnicas de computer vision tradicionales, el algoritmo de Canny requiere una cantidad sustancial de intervención manual, principalmente en lo que a la escogencia de parámetros se refiere.

Así mismo, no tenemos garantías que una configuración exitosa para una foto vaya a producir resultados favorables en otras circunstancias.

Es más, lo más probable es que las variables condiciones lumínicas entre foto y foto hagan de Canny una solución difícil de escalar.

¿Existe una alternativa mejor o, al menos, más estable?

¡Sí! Y a que no adivinas en qué está basada esta alternativa…

Ajá… ¡Deep learning!

Dedicaremos el remanente de este post a aprender cómo funciona (brevemente) y a utilizar un algoritmo llamado Holistically-Nested Edge Detection (HED) o, en español, Detección Holísticamente Anidada de Bordes, directamente en OpenCV.

Al final de este artículo habrás aprendido:

  • Cuáles son las principales limitaciones del algoritmo de Canny para la detección de bordes.
  • Qué es y cómo funciona, a grosso modo, el algoritmo de detección de bordes basado en deep learning, HED.
  • Cómo utilizar HED en OpenCV.

¿Qué Hay de Malo con el Detector Canny?

Ejemplo de bordes detectados por Canny

Ejemplo de bordes detectados por Canny

Como mencionamos en la introducción, lo más probable es que cuando estés trabajando con detección de bordes, al menos con OpenCV, recurras al [detector Canny].

La pregunta que cabe, entonces, es la siguiente: ¿Por qué habríamos de recurrir a HED o, si al caso vamos, a cualquier otro detector alterno? ¿Qué hay de malo con el detector Canny?

Pues, he aquí algunos de los problemas más frecuentes con el querido Canny:

  • Configurar las cotas inferior y superior de la histéresis es un proceso iterativo que necesita constante validación manual.
  • Los valores de la histéresis que funcionen bien para una foto, más que seguramente no lo harán para otras fotos. ¿Por qué?  Iluminación.
  • El algoritmo de Canny no es independiente, ya que tiene como precondición ciertos pasos como conversión a escala de grises, difuminado, suavizado, entre otros, lo cual incrementa aún más el número de combinaciones a probar hasta dar con un buen resultado.

Como vemos, Canny, muy a pesar de sus bondades, presenta varias complicaciones y mañas al momento de trabajar con él.

Justamente son estas debilidades las que HED busca mitigar.

¿Qué es Holistically-Nested Edge Detection (HED)?

Holistically-Nested Edge Detection

Holistically-Nested Edge Detection


El algoritmo Holistically-Nested Edge Detection (HED) fue postulado por Saining Xie y Zhuowen Tu en su publicación de 2015, titulada, pues… Holistically-Nested Edge Detection ?.

En dicho paper, los autores describen una red neuronal profunda con la capacidad de aprender automáticamente ricos mapas jerárquicos de bordes que sirven para determinar los bordes o límites entre los objetos de una imagen.

A pesar de que no ahondaremos en los detalles de HED (eso sí, te recomiendo que leas el paper cuando tengas un chance), sí que aprenderemos a usarlo en OpenCV en las próximas secciones. ?

Creación del Entorno de Programación con Anaconda

Como siempre, empecemos viendo la estructura del proyecto que nos ocupa:

Estructura del proyecto

Estructura del proyecto

  • El archivo datasmarts/hed.py contiene la implementación del detector de bordes usando HED. Como veremos en breve, también corremos el detector Canny para comparar sus resultados con los arrojados por HED.
  • En la carpeta resources tenemos los archivos necesarios para cargar en OpenCV la red HED implementada y entrenada en Caffe.
  • Finalmente, en el directorio assets contamos con varias imágenes de ejemplo que usaremos para probar que nuestro programa funcione debidamente.

Para crear el ambiente de Anaconda, corre este comando:

conda env create -f opencv-hed

Esta instrucción habrá creado un ambiente llamado opencv-hed, configurado de la siguiente manera:

Puedes activar el ambiente así:

conda activate opencv-hed

Cool, prosigamos.

Detección de Bordes con Holistically-Nested Edge Detection (HED) en OpenCV

Abre el archivo datasmarts/hed.py e inserta estas líneas para importar las dependencias del programa:

Para poder usar el modelo HED, necesitamos implementar una capa personalizada para recortar los volúmenes de entrada que recibe la red. 

La clase CropLayer implementa dicha capa. Como vemos abajo, el constructor simplemente inicializa las dimensiones del área del recorte final:

El siguiente método, getMemoryShapes(), calcula el tamaño de los volúmenes de entrada de la red. Te recomiendo que leas los comentarios, pues explican en mayor detalle las particularidades del método:

El último método de CropLayer es forward(), que simplemente lleva a cabo el recorte con base a las dimensiones calculadas por getMemoryShapes():

Nuestra meta con este programa no es solo aprender cómo usar HED en OpenCV, sino comparar sus resultados con los de Canny. Por este motivo, implementamos la función detect_canny(), la cual toma una imagen de entrada y devuelve una imagen binaria con los bordes encontrados por el detector Canny:

De manera análoga, definimos la función detect_hed(), que dada una imagen y la red correspondiente al modelo HED ya cargado en OpenCV, devuelve la imagen binaria con los bordes encontrados por dicho modelo:

Ahora nos toca definir los parámetros de entrada del script:

  • -p/--prototxt: Ruta al archivo .prototxt donde se define la arquitectura de la red en Caffe.
  • -c/--caffemodel: Ruta al archivo .caffemodel correspondiente a la red entrenada en Caffe.
  • -i/--image: Ruta a la imagen de entrada.

Cargamos la red utilizando la función cv2.readNetFromCaffe(), a la que le debemos pasar la ruta a los archivos .prototxt y .caffemodel, respectivamente:

También debemos registrar la capa personalizada que implementamos arriba:

Leemos y redimensionamos la imagen de entrada para acelerar un poco su procesamiento:

Hallamos los bordes con Canny:

Y ahora con HED:

Concatenamos los resultados con la imagen original para armar un mosaico comparativo:

Finalmente, mostramos los resultados y destruimos las ventanas creadas en el proceso:

Podemos correr el programa así:

python ./datasmarts/hed.py -p ./resources/deploy.prototxt -c ./resources/hed_pretrained_bsds.caffemodel -i ./assets/truck.jpg

Al cabo de unos instantes veremos este resultado en pantalla:

De izquierda a derecha: Imagen original, bordes con Canny, bordes con HED

De izquierda a derecha: Imagen original, bordes con Canny, bordes con HED

A mano izquierda tenemos la imagen original, la cual a primera vista se nota que es desafiante, debido a la cantidad de formas que resultan de las ramas de los árboles a los lados del camino, así como las pequeñas piedras y rocas en el sendero, sin mencionar los bordes y detalles propios de mi camioneta.

En el centro tenemos los bordes resultantes del detector Canny. Lo primero que notamos es que no fue capaz de mantener la continuidad del contorno de la camioneta, ni de varios de los árboles a los lados del sendero.

Adicionalmente, Canny arroja mucho ruido proveniente de las texturas de las hojas y demás detalles de baja resolución que no aportan demasiada información valiosa.

A mano derecha tenemos el resultado de aplicar HED. Como vemos, preserva todos los bordes de los objetos más importantes en la foto, como la camioneta, los árboles y el camino. Además, no nos vemos sobrecargados de bordes y contornos menos importantes como en el caso de Canny.

¿Qué tal? Chévere, ¿no?

Resumen

Hoy aprendimos sobre un novedoso detector basado en deep learning, conocido como HED, un acrónimo para Holistically-Nested Edge Detection.

Como sucede con muchas herramientas de computer vision impulsadas por deep learning, contamos con la capacidad de cargar una versión entrenada e implementada en Caffe directamente en OpenCV, lo cual nos ahorra muchísimo tiempo y esfuerzo.

Aunque Canny es un método muy utilizado y, honestamente, el detector que usaremos en un número importante de ocasiones, tiene sus falencias, principalmente debido a su poca escalabilidad.

¿Por qué? Pues porque tenemos que configurar una serie de parámetros de forma iterativa, hasta dar con un resultado lo suficientemente satisfactorio para las imágenes que queremos procesar.

Lamentablemente, no hay garantía de que una configuración exitosa en una aplicación produzca resultados similarmente buenos en otra.

HED, precisamente, busca contrarrestar estos problemas.

Como vimos cuando probamos nuestro script, HED suele producir contornos y bordes completos para los objetos más prominentes en una imagen, mientras que Canny tiende a fallar en esta labor, además de entregarnos montones de bordes menores correspondientes a detalles menos importantes.

¿Cuál es mejor? Pues, como siempre, depende de las necesidades de tu proyecto. La mejor estrategia es saber manejar ambas herramientas para poderles sacar el máximo provecho posible.

¿Por qué no te descargas el código que acompaña a este artículo, y pruebas con las otras dos imágenes incluidas en el mismo? 

¡Hasta pronto!

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.