enero 5, 2019 6:00 pm

Jesús

?? Read in English

El advenimiento de las redes neuronales profundas ha facilitado enormemente la introducción de la inteligencia artificial a un sinnúmero de dominios que comprenden desde el análisis lingüístico de un texto, hasta el reconocimiento de objetos en imágenes, videos, e incluso, transmisiones en vivo.

No obstante, es menester recordar que no hace mucho, la cantidad de conocimiento específico necesario para desarrollar soluciones decentes en estos dominios era intimidante. Apenas en la década anterior, campos como computer vision eran territorio casi exclusivo de profesionales con PhDs, mientras que, hoy en día, cualquier individuo con la disciplina, disposición y tiempo suficiente para aprender sobre machine y deep learning puede realizar grandes contribuciones sin la necesidad de un título universitario.

Tareas que en la actualidad parecen sencillas, como detectar objetos en una fotografía, demandaban la dedicación de un artesano, experimentando con distintos features basados en la intensidad de los pixeles y su variación en distintas regiones de una imagen.

Claramente, esta forma de proceder no era escalable y, de hecho, era computacionalmente bastante costosa.

Afortunadamente, hace ya 18 años, Paul Viola y Michael Jones publicaron un algoritmo conocido como Haar Cascades en su paper “Rapid Object Detection Using a Boosted Cascade of Simple Features”. Aunque los métodos modernos basados en CNNs son mucho más populares, ésta fue una de las primeras aproximaciones al problema de encontrar objetos en una imagen basada en machine learning. En este post hablaremos sobre este potente algoritmo.

>>> Descarga el código de este post aquí <<<

Haar Features

En nuestra discusión sobre redes neuronales convolucionales descubrimos que el inmenso poder de éstas reside en la convolución de una imagen con un filtro, también conocido como kernel, capaz de aislar y reconocer determinadas cualidades.

Los Haar features son, en esencia, kernels compuestos de un único valor, el cual se obtiene de la resta entre la suma de los pixeles en el rectángulo blanco y la suma de los pixeles en el rectángulo negro.

En la imagen de abajo observamos dos Haar features útiles para detectar ojos y nariz en un rostro, respectivamente. ¿Cómo? Pues, en una imagen de un rostro es común que las pupilas de los ojos sean más oscuras que las mejillas, razón por la cual el rectángulo negro se encuentra arriba del blanco. Así mismo, el tabique nasal suele ser más claro que los ojos, puesto que la tez de una persona casi siempre tiene una tonalidad más clara que la de sus ojos, por lo que este feature está compuesto de un rectángulo blanco rodeado de dos rectángulos negros.

Relevancia

Ahora bien, estos dos features son muy útiles para detectar características específicas de un rostro, pero bastante ineficientes en otras regiones de la imagen.

¿Cómo escogemos los mejores features entre un universo de más de 160.000 (asumiendo que usamos una ventana deslizante de 24×24)? La mejor manera es aplicar cada feature a todas las imágenes en nuestro conjunto de entrenamiento, con la finalidad de encontrar el mejor umbral que nos permita clasificar correctamente un rostro (o cualquier otro objeto, la verdad).

Específicamente, usamos AdaBoost, el cual es un algoritmo de machine learning basado en boosting, una técnica consistente en entrenar un clasificador robusto a partir de múltiples clasificadores débiles (donde débil significa que son ligeramente mejores que adivinar aleatoriamente).

En el paper original, aplicando esta técnica, pasaron de más de 160.000 features a solo 6.000. Impresionante, ¿no?

Un poco lento, ¿no?

De acuerdo. Aplicar 6.000 filtros a cada ventana o región de una imagen para ver si contiene un rostro o no se demora bastante.

Pero, ¡ah! hay un truco que podemos usar. Mira la imagen de abajo:

¿Qué ves? Un rostro, por supuesto. Pero, ¿cuál proporción de la imagen ocupa? Probablemente menos de la mitad, ¿verdad?

Teniendo en mente el hecho de que en la inmensa mayoría de los casos una gran cantidad de las regiones de una imagen no contienen un rostro, podemos armar una cadena o cascada de clasificadores para centrarnos únicamente en las regiones/ventanas que sí encierran una cara.

La idea es agrupar los features en diferentes etapas, las cuáles serán aplicadas una a una. Si una región falla en la primera etapa, la descartamos y no le prestamos atención nunca más. Si pasa, vamos a la segunda etapa y así sucesivamente. Cuando una región pasa todas las etapas, entonces tenemos un rostro.

Típicamente las primeras etapas contienen menos features que las últimas. (¿No te suena esto familiar? ¡Exacto! Es prácticamente una CNN rudimentaria).

Esto es confuso…

Lo sé, lo sé. Te entiendo. Nada en computer vision es fácil, créeme. Sin embargo, un recurso que me ayudó muchísimo a entender este algoritmo es el siguiente video (¡es fantástico!).

Es interesante como las ventanas que no contienen rostros son descartadas rápidamente pasadas unas pocas etapas, mientras que a medida que nos vamos acercando al rostro, vamos llegando más y más lejos, hasta que finalmente, detectamos la cara de la modelo.

Manos a la obra

Para solidificar nuestro entendimiento de Haar Cascades, procedamos a implementar un detector de rostros utilizando OpenCV.

>>> Descarga el código de este post aquí <<<

Espero que te haya sido de utilidad este post.

¡Nos vemos!

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.