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:
¿Qué Hay de Malo con el Detector 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:
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)?
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:
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:
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:
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!