Tutorial

Detección Facial en Python y OpenCV

En la actualidad la tecnologia representa un constante crecimiento en las diversas áreas de nuestras vidas, prácticamente todo aquello que solíamos hacer mediante un grupo de personas o herramienta física, se esta viendo reemplazada por un software o pieza de hardware cada vez mas potente, que "facilita" de cierta forma las tareas cotidianas.

El software como bien saben es un ambiente bastante "volátil", hoy en día es mas sencillo acceder a distintas herramientas que permiten "jugar y aprender" sobre temas que quizás en otro momento podían parecer inaccesibles, y se debe a las diversas plataformas que difunden el "software libre"; estas permiten mejorar y crear nuevas herramientas para todo tipo de situaciones.

Hoy hablaremos de OpenCV, la cual, es una biblioteca libre de visión artificial que fue desarrollada en un principio por Intel y que gracias a los distintos contribuidores de código a nivel mundial, ha permitido el uso de muchas aplicaciones actuales. Desde sistemas de seguridad, hasta reconocimiento y detección de objetos. Lo mas importante es que ha crecido a tal grado, que ahora contamos con esta fantástica librería en casi todas las plataformas de desarrollo posibles, ademas contiene mas de 500 funciones nuevas que abarcan procesos de visión artificial, calibración de cámaras, visión estérea, visión robótica, entre otros.

Marco Teórico.

Primero hay que comprender que es "reconocimiento" y "detección", ambos conceptos son muy populares hoy en día cuando se habla de análisis de imágenes, pero aveces dista de lo que en realidad significa.

La "visión artificial" o "visión por computadora" es una disciplina dentro de la ciencia y la tecnologia que se dedica a crear e implementar métodos para adquirir, procesar, analizar y comprender las imágenes del mundo real (entorno análogo) con el objetivo de convertirlo en su semejante digital mediante información numérica o simbólica que las computadoras puedan comprender.

Así como el cuerpo humano ejecuta distintos procesos a nivel físicos, biológicos y químicos para comprender el mundo que nos rodea, la visión por computadora también trata de simular el mismo efecto para que estas puedan percibir y comprender imágenes, objetos, colores y profundidad.

En este tutorial vamos a abarcar de manera introductoria la "detección" facial, por lo tanto no debe confundirse con "reconocimiento". Si bien, es posible hacer un reconocimiento mediante OpenCV, el primer paso es crear un software o algoritmo que primero identifique lo que deseamos reconocer.

El reconocimiento de objetos, se diferencia porque ademas de haber pasado por una detección especifica de la imagen, también es posible entregar información mas precisa, como por ejemplo; si el rostro es de una mujer y si es así...de que mujer se trata (un familiar, famoso, conocido, etc).

En la actualidad existen distintos algoritmos que pueden ser implementados para una detección facial, muchos de ellos un tanto complejos o específicos según el área en donde se desea emplear, estos pueden llegar a tratarse de redes neuronales, grafos, entre otros. Sin embargo vamos a comprender uno de los métodos mas populares y eficientes que permiten detectar objetos en tiempo real. 

Clasificador de Cascada.

Mejor conocido como algoritmo o clasificador Haar, fue el primer framework de detección de objetos propuesto por Paul Viola y Michael Jones en 2001 que permitía el análisis de imágenes en tiempo real, haciendo uso de una función matemática (Wavelet Haar) propuesta por Alfred Haar en 1909.

Los clasificadores haar, definen regiones rectangulares sobre una imagen en escala de grises (imagen integral) y al estar formada por un numero finito de rectángulos, se puede obtener un valor escalar que consiste en sumar los pixeles de cada rectángulo, en base a una serie de clasificadores en cascada. Cada clasificador determina si la subregion se trata del objeto buscado o no. A diferencia de otros algoritmos, este solo invierte capacidad de procesamiento a las subregiones que posiblemente representen un rostro.

Deteccion facial 1Deteccion facial 2

¿Aburridos? Si, yo se que la teoría detrás del código suele ser un poco tediosa, pero no quiero hacer el típico tutorial que solo trata de mostrar lineas de código, muchas veces necesitamos comprender el origen y el porque, de determinada porción de código o pieza de software.

Lo interesante hasta este punto, es que mediante OpenCV, la mayoría de los algoritmos empleados (te invito a leer su código fuente en Github) ya están hechos...así que solo nos enfocaremos en la parte del desarrollo del software de detección facial.

Hasta aquí, tratamos de abarcar el funcionamiento de las cascadas o clasificadores mediante filtros haar. Pero todo ciclo de detección de objetos basado en este algoritmo necesita ser entrenado, es decir, para que funcione debemos proporcionar dos tipos de muestras: positivas y negativas.

Las muestras positivas del objeto son imágenes recortadas que contienen la referencia del objeto en si. Las muestras negativas son aquellas imágenes que no contienen el objeto a detectar. Se estima que para una detección positiva en un 96% se debe recolectar entre 1,000 y 10,000 muestras de cada tipo de muestra.

La buena noticia es que nosotros omitiremos este paso, ya que OpenCV nos regala un fichero .xml que contiene la información de una cascada Haar entrenada para detección facial y que podemos utilizar libremente para este fin. (Quizás en otro momento escriba un tutorial sobre como generar cascadas Haar para otro tipo de objetos)

Instalación de OpenCV

Antes de comenzar la instalación, debes asegurarte de contar con la versión 2.7.x del interprete de Python (No funciona en la versión 3), ademas tener instalado:

Voy a separar los pasos para Windows y la distribución Ubuntu, para abarcar las plataformas mas populares.

Windows.

Una vez cumplidos los requisitos anteriores, vamos a descargar OpenCV en su versión mas reciente (3.1).

Como es un archivo comprimido, nos va preguntar donde extraer su contenido; yo recomiendo extraerlo en la raíz de la partición C, para que nos sea mas fácil identificarlo posteriormente.

Ahora hay que ir al directorio de extracción y vamos a ir a la carpeta build\python\2.7\(x64 o x86 segun tu interprete)  dentro vamos a encontrar un archivo llamado cv2.pyd , lo vamos a copiar dentro de C:\Python27\Lib\site-packages

Si todo esta correctamente instalado y seguiste mis pasos, abre tu interprete de python y ejecuta lo siguiente:

>>> import cv2
>>> cv2.__version__
'3.1.0'

Si te muestra un resultado parecido o igual al mio, quiere decir que ya estas listo para continuar con el tutorial.

Ubuntu.

Primero vamos a asegurarnos de actualizar la lista de repositorios de nuestra distribucion y actualizar si es posible.

$ sudo apt-get update
$ sudo apt-get upgrade

Ahora vamos a instalar las herramientas de desarrollo, necesarias para compilar el codigo fuente de OpenCV.

$ sudo apt-get install build-essential cmake git pkg-config

Si no contamos con los requisitos previos, como Numpy y Matplotlib, vamos a proceder con su instalacion, mediante los siguientes comandos:

$ sudo apt-get install python-dev python-numpy
$ sudo apt-get install python-scipy

Ahora vamos a instalar las librerías que permiten mostrar la interfaz de usuario en nuestros programas...OpenCV nos permite utilizar cualquiera de los dos back-ends mas populares, nosotros vamos a instalar el que se adapte mas a nuestro entorno de escritorio (GTK es el recomendado para Ubuntu).

Si deseamos utilizar QT como backend, ejecutamos:

$ sudo apt-get install qt5-default
$ sudo apt-get install libqt5opengl5-dev

Si deseamos utilizar GTK, ejecutamos lo siguiente:

$ sudo apt-get install libgtk2.0-dev
$ sudo apt-get install libgtkglext1 libgtkglext1-dev

Como es de suponerse, OpenCV maneja distintos formatos de imagen, asi que necesitamos instalar las librerias necesarias para permitirle cargar estos formatos.

$ sudo apt-get install libpng3 pngtools libpng12-dev libpng12-0 libpng++-dev
$ sudo apt-get install libjpeg-dev libjpeg libjpeg-dbg libjpeg-progs
$ sudo apt-get install libtiff4-dev libtiff4 libtiffxx0c2 libtiff-tools
$ sudo apt-get install libjasper1-dev libjasper libjasper-runtime
$ sudo apt-get install zlib1g zlib1g-dbg zlib1g-dev

Así como instalamos librerías para la carga y manipulación de imágenes, también debemos agregar soporte para la manipulación de video:

$ sudo apt-get install libavformat-dev libavutil51 libavutil-dev
$ sudo apt-get install libxine2-dev libxine2
$ sudo apt-get install libswscale-dev libswscale2
$ sudo apt-get install libdc1394-22 libdc1394-22-dev libdc1394-utils

Si no contamos con los codecs de video y audio necesarios, los podemos instalar con los siguientes comandos:

$ sudo apt-get install libavformat-dev libavutil51 libavutil-dev
$ sudo apt-get install libxine2-dev libxine2
$ sudo apt-get install libswscale-dev libswscale2
$ sudo apt-get install libdc1394-22 libdc1394-22-dev libdc1394-utils

OpenCV al estar escrito en C++, tiene características de ejecución multi-core, así que para agregar dicho soporte a nuestros programas, vamos a instalar el siguiente paquete:

$ sudo apt-get install libtbb-dev

Como vamos a compilar OpenCV desde el código fuente, necesitamos descargar el proyecto directamente desde github, así que abrimos una terminal nueva y nos posicionamos en el directorio donde deseamos almacenar dicho proyecto. (Yo recomiendo una carpeta llamada "Github" dentro del "Home")

Una vez dentro de nuestro directorio, desde la terminal, ingresamos:

$ git clone https://github.com/Itseez/opencv

Despues hay que traer la version mas reciente de la rama master:

$ git pull origin master

Una vez clonado el repositorio, accedemos a la carpeta del proyecto y creamos una carpeta nueva dentro de la misma para generar el archivo de configuracion necesario para compilar opencv.

$ cd opencv
$ mkdir build
$ cd build

Ahora vamos a crear el makefile necesario para compilar, con el comando cmake; podemos especificar los parámetros que deseamos incluir en los binarios, pero si no eres muy diestro compilando desde las fuentes; te dejo la configuración optima para cualquier distribución linux.

cmake -DCMAKE_BUILD_TYPE=RELEASE \
 -DCMAKE_INSTALL_PREFIX=/usr/local \
 -DINSTALL_C_EXAMPLES=OFF \
 -DINSTALL_PYTHON_EXAMPLES=ON \
 -DBUILD_EXAMPLES=ON \
 -DBUILD_NEW_PYTHON_SUPPORT=ON \
 -DWITH_TBB=ON \
 -DWITH_V4L=ON \
 -DWITH_QT=ON \
 -DWITH_OPENGL=ON \
 -DWITH_VTK=ON ..

Bien, ahora vamos a empezar a compilar con make; como este proceso suele tardar bastante dependiendo de la potencia de cada equipo, tenemos la opción de especificar los cores que deseamos utilizar de nuestro procesador para acelerar este proceso. (-j4, indica 4 cores)

$ make -j4

Asumiendo que el proceso de compilación no tuvo ningún inconveniente, ahora instalamos OpenCV en nuestra distribución, mediante: 

$ sudo make install
$ sudo ldconfig 

Hasta aquí hemos finalizado con la instalación en GNU/LINUX. Si deseamos comprobar la instalación, basta con abrir el interprete de python y ejecutar: 

>> import cv2

Si el interprete no manda algún mensaje de error, entonces tienes instalado correctamente OpenCV.

Detección de Rostros.

Bien, ahora vamos a comenzar con el código en python, para reconocer rostros.

Primero debemos importar las librerías y cargar el archivo "cascade" ya configurado para detectar rostros, y como les había mencionado, OpenCV ya trae uno por defecto que nos va ser de mucha utilidad.

import cv2
import sys

imagen_dir = sys.argv[1]  #obtenemos la ruta de la imagen a analizar y almacenamos
cascade_dir = sys.argv[2] #obtenemos la ruta del archivo cascade y almacenamos

#Cargamos el archivo cascade
rostroCascade = cv2.CascadeClassifier(cascade_dir)

Ahora necesitamos cargar la imagen y leerla, con un filtro de "escala de grises" para un mejor análisis.

imagen = cv2.imread(imagen_dir)  #cargamos imagen
filtro = cv2.cvtColor(imagen, cv2.COLOR_BGR2GRAY) #aplicamos filtro

Bien, es momento de realizar el análisis de la imagen y devolver los rostros encontrados en una matriz.

rostros = rostroCascade.detectMultiScale(
	filtro,
	scaleFactor = 1.2,
	minNeighbors = 5,
	minSize= (30,30),
	flags = cv2.CASCADE_SCALE_IMAGE
)

La funcion detectMultiScale es la que se encarga de detectar objetos a partir del archivo cascade que hemos cargado, ademas de recibir como primer parámetro el filtro.

El parámetro scaleFactor se encarga de compensar las diferentes dimensiones de los posibles rostros que puede encontrar durante el análisis, esto se debe a que algunas camaras parecen enfocar mas cerca de lo que aparentan.

El parámetro minNeighbors le indica al detector cuantas veces tiene que pasar sobre la imagen para reducir el numero de falsos positivos en la imagen; esto se debe a que el analizador, hace un recorrido de la imagen en distintas posiciones y direcciones, así que de manera horizontal podemos deducir que algo se parece a un rostro, pero en la siguiente pasada aparecería otro objeto que no lo es. Ademas nos ayudamos del parámetro minSize para indicarle el tamaño mínimo del objeto, de otra forma sera ignorado.

Por ultimo recorremos la matriz resultante con la información de los rostros encontrados en la imagen y para poder visualizarla de manera gráfica, editamos la imagen cargada y dibujamos rectangulos de colores correspondientes a la matriz..

for (x, y, w, h) in rostros:
	##imagen, coordenadas, dimension, color rgb, canal alpha
	cv2.rectangle(imagen, (x, y), (x+w, y+h), (0, 255, 0), 2)

cv2.imshow("Rostros encontrados", imagen) #abrimos una ventana con la imagen resultante
cv2.waitKey(0) #evento de salida o cierre de la ventana

El codigo final es el siguiente:

import cv2
import sys

imagen_dir = sys.argv[1] 
cascade_dir = sys.argv[2]

rostroCascade = cv2.CascadeClassifier(cascade_dir)

imagen = cv2.imread(imagen_dir) 
filtro = cv2.cvtColor(imagen, cv2.COLOR_BGR2GRAY) 

rostros = rostroCascade.detectMultiScale(
	filtro,
	scaleFactor = 1.2,
	minNeighbors = 5,
	minSize= (30,30),
	flags = cv2.CASCADE_SCALE_IMAGE
)

for (x, y, w, h) in rostros:
	cv2.rectangle(imagen, (x, y), (x+w, y+h), (0, 255, 0), 2)

cv2.imshow("Rostros encontrados", imagen) 
cv2.waitKey(0) 

Para probarlo, lo almacenamos en algún lugar de nuestra computadora y abrimos una terminal o consola de comandos y ejecutamos:

$ python nombre_de_mi_fuente.py imagen.jpg haarcascade_frontalface_default.xml

Si no encuentran el archivo xml, lo pueden descargar de aquí. Pero la ruta por default de este y otros archivos de configuración están en 'opencv/data/haarcascades'

Al ejecutar el comando anterior, tendríamos un resultado como el siguiente:

deteccion facil 3


Si analizamos la imagen, no detecto a "Scarlet Witch" y "Hawkeye", esto se debe a que sus rostros están en una posición mas de perfil y el archivo cascade solo esta entrenado para detectar rostros con posición frontal y no perfilados.

Con esto concluimos el tutorial, espero que les haya servido y sea de utilidad para futuros proyectos, no se olviden de compartirlo en redes sociales; hasta la proxima!

Compartelo en:    

Acerca del Autor

Aarón Díaz R Software Developer

Soy desarrollador de software con experiencia en bases de datos y lenguajes de programación como Python, Java SE, Javascript, C y PHP.

  Comentarios



"El ser de las cosas, no su verdad, es la causa de la verdad en el entendimiento."

- Santo Tomás de Aquino