31/03/2024
El reconocimiento facial ha pasado de ser una fantasía de ciencia ficción a una realidad omnipresente en nuestro día a día, desde el desbloqueo de nuestros teléfonos inteligentes hasta la seguridad en aeropuertos. Esta tecnología, impulsada por avances significativos en el aprendizaje automático y las redes neuronales, ofrece soluciones innovadoras a problemas complejos. En este artículo, desglosaremos el proceso de construcción de un sistema de reconocimiento facial robusto y eficiente utilizando Python y dos arquitecturas de redes neuronales convolucionales de vanguardia: MobileNet para la detección de rostros y FaceNet para la verificación. Prepárate para sumergirte en el mundo de la inteligencia artificial y aprender a implementar una solución práctica capaz de identificar sujetos en imágenes con múltiples rostros, incluso bajo diferentes condiciones y expresiones.

- ¿Qué es el Sistema de Reconocimiento Facial?
- El Problema a Resolver: Un Sistema de Verificación
- Configuración Inicial y Funciones de Utilidad
- Detección de Rostros con MobileNet
- Reconocimiento Facial con FaceNet
- Preguntas Frecuentes (FAQ)
- ¿Qué es un "embedding" en el contexto del reconocimiento facial?
- ¿Por qué se utilizan dos redes diferentes, MobileNet y FaceNet?
- ¿Cuál es la importancia de la normalización de la imagen antes de FaceNet?
- ¿Cómo se determina si un rostro "coincide" con uno de referencia?
- ¿Es este sistema apto para uso en tiempo real?
- Conclusión
¿Qué es el Sistema de Reconocimiento Facial?
Un sistema de reconocimiento facial es una aplicación tecnológica capaz de identificar o verificar la identidad de una persona a partir de una imagen digital o un fotograma de video. Generalmente, este proceso se divide en dos fases fundamentales:
- Detección de Rostros: En esta primera etapa, el sistema localiza las regiones dentro de una imagen que contienen rostros humanos. Es crucial que el algoritmo sea capaz de identificar todos los rostros presentes, sin importar su tamaño, orientación o las condiciones de iluminación.
- Reconocimiento Facial: Una vez detectados los rostros, la segunda fase se encarga de determinar a qué sujeto específico pertenece cada uno de ellos. Esto implica comparar las características del rostro detectado con una base de datos de rostros conocidos para encontrar una coincidencia.
Ambas fases hacen uso intensivo de Redes Convolucionales (CNNs), que son modelos de aprendizaje profundo excepcionalmente buenos para el procesamiento de imágenes. En este tutorial, combinaremos estas ideas para construir un sistema de reconocimiento facial completo, capaz de tomar una imagen con múltiples rostros y determinar, para cada uno de ellos, si corresponden o no a un rostro de referencia previamente establecido.
El Problema a Resolver: Un Sistema de Verificación
Nuestro objetivo principal será desarrollar un sistema que pueda verificar la presencia de un sujeto particular en una imagen, la cual puede contener uno o varios rostros. Esto es lo que se conoce como un sistema de verificación de identidad. Para ilustrarlo, utilizaremos un conjunto de imágenes de referencia (rostros "conocidos") y una serie de imágenes de prueba (rostros "desconocidos").
Imaginemos que tenemos varias imágenes de una persona específica, pero tomadas en diferentes momentos, con distintas expresiones faciales, poses o incluso usando accesorios como gafas. El sistema debe ser lo suficientemente inteligente como para reconocer a esta persona en nuevas imágenes, incluso si las condiciones son distintas a las de las fotos de referencia. Por ejemplo, en nuestras imágenes de prueba, el sujeto de referencia puede aparecer con gestos o poses variadas, y las imágenes también pueden incluir a otras personas o elementos del cuerpo, no solo el rostro. El desafío radica en que el sistema detecte con precisión todos los rostros presentes y, lo que es más importante, discrimine cuáles de ellos corresponden al sujeto de referencia y cuáles no.
Para lograr esta robustez, el problema se abordará en dos etapas bien diferenciadas y secuenciales:
- Detección de Rostros: Primero, implementaremos un sistema de detección de rostros utilizando la red MobileNet. Esta etapa nos proporcionará las coordenadas exactas de cada rostro presente en la imagen.
- Reconocimiento Facial: Luego, cada rostro detectado será procesado por la red FaceNet, que se encargará de la tarea de verificación, es decir, de determinar si el rostro en cuestión pertenece o no al sujeto de referencia.
Visualmente, el proceso se puede entender como un flujo: una imagen de entrada pasa por MobileNet para la detección, generando "cajas" alrededor de los rostros. Cada una de estas cajas se alimenta a FaceNet para la extracción de características únicas, y finalmente, estas características se comparan con las de los rostros de referencia para etiquetar al rostro como "verificado" (por ejemplo, en verde) o "no verificado" (en rojo).
Tabla Comparativa: MobileNet vs. FaceNet
Para entender mejor los roles de cada red en nuestro sistema, veamos sus características principales:
| Característica | MobileNet | FaceNet |
|---|---|---|
| Propósito Principal | Detección de Rostros | Generación de Embeddings (Reconocimiento) |
| Tipo de Salida | Cajas Delimitadoras (Coordenadas) | Vector de 128 Elementos (Embedding) |
| Optimización | Dispositivos Móviles, Eficiencia | Precisión en Distinción Facial |
| Librería/Framework | TensorFlow (usado para cargar el grafo) | Keras/TensorFlow |
Configuración Inicial y Funciones de Utilidad
Antes de sumergirnos en la lógica de las redes neuronales, es fundamental establecer un entorno de trabajo y definir algunas funciones básicas que nos facilitarán la lectura de imágenes y la visualización de los resultados. Estas funciones actuarán como los cimientos de nuestro sistema.
Definiremos primero las rutas a los directorios que contendrán nuestras imágenes:
DIR_KNOWNS: Directorio para las imágenes de referencia (rostros conocidos).DIR_UNKNOWNS: Directorio para las imágenes de prueba (rostros desconocidos).DIR_RESULTS: Directorio donde se guardarán las imágenes con los resultados del reconocimiento.
Todas estas rutas se asumen relativas a la carpeta donde se ejecute el código fuente.
Ahora, implementaremos dos funciones esenciales utilizando la librería OpenCV, una herramienta poderosa para el procesamiento de imágenes:
load_image(DIR, NAME): Esta función se encargará de leer una imagen desde un directorio específico y convertirla al formato de color RGB, que es el estándar con el que trabajan la mayoría de los modelos de aprendizaje profundo.draw_box(image, box, color, line_width=6): Una función simple pero crucial que nos permitirá dibujar un rectángulo alrededor de los rostros detectados. Recibe la imagen, las coordenadas de la caja delimitadora (bounding box), el color deseado para el rectángulo (verde para rostros verificados, rojo para no verificados) y el grosor de la línea. Si no se detecta ningún rostro o la caja está vacía, simplemente retorna la imagen original.
Con estas herramientas básicas configuradas, estamos listos para abordar la primera fase crucial de nuestro sistema: la detección de rostros.
Detección de Rostros con MobileNet
La detección precisa de rostros es el primer paso indispensable para cualquier sistema de reconocimiento facial. Para esta tarea, utilizaremos MobileNet, una arquitectura de red convolucional conocida por su eficiencia y su capacidad para operar en dispositivos con recursos limitados. Este modelo ha sido pre-entrenado específicamente para la detección de objetos, y en nuestro caso, para identificar rostros humanos.
Lectura del Modelo Pre-entrenado de MobileNet
El modelo pre-entrenado de MobileNet se almacena en un formato de grafo de TensorFlow (mobilenet_graph.pb). Para cargarlo en nuestra aplicación Python, haremos uso de las funciones tf.io.gfile e import_graph_def de TensorFlow. Una vez cargado, el modelo estará accesible a través de la variable mobilenet, listo para ser utilizado en el proceso de detección.
La importancia de usar un modelo pre-entrenado radica en que no necesitamos entrenar la red desde cero, lo cual requeriría una enorme cantidad de datos y recursos computacionales. En su lugar, aprovechamos el conocimiento que el modelo ya ha adquirido al ser entrenado con millones de imágenes, lo que nos permite un inicio rápido y resultados precisos.
Función para la Detección de Rostros: detect_faces
Ahora implementaremos la función central para la detección de rostros, llamada detect_faces. Esta función tomará como entrada la imagen original y un parámetro clave: score_threshold (umbral de puntuación). El umbral es fundamental porque MobileNet, como muchos detectores de objetos, tiende a identificar múltiples regiones de interés para un mismo rostro, y algunas de estas detecciones pueden no ser del todo precisas.
Cada región de interés detectada por MobileNet viene acompañada de una puntuación de confianza, un valor entre 0 y 1 que indica la probabilidad de que esa región contenga un rostro (1 es certeza total, 0 es baja probabilidad). Nuestra función filtrará estas detecciones, seleccionando solo aquellas con una puntuación superior o igual al score_threshold (por ejemplo, 0.7, que significa un 70% de probabilidad). Las coordenadas de estas regiones seleccionadas (left, right, top, bottom) se almacenarán en una lista llamada bboxes, representando las cajas delimitadoras de los rostros detectados.
Dentro de esta función, la imagen de entrada se prepara para MobileNet (expandiendo sus dimensiones) y luego se alimenta al modelo. El modelo de TensorFlow ejecuta una "predicción" y nos devuelve las posibles cajas delimitadoras (boxes) y sus respectivas puntuaciones de confianza (scores). Finalmente, estos resultados se ajustan al tamaño original de la imagen y se filtran por el umbral para obtener las detecciones más fiables.
Prueba de la Etapa de Detección de Rostros
Para validar la eficacia de MobileNet, tomaremos una imagen de prueba desafiante, como christian_bale_01.jpg, que contiene múltiples rostros con diferentes poses y expresiones. El proceso es sencillo: cargamos la imagen usando load_image, aplicamos la función detect_faces, y luego usamos draw_box para visualizar las regiones detectadas. La visualización se realiza con Matplotlib.
Si todo funciona como se espera, observaremos que MobileNet ha identificado correctamente la totalidad de los rostros presentes en la imagen, demarcándolos con rectángulos verdes. Este resultado satisfactorio nos confirma que la primera etapa de nuestro sistema, la detección de rostros, está funcionando de manera óptima, abriendo el camino para la fase de reconocimiento facial.
Reconocimiento Facial con FaceNet
Una vez que hemos detectado los rostros en una imagen, el siguiente paso es determinar la identidad de cada uno de ellos. Aquí es donde entra en juego FaceNet, una poderosa red neuronal diseñada para generar "embeddings" de rostros. Estos embeddings son la clave para un reconocimiento facial preciso y eficiente.
Cálculo de Embeddings usando FaceNet
Un embedding es una representación numérica compacta de un rostro. En lugar de trabajar directamente con la complejidad de todos los píxeles de una imagen facial, FaceNet comprime esta información en un vector de 128 elementos. Lo remarkable de este vector es que es prácticamente único para cada individuo, y su valor es consistente incluso si el sujeto cambia de pose, expresión o utiliza accesorios. Es decir, dos imágenes del mismo sujeto, aunque diferentes visualmente, producirán embeddings muy similares, mientras que imágenes de sujetos distintos producirán embeddings muy diferentes.
Lectura del Modelo Pre-entrenado de FaceNet
El modelo pre-entrenado de FaceNet, generalmente guardado como facenet_keras.h5, se carga utilizando la función load_model de Keras, una API de alto nivel para construir y entrenar modelos de aprendizaje profundo. Al cargar el modelo, podemos verificar sus dimensiones de entrada y salida: FaceNet espera una imagen RGB de 160x160 píxeles como entrada y produce un vector de 128 elementos como salida.
Extracción y Redimensionamiento de Rostros: extract_faces
Dado que la etapa de detección de MobileNet nos entrega rostros de diferentes tamaños (dependiendo del tamaño original del rostro en la imagen), necesitamos una función que prepare estos rostros para FaceNet. La función extract_faces toma la imagen original y las cajas delimitadoras de los rostros detectados. Para cada caja, extrae la porción de la imagen correspondiente al rostro y luego la redimensiona a 160x160 píxeles, el tamaño exacto requerido por FaceNet. Esto asegura que todos los rostros, sin importar su tamaño original, se presenten de manera uniforme al modelo de FaceNet.
Cálculo del Embedding: compute_embedding
Con los rostros ya extraídos y redimensionados, la función compute_embedding se encarga de alimentarlos a FaceNet para obtener su representación numérica. Antes de la predicción, es crucial normalizar la imagen del rostro. Esto se logra restando el valor promedio de los píxeles y dividiendo por la desviación estándar. La normalización es un paso estándar en el procesamiento de datos para redes neuronales, ya que ayuda a garantizar la convergencia y la estabilidad del algoritmo de entrenamiento, y es necesaria para que el modelo pre-entrenado funcione correctamente.
Una vez normalizada, la imagen del rostro se pasa al método model.predict() de FaceNet, que devuelve el vector de 128 elementos, el embedding, que encapsula las características únicas de ese rostro.
Reconocimiento Facial: Comparando los Embeddings
La fase final del reconocimiento facial consiste en comparar los embeddings de los rostros desconocidos con los embeddings de los rostros de referencia. Esta comparación se basa en el cálculo de la distancia entre estos vectores. Cuanto menor sea la distancia entre dos embeddings, mayor será la similitud entre los rostros que representan.
Cálculo de Embeddings de Referencia
Primero, necesitamos calcular los embeddings de todos nuestros rostros de referencia (los que se encuentran en DIR_KNOWNS). Para cada imagen de referencia, aplicamos la misma secuencia de pasos: lectura de la imagen (load_image), detección de rostros (detect_faces), extracción del rostro (extract_faces) y cálculo de su embedding (compute_embedding). Estos embeddings de referencia se almacenan en una lista llamada known_embeddings.
Función de Comparación: compare_faces
La función compare_faces toma como entradas los embeddings de referencia (embs_ref) y el embedding del rostro desconocido (emb_desc). Calcula la distancia euclidiana entre el embedding desconocido y cada uno de los embeddings de referencia. La métrica utilizada es la norma euclidiana (np.linalg.norm), que nos da una medida de la "distancia" en el espacio de 128 dimensiones.
Para determinar si un rostro desconocido coincide con uno de los rostros de referencia, se aplica un umbral (por ejemplo, 11) a cada una de estas distancias. Si al menos una de las distancias calculadas es inferior o igual a este umbral, consideramos que el rostro desconocido es una coincidencia con uno de los rostros de referencia. La función retorna tanto las distancias calculadas como una lista booleana indicando si cada distancia está por debajo del umbral.
Uniendo las Piezas: Procesamiento de Imágenes Desconocidas
Finalmente, integramos todos los componentes para procesar las imágenes de prueba (desconocidas). Iteramos sobre cada imagen en DIR_UNKNOWNS. Para cada imagen:
- Se carga la imagen.
- Se detectan todos los rostros presentes utilizando MobileNet.
- Por cada rostro detectado, se extrae y redimensiona para FaceNet.
- Se calcula su embedding utilizando FaceNet.
- El embedding del rostro detectado se compara con todos los embeddings de referencia usando
compare_faces. - Si la función
compare_facesindica que hay una coincidencia (es decir, al menos una distancia está por debajo del umbral), el rostro se demarca con un rectángulo verde. De lo contrario, se demarca con un rectángulo rojo. - La imagen resultante, con los rostros etiquetados, se guarda en el directorio
DIR_RESULTS.
Al ejecutar este proceso, el sistema imprimirá mensajes indicando qué imágenes se están procesando y si se ha encontrado una coincidencia ("match!") en ellas. Los resultados visuales en el directorio results confirmarán la eficacia del sistema, mostrando claramente qué rostros han sido verificados y cuáles no.
Preguntas Frecuentes (FAQ)
¿Qué es un "embedding" en el contexto del reconocimiento facial?
Un embedding es una representación numérica compacta de un rostro, típicamente un vector de números (en nuestro caso, 128 elementos). Es generado por una red neuronal profunda como FaceNet y está diseñado para encapsular las características distintivas de un rostro de tal manera que rostros similares (del mismo individuo) tienen embeddings cercanos en el espacio multidimensional, mientras que rostros diferentes tienen embeddings distantes. Esto permite comparar rostros simplemente calculando la distancia entre sus respectivos embeddings.
¿Por qué se utilizan dos redes diferentes, MobileNet y FaceNet?
Se utilizan dos redes porque realizan tareas distintas y complementarias. MobileNet está optimizada para la detección de rostros, es decir, para encontrar dónde están los rostros en una imagen. FaceNet, por otro lado, se especializa en la generación de embeddings, que son las representaciones numéricas únicas de los rostros. Separar estas tareas permite a cada red ser altamente eficiente en su dominio específico, lo que resulta en un sistema de reconocimiento facial más robusto y preciso. MobileNet es eficiente para la detección rápida, y FaceNet para la creación de huellas dactilares faciales.
¿Cuál es la importancia de la normalización de la imagen antes de FaceNet?
La normalización de la imagen (restar la media y dividir por la desviación estándar de los píxeles) es un paso crucial en el preprocesamiento de datos para muchas redes neuronales, incluida FaceNet. Ayuda a estandarizar la escala de los valores de entrada, lo que puede prevenir problemas durante el proceso de predicción y asegurar que el modelo pre-entrenado funcione como se espera. Sin una normalización adecuada, el modelo podría interpretar los valores de píxeles de manera diferente a como fue entrenado, llevando a resultados inexactos o a una menor eficacia.
¿Cómo se determina si un rostro "coincide" con uno de referencia?
La coincidencia se determina calculando la distancia euclidiana entre el embedding del rostro desconocido y cada uno de los embeddings de los rostros de referencia. Si la distancia entre el embedding desconocido y al menos uno de los embeddings de referencia es menor o igual a un umbral predefinido (en nuestro caso, 11), se considera que hay una coincidencia. Este umbral es un valor clave que define la tolerancia del sistema a las variaciones entre rostros del mismo individuo y debe ser ajustado cuidadosamente.
¿Es este sistema apto para uso en tiempo real?
Dado que MobileNet está optimizada para dispositivos móviles y FaceNet es eficiente en la generación de embeddings, la combinación de ambas redes puede ser sorprendentemente rápida. Si bien la implementación mostrada es para imágenes estáticas, los principios son aplicables a flujos de video. Para un uso en tiempo real, la velocidad de procesamiento dependerá del hardware (CPU/GPU), la resolución del video y la optimización del código, pero la arquitectura subyacente tiene el potencial para aplicaciones en tiempo real.
Conclusión
En este extenso tutorial, hemos explorado paso a paso cómo construir un sistema de reconocimiento facial completo y funcional utilizando el aprendizaje automático y las librerías de Python. Hemos visto cómo la combinación inteligente de MobileNet para la detección de rostros y FaceNet para la generación de embeddings crea una solución robusta y eficiente. Desde la carga de modelos pre-entrenados hasta la implementación de funciones de utilidad y la lógica de comparación de embeddings para la verificación, cada etapa ha sido detallada para permitirte replicar y comprender a fondo el funcionamiento interno de esta fascinante tecnología.
La capacidad de detectar y verificar identidades faciales abre un abanico de posibilidades en campos como la seguridad, la autenticación, la biometría y la automatización. Este proyecto no solo es una demostración práctica de conceptos avanzados de inteligencia artificial, sino también una base sólida para futuras exploraciones y desarrollos en el campo de la visión por computador. Esperamos que esta guía te haya proporcionado el conocimiento y las herramientas necesarias para comenzar a experimentar y construir tus propios sistemas de reconocimiento facial.
Si quieres conocer otros artículos parecidos a Reconocimiento Facial con Python: Guía Completa puedes visitar la categoría Librerías.
