7

Detección y reconocimiento facial con OpenCV, Python y FaceRecognition

¡Hola, homo fabers! Detectar e identificar rostros en imágenes puede parecer una tarea intimidatoria, pero gracias a Python y librerías de visión por computador como OpenCV se convierte en una tarea muy sencilla.

En este tutorial aprenderéis cómo detectar y reconocer rostros con Python y las librerías de visión por computador OpenCV y Face_Recognition. El objetivo final de este tutorial es llegar a programar un pequeño script en Python capaz identificar nuestro careto mediante una webcam. No obstante, también veremos como detectar e identificar rostros humanos en fotografías estáticas, pues hacer el paso a vídeo consiste sólo en añadir unas pocas líneas de programa.

Para poder seguir bien este tutorial es muy recomendable tener buenos conocimientos del lenguaje Python y saber trabajar con librerías. Algunas nociones básicas de como funciona OpenCV también serán de ayuda.


Librerías necesarias

Para este tutorial váis a necesitar Python con las siguientes librerías instaladas:

También váis a necesitar una webcam configurada y que funcione con vuestro sistema operativo.

NOTA IMPORTANTE: Si trabajáis con Python 3 y OpenCV 3+ en Linux, puede que al ejecutar los ejemplos del tutorial os aparezca un error como este al llamar a la función cv2.imshow():

QObject::moveToThread: Current thread (0x1d2c9cf0) is not the object's thread (0x1d347b20).
Cannot move to target thread (0x1d2c9cf0)

Por lo que he leído, parece ser que ocurre por una incompatibilidad de OpenCV con las librerías de QT y no hay forma simple de arreglarlo. Si os ocurre recomiendo cambiar a una versión anterior de Python y/o de OpenCV.


Detección facial vs. Reconocimiento facial

Aunque muchas veces se usan los nombres indistintamente, Detección y Reconocimiento facial no significan exactamente lo mismo.

Se conoce como detección facial el proceso de encontrar rostros humanos en una imagen, sin llegar a identificar a las personas:

En cambio, el reconocimiento facial es ir un paso más allá: no solo buscamos rostros, sino que intentamos verificar la identidad de las personas que aparecen en la imagen:

En este tutorial veremos cómo resolver ambos problemas. En la primera parte utilizaremos OpenCV para hacer detección facial, y en las segunda parte utilizaremos Face_Recognition para hacer reconocimiento facial.


PARTE I: Detección facial con OpenCV

En esta primera parte veremos cómo hacer detección facial con OpenCV tanto en una imagen estática como en un vídeo capturado con una webcam.

¿Cómo consigue OpenCV detectar rostros?

OpenCV utiliza el algoritmo de Viola & Jones para detectar rostros, que desde su publicación en 2001 es probablemente el algoritmo por excelencia para hacer este tipo de tareas. Este algoritmo está pensado para detectar objetos concretos, ya sean rostros, coches, gatos, plátanos…

Para poder detectar objetos se necesita un clasificador. Podemos imaginar los clasificadores como una especie de “plantilla” para detectar un determinado tipo de objeto. Este clasificador es entrenado proporcionándole cientos de imágenes de ejemplo del objeto que se quiere detectar.

El clasificador busca características visuales en las imágenes de ejemplo. Las características que se utilizan son las llamadas “Características de Tipo Haar” (en inglés, Haar-Like Features), las cuáles tienen esta forma:

A la hora de entrenar al clasificador, se buscan combinaciones de estas caracterísitcas en las imágenes de ejemplo y se eligen las más significativas para que formen parte del clasificador.

Cuando se quieren detectar objetos, el algoritmo aplica una serie de clasificadores (una “cascada de clasificadores”) sobre una región de interés en la que considera que podría hallarse el objeto en cuestión. Si todos los clasificadores acaban dando positivo, el algoritmo considera que hay una coincidencia y se ha encontrado el objeto deseado. En nuestro caso, un rostro.

Esta es la idea intuitiva que hay detrás del algoritmo de detección de objetos de OpenCV. Para los que estéis interesados en los detalles más técnicos os recomiendo buscar el paper original de Viola & Jones.

Descargar el classificador de Haar

Hemos visto que para detectar objetos se necesita un clasificador. ¿Significa esto que tendremos que entrenar nuestro propio clasificador de rostros? ¡Qué va! OpenCV ya nos proporciona varios clasificadores en formato .xml que están preparados para reconocer cosas como rostros, manos, siluetas humanas, etc.

En esta página de github podéis encontrar una lista con todos los ficheros .xml que nos ofrece OpenCV. Descargad el que se llama ‘haarcascade_frontalface_alt.xml’ y guardadlo en un directorio que recordéis.

Código 1.1: detección facial en una imagen

Vamos a empezar viendo cómo detectar rostros en una imagen estática.

Descargad la imagen que hay debajo, que utilizaremos como ejemplo, y guardadla con el nombre ‘imagen_input.jpg’ en el mismo directorio donde tengáis el fichero .xml que acabáis de descargar de github:

Guardad esta imagen con el nombre ‘imagen_input.jpg’

 

Ahora cread un nuevo fichero de Python y copiad el código que hay debajo. Para que funcione debe ejecutarse en el mismo directorio en el que tengamos el fichero .xml y la imagen.

# -*- coding: latin-1 -*-
"""
	Código 1.1 - Detección facial en una imagen estática
	Este programa encuentra todos los rostros de una fotografía.

	Escrito por Glare y Transductor
	www.robologs.net
"""
import cv2

#Cargamos nuestro classificador de Haar:
cascada_rostro = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml')
# Si utilizas otro clasificador o lo tienes guardado en un directorio diferente al de este script python, 
# tendrás que cambiar 'haarcascade_frontalface_alt.xml' por el path a tu fichero xml.


#Cargamos la imagen y la convertimos a grises:
img = cv2.imread('imagen_input.jpg')
img_gris = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# Nota: la imagen de ejemplo que hemos utilizado para el tutorial ya está en blanco y negro,
# por lo que no sería necesario convertirla. Lo he hecho igualmente por si más adelante queréis
# probar con una imagen en color.


#Buscamos los rostros:
coordenadas_rostros = cascada_rostro.detectMultiScale(img_gris, 1.3, 5)
# Nota 1: la función detectMultiScale() requiere una imagen en escala de grises. Esta es la razón
# por la que hemos hecho la conversión de BGR a Grayscale.
# Nota 2: '1.3' y '5' son parámetros estándar para esta función. El primero es el factor de escala ('scaleFactor'): la
# función intentará encontrar rostros escalando la imagen varias veces, y este factor indica en cuánto se reduce la imagen
# cada vez. El segundo parámetro se llama 'minNeighbours' e indica la calidad de las detecciones: un valor elevado
# resulta en menos detecciones pero con más fiabilidad.


#Ahora recorremos el array 'coordenadas_rostros' y dibujamos los rectángulos sobre la imagen original:
for (x,y,ancho, alto) in coordenadas_rostros:
	cv2.rectangle(img, (x,y), (x+ancho, y+alto), (0,0,255) , 3)


#Abrimos una ventana con el resultado:
cv2.imshow('Output', img)
print("\nMostrando resultado. Pulsa cualquier tecla para salir.\n")
cv2.waitKey(0)
cv2.destroyAllWindows()

 

¡Hecho! Si todo ha funcionado correctamente, al ejecutar este programa debería abrirse una ventana con este resultado:

 

Código 1.2: detección facial en un vídeo

Podemos ampliar un poco el código anterior para que detecte nuestro rostro con la webcam del ordenador:

# -*- coding: latin-1 -*-
"""
	Código 1.2 - Detección facial en un vídeo en tiempo real
	Este programa detecta rostros con una webcam.

	Escrito por Glare y Transductor
	www.robologs.net
"""
import cv2

#Cargamos nuestro classificador de Haar:
cascada_rostro = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml')
# Si utilizas otro clasificador o lo tienes guardado en un directorio diferente al de este script python, 
# tendrás que cambiar 'haarcascade_frontalface_alt.xml' por el path a tu fichero .xml.

#Iniciar la webcam:
webcam = cv2.VideoCapture(0)
# NOTA 1: Si no funciona puedes cambiar el índice 0 por otro, o cambiarlo por la dirección de tu webcam (p.ej. '/dev/video0')
# NOTA 2: también debería funcionar si en vez de una webcam utilizas un fichero de vídeo.

#Recordamos al usuario cuál es la tecla para salir:
print("\nRecordatorio: pulsa 'ESC' para cerrar.\n")


while(1):

	#Capturar una imagen con la webcam:
	valido, img = webcam.read() 

	#Si la imagen es válida (es decir, si se ha capturado correctamente), continuamos:
	if valido:

		#Convertir la imagen a gris:
		img_gris = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)


		#Buscamos los rostros:
		coordenadas_rostros = cascada_rostro.detectMultiScale(img_gris, 1.3, 5)


		#Recorremos el array 'coordenadas_rostros' y dibujamos los rectángulos sobre la imagen original:
		for (x,y,ancho, alto) in coordenadas_rostros:
			cv2.rectangle(img, (x,y), (x+ancho, y+alto), (0,0,255) , 3)


		#Abrimos una ventana con el resultado:
		cv2.imshow('Output', img)

		#Salir con 'ESC':
		k = cv2.waitKey(5) & 0xFF
		if k == 27:
			cv2.destroyAllWindows()
			break

webcam.release()

Al igual que antes, este programa necesita ejecutarse en el mismo directorio en el que está el fichero .xml para que funcione correctamente. Si lo habéis hecho bien, veréis que se abre una ventana con la imagen de la webcam y que marca nuestra cara con un recuadro rojo.


PARTE II: Reconocimiento facial con OpenCV y FaceRecognition

Hasta ahora hemos visto cómo encontrar todas las caras de una imagen. El siguiente paso es identificar las personas que aparecen y mostrar sus nombres.

OpenCV es muy buena librería de visión por computador (¡y mi favorita!), y nos proporciona herramientas muy efectivas para detectar rostros. Sin embargo, no dispone de funciones para identificar fácilmente a personas. Por tanto, utilizaremos la librería Face_Recognition que está específicamente diseñada para hacer reconocimiento facial de humanos.

Si os interesa conocer más acerca de la teoría que hay detrás de los algoritmos de reconocimiento facial, os recomiendo muchísimo leer este artículo.

Código 2.1: reconocimiento facial en una imagen

Vamos a hacer un programa que nos identifique el rostro de algunos físicos famosos. Concretamente identificaremos a Albert Einstein, Max Planck y Paul Langevin en dos imágenes distintas.

Si el programa identifica un rostro, dibujará un recuadro verde con el nombre. En caso contrario, dibujará un recuadro rojo.

Para empezar, necesitamos fotografias de referencia de las personas que queremos identificar para que el programa pueda aprender las características únicas de su rostro. Descargad estas tres imágenes y guardadlas con los nombres ‘einstein.jpg’, ‘paul.jpg’ y ‘planck.jpg’.

‘einstein.jpg’

‘paul.jpg’

‘planck.jpg’

 

Como he dicho, vamos a intentar identificar estos señores en dos imágenes distintas.

La primera imagen es la que ya hemos utilizado en el ejemplo de detección facial, en la que aparecen Einstein y Planck. Si no lo habéis hecho ya, descargadla con el nombre ‘imagen_input.jpg’:

‘imagen_input.jpg’

La segunda imagen será esta fotografía en la que aparecen Einstein y Langevin junto con otros físicos alemanes. Guardadla con el nombre ‘imagen_input2.jpg’:

‘imagen_input2.jpg’

El código de abajo será el que utilizaremos para identificar los rostros. Al igual que en los ejemplos anteriores, aseguraos de ejecutarlo en el mismo directorio donde tengáis todas las imágenes:

# -*- coding: latin-1 -*-
"""
	Código 2.1 - Reconocimiento facial en una imagen estática
	Este programa identifica varios rostros de físicos famosos en fotografías.

	Escrito por Glare y Transductor
	www.robologs.net
"""
import cv2
import face_recognition

#Cargamos las imagenes con los rostros que queremos identificar:
imagen_einstein = face_recognition.load_image_file("einstein.jpg")
imagen_paul = face_recognition.load_image_file("paul.jpg")
imagen_planck = face_recognition.load_image_file("planck.jpg")


#El siguiente paso es extraer los 'encodings' de cada imagen.
#Los encodings son las características únicas de cada rostro que permiten diferenciarlo de otros.
einstein_encodings = face_recognition.face_encodings(imagen_einstein)[0]
paul_encodings = face_recognition.face_encodings(imagen_paul)[0]
planck_encodings = face_recognition.face_encodings(imagen_planck)[0]


#Creamos un array con los encodings y otro con sus respectivos nombres:
encodings_conocidos = [
	einstein_encodings,
	paul_encodings,
	planck_encodings
]
nombres_conocidos = [
	"Albert Einstein",
	"Paul Langevin",
	"Max Planck"
]


#Cargamos una fuente de texto:
font = cv2.FONT_HERSHEY_COMPLEX 


#Cargamos la imagen donde hay que identificar los rostros:
img = face_recognition.load_image_file('imagen_input.jpg')
#(Para probar la segunda imagen hay que cambiar el argumento de la función por 'imagen_input2.jpg')



# Definir tres arrays, que servirán para guardar los parámetros de los rostros que se encuentren en la imagen:
loc_rostros = [] #Localizacion de los rostros en la imagen (contendrá las coordenadas de los recuadros que las contienen)
encodings_rostros = [] #Encodings de los rostros
nombres_rostros = [] #Nombre de la persona de cada rostro


#Localizamos cada rostro de la imagen y extraemos sus encodings:
loc_rostros = face_recognition.face_locations(img)
encodings_rostros = face_recognition.face_encodings(img, loc_rostros)


#Recorremos el array de encodings que hemos encontrado:
for encoding in encodings_rostros:

	#Buscamos si hay alguna coincidencia con algún encoding conocido:
	coincidencias = face_recognition.compare_faces(encodings_conocidos, encoding)

	#El array 'coincidencias' es ahora un array de booleanos.
	#Si contiene algun 'True', es que ha habido alguna coincidencia:
	if True in coincidencias:
		#Buscamos el nombre correspondiente en el array de nombres conocidos:
		nombre = nombres_conocidos[coincidencias.index(True)]

	#Si no hay ningún 'True' en el array 'coincidencias', no se ha podido identificar el rostro:
	else:
		nombre = "???"

	#Añadimos el nombre de la persona identificada en el array de nombres:
	nombres_rostros.append(nombre)


#Dibujamos un recuadro rojo alrededor de los rostros desconocidos, y uno verde alrededor de los conocidos:
for (top, right, bottom, left), nombre in zip(loc_rostros, nombres_rostros):

	#Cambiar el color segun el nombre:
	if nombre != "???":
		color = (0,255,0) #Verde
	else:
		color = (0,0,255) #Rojo

	#Dibujar los recuadros alrededor del rostro:
	cv2.rectangle(img, (left, top), (right, bottom), color, 2)
	cv2.rectangle(img, (left, bottom - 20), (right, bottom), color, -1)

	#Escribir el nombre de la persona:
	cv2.putText(img, nombre, (left, bottom - 6), font, 0.6, (0,0,0), 1)

#Abrimos una ventana con el resultado:
cv2.imshow('Output', img)
print("\nMostrando resultado. Pulsa cualquier tecla para salir.\n")
cv2.waitKey(0)
cv2.destroyAllWindows()

 

Si ejecutáis el código veréis que identifica los rostros de la primera imagen:

 

Para probarlo con la segunda imagen, cambiad la línea
img = face_recognition.load_image_file('imagen_input.jpg')
por
img = face_recognition.load_image_file('imagen_input2.jpg')

 

Código 2.2: reconocimiento facial con webcam

Podemos ampliar el programa anterior para que aprenda a identificar nuestro rostro con una webcam.

Para este segundo ejemplo vamos a necesitar una foto nuestra. Idealmente, tendría que ser una foto clara y mirando a la cámara (una foto estilo pasaporte sería ideal). Guardadla con el nombre ‘foto_personal.jpg’.

El código que vamos a utilizar es este:

# -*- coding: latin-1 -*-

"""
	Código 2.2 - Reconocimiento facial con webcam
	Este código identifica nuestro rostro en un vídeo capturado con una webcam.

	Escrito por Glare y Transductor
	www.robologs.net
"""


import cv2
import face_recognition


#Cargar la imagen de ejemplo con nuestro rostro:
imagen_personal = face_recognition.load_image_file("foto_personal.jpg")

#Extraer los 'encodings' que caracterizan nuestro rostro:
personal_encodings = face_recognition.face_encodings(imagen_personal)[0]

#Definir un array con los encodings y nuestro nombre:
encodings_conocidos = [
	personal_encodings
]
nombres_conocidos = [
	"Soy yo :)"
]
# NOTA: Como solo queremos identificarnos a nosotros mismos, en realidad no sería necesario definir un array.
# Lo he hecho así para imitar la estructura del código del ejemplo anterior, y para que sea fácil añadir
# nuevos rostros (vuestra pareja o hijos, por ejemplo).


#Iniciar la webcam:
webcam = cv2.VideoCapture(0)
# NOTA: Si no funciona puedes cambiar el índice '0' por otro, o cambiarlo por la dirección de tu webcam.


#Cargar una fuente de texto:
font = cv2.FONT_HERSHEY_COMPLEX 


# Identificar rostros es un proceso costoso. Para poder hacerlo en tiempo real sin que haya retardo
# vamos a reducir el tamaño de la imagen de la webcam. Esta variable 'reduccion' indica cuanto se va a reducir:
reduccion = 5 #Con un 5, la imagen se reducirá a 1/5 del tamaño original


#Recordamos al usuario cuál es la tecla para salir:
print("\nRecordatorio: pulsa 'ESC' para cerrar.\n")


while 1:
	#Definimos algunos arrays y variables:
	loc_rostros = [] #Localizacion de los rostros en la imagen
	encodings_rostros = [] #Encodings de los rostros
	nombres_rostros = [] #Nombre de la persona de cada rostro
	nombre = "" #Variable para almacenar el nombre

	#Capturamos una imagen con la webcam:
	valido, img = webcam.read()

	#Si la imagen es válida (es decir, si se ha capturado correctamente), continuamos:
	if valido:

		#La imagen está en el espacio de color BGR, habitual de OpenCV. Hay que convertirla a RGB:
		img_rgb = img[:, :, ::-1] 

		#Reducimos el tamaño de la imagen para que sea más rápida de procesar:
		img_rgb = cv2.resize(img_rgb, (0, 0), fx=1.0/reduccion, fy=1.0/reduccion)

		#Localizamos cada rostro de la imagen y extraemos sus encodings:
		loc_rostros = face_recognition.face_locations(img_rgb)
		encodings_rostros = face_recognition.face_encodings(img_rgb, loc_rostros)

		#Recorremos el array de encodings que hemos encontrado:
		for encoding in encodings_rostros:

			#Buscamos si hay alguna coincidencia con algún encoding conocido:
			coincidencias = face_recognition.compare_faces(encodings_conocidos, encoding)

			#El array 'coincidencias' es ahora un array de booleanos. Si contiene algun 'True', es que ha habido alguna coincidencia:
			if True in coincidencias:
				nombre = nombres_conocidos[coincidencias.index(True)]

			#Si no hay ningún 'True' en el array 'coincidencias', no se ha podido identificar el rostro:
			else:
				nombre = "???"

			#Añadir el nombre de la persona identificada en el array de nombres:
			nombres_rostros.append(nombre)

		#Dibujamos un recuadro rojo alrededor de los rostros desconocidos, y uno verde alrededor de los conocidos:
		for (top, right, bottom, left), nombre in zip(loc_rostros, nombres_rostros):
			
			#Deshacemos la reducción de tamaño para tener las coordenadas de la imagen original:
			top = top*reduccion
			right = right*reduccion
			bottom = bottom*reduccion
			left = left*reduccion

			#Cambiar de color según si se ha identificado el rostro:
			if nombre != "???":
				color = (0,255,0)
			else:
				color = (0,0,255)

			#Dibujar un rectángulo alrededor de cada rostro identificado, y escribir el nombre:
			cv2.rectangle(img, (left, top), (right, bottom), color, 2)
			cv2.rectangle(img, (left, bottom - 20), (right, bottom), color, -1)
			cv2.putText(img, nombre, (left, bottom - 6), font, 0.6, (0,0,0), 1)

		#Mostrar el resultado en una ventana:
		cv2.imshow('Output', img)

		#Salir con 'ESC'
		k = cv2.waitKey(5) & 0xFF
		if k == 27:
			cv2.destroyAllWindows()
			break

webcam.release()


Ejemplo extra: ¡GATETES!

¡¿Sabiáis que OpenCV tiene un clasificador entrenado para detectar GATOS?! Yo tampoco, hasta que empecé a redactar este tutorial. Así pues… ¡Vamos a programar un detector de gatitos!

Abrid el enlace de github de los clasificadores y descargad ‘haarcascade_frontalcatface_extended.xml’. Después descargad esta imagen guardadla con el nombre ‘imagen_gatos.jpg’:

‘imagen_gatos.jpg’

 

¡Y ahora toca programar! Este código es idéntico al que hemos utilizado para detectar rostros en imágenes estáticas; únicamente cambia el nombre de los ficheros que cargamos y los parámetros de la función detectMultiScale().

# -*- coding: latin-1 -*-
"""
	Extra - Detector de gatos
	Este programa detecta gatetes en una fotografía

	Escrito por Glare y Transductor
	www.robologs.net
"""
import cv2

#Cargamos nuestro classificador de gatos:
cascada_rostro = cv2.CascadeClassifier('haarcascade_frontalcatface_extended.xml')


#Cargamos la imagen y la convertimos a grises:
img = cv2.imread('imagen_gatos.jpg')
img_gris = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)


#Buscamos los gatitos:
coordenadas_rostros = cascada_rostro.detectMultiScale(img_gris, 1.1, 2)


#Marcamos todos los gatos de la imagen:
for (x,y,ancho, alto) in coordenadas_rostros:
	cv2.rectangle(img, (x,y), (x+ancho, y+alto), (0,255,0) , 3)


#Abrimos una ventana con el resultado:
cv2.imshow('Beware the holy kitten', img)
print("\nMostrando resultado. Pulsa cualquier tecla para salir.\n")
cv2.waitKey(0)
cv2.destroyAllWindows()

 

Debo decir que el clasificador de gatos que nos proporcionan los chicos de OpenCV es un poco malo, y solo detecta rostros de gatos que miren frontalmente a la cámara (y a veces ni eso).


ERRORES Y PREGUNTAS FRECUENTES

Aquí he recogido algunos de los errores más frecuentes que podéis experimentar al correr los ejemplos, junto con algunas preguntas habituales. Si encontráis un problema que no está recogido aquí podéis escribirme un comentario. Pero por favor: leed y revisad bien todos los pasos del tutorial, y aseguraos de que vuestra duda no se soluciona buscando en Google (más de la mitad de las dudas que contesto se resuelven con el primer resultado de una búsqueda por Internet).

1. QObject::moveToThread error

Como he dicho al principio, si utilizáis Python 3 u OpenCV 3+ puede que os aparezca este error al llamar cv2.imshow():

QObject::moveToThread: Current thread (0x1d2c9cf0) is not the object's thread (0x1d347b20).
Cannot move to target thread (0x1d2c9cf0)

Por lo que he leído, este error se debe a una incompatibilidad de OpenCV con las librerías de QT, y no hay una forma sencilla de resolverlo. Si os ocurre, os sugiero cambiar a una versión anterior de OpenCV y/o de Python. Alternativamente podéis usar PIL para mostrar las imágenes, o podéis utilizar cv2.imwrite() para guardar el resultado en una imagen y después abrirla con otro programa.

2. En el código de Detección Facial, aparece la ventana con la imagen pero no señala los rostros.

Esto es porque no se ha cargado bien el clasificador de Haar. Asegúrate de que tengas el fichero .xml en el mismo directorio en el que estás ejecutando tu código python, y que no te has equivocado al escribir el nombre de este fichero cuando llamas a la función cv2.CascadeClassifier().
Por otra parte, si estás detectando rostros con la webcam intenta que tu rostro se vea claramente y que haya suficiente luz. Si llevas gafas, quítatelas.

3. No se ha cargado la imagen

Si OpenCV no puede abrir la imagen de ejemplo en la que hay que buscar rostros, os dará un error parecido a este:

OpenCV Error: Assertion failed (scn == 3 || scn == 4) in cvtColor, file /build/opencv-ys8xiq/opencv-2.4.9.1+dfsg/modules/imgproc/src/color.cpp, line 3737
Traceback (most recent call last):
File "deteccion.py", line 19, in
img_gris = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
cv2.error: /build/opencv-ys8xiq/opencv-2.4.9.1+dfsg/modules/imgproc/src/color.cpp:3737: error: (-215) scn == 3 || scn == 4 in function cvtColor

Si habéis copiado mis ejemplos sin hacer ningún cambio, comprobad que la imagen de ejemplo esté en el mismo directorio donde estáis ejecutando el código de python y que tenga el nombre ‘imagen_input.jpg’. Si habéis hecho algún cambio o estáis intentando cargar una imagen que esté en otro directorio, comprobad que el path a la imagen que habéis pasado a la función cv2.imread() sea el correcto.

4. ¿Cómo puedo saber el número de rostros que se han detectado?

En el caso del código de detección facial, el array ‘coordenadas_rostros’ contiene las coordenadas de todas las caras que se han detectado. Por tanto, si calculas la longitud del array sabrás cuantos rostros hay en la imagen.

Lo mismo con el array ‘loc_rostros’ en los códigos de reconocimiento facial.

5. ¿Cómo puedo mostrar un mesaje o encender un led de Raspberry/Arduino/ESP al detectar un rostro?

Esta pregunta está ligada a la anterior. Puedes crear un condicional que compruebe si el número de rostros es mayor que 0, y después ejecutar una acción como escribir un texto por consola o enviar un mensaje por serial (que puede ser leído por Arduino/ESP).

Nuestro lector Pablo Agustín Becerra nos ha enviado dos códigos de ejemplo para encender el LED 13 de una placa Arduino cada vez que se detecte un rostro. El primer código es el que debe ejecutarse en nuestro ordenador, y utiliza la librería pySerial para enviar el carácter ‘h’ si la longitud del array de rostros es mayor que cero:

# -*- coding: latin-1 -*-
 
"""
    Este programa detecta rostros con OpenCV, y envia el caracter 'h' por
    serial si detecta alguno (en caso contrario, envia 'n')
 
    Escrito por Pablo Becerra y Glare
"""

import cv2  
import serial


#Abrir comunicacion serial:
ser = serial.Serial('/dev/ttyUSB1', 9600)
#Nota: cambia la dirección /dev/ttyUSB1 por la de tu placa Arduino.

#Cargar haarcascade:
face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_alt.xml')

#Inicializar webcam:
webcam = cv2.VideoCapture(0)


while(True):

    #Capturar un frame con la webcam:
    valido, img = webcam.read()

    #Si el frame se ha capturado correctamente, continuamos:
    if valido:

        #Convertir el frame de BGR a grises:
        img_gris = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

        #Detectar todos los rostros del frame, y guardar sus coordenadas:
        array_rostros = face_cascade.detectMultiScale(img_gris, 1.3, 5)

        #Si el array de rostros no está vacío, enviamos el carácter 'h'
        if len(array_rostros) > 0:
         ser.write(str('h').encode())

        #En caso contrario, enviamos el carácter 'n':
        else:
         ser.write(str('n').encode())

        #También abriremos una ventana y marcaremos los rostros detectados:
        for (x,y,w,h) in array_rostros:
                cv2.rectangle(img,(x,y),(x+w,y+h),(125,255,0),2)
        cv2.imshow('Webcam',img)

        #Salimos con 'ESC':
        k = cv2.waitKey(5) & 0xFF
        if k == 27:
            cv2.destroyAllWindows()
            break

ser.close()
webcam.release()
cv2.destroyAllWindows()

 

El segundo código debe cargarse dentro de la placa Arduino, y encenderá el LED 13 cada vez que se reciba el carácter ‘h’ por Serial (y lo apagará si recibe otro):

/*
  Programa para Arduino: este programa enciende el LED 13 cuando
  se recibe el carácter 'h' por serial, y lo apaga si recibe otro.

  Escrito por Pablo Becerra y Glare.
*/

//Se define el pin del LED:
#define LED 13

//Variable para almacenar el caracter que llega por serial:
char lectura;

void setup()
{
   //Se inicia el Serial:
   Serial.begin(9600);

   //Definir el pin 13 como output:
   pinMode(LED, OUTPUT);
} 


void loop()
{
   if(Serial.available() >= 1)
   {
      //Leemos el serial y guardamos el mensaje:
      lectura = Serial.read();

      //Si recibimos 'h', encendemos el LED:
      if(lectura == 'h')
      {
         digitalWrite(LED, HIGH);
      }
      //En caso contrario, lo apagamos:
      else
      {
         digitalWrite(LED, LOW);
      }
   }
}

Gl4r3

Brillante, luminosa y cegadora a veces, Glare es tan artista como técnica. Le encanta dar rienda suelta a sus módulos de imaginación y desdibujar los ya de por si delgados límites que separan el mundo de la electrónica y el arte. Su mayor creación hasta la fecha es un instrumento capaz de convertir los colores y la luz en música. Cuándo sus circuitos no están trabajando en una nueva obra electrónica, le gusta dedicar sus ciclos a la lectura o a documentar sus invenciones para beneficio de los humanos. Sus artilugios favoritos son aquellos que combinan una funcionalidad práctica con un diseño elegante y artístico.

7
Deja un comentario

avatar
2 Hilos iniciados
5 Respuestas a hilos
0 Followers
 
Most reacted comment
Hottest comment thread
4 Nº autores comentarios
PabloGl4r3pabloJanny López Autores de comentarios recientes
más nuevos primero más antiguos primero
pablo
Humano
pablo

Yo recuerdo q hice en arduino q se prenda una luz al detectar rostro por una camara el año pasado, gracias a tu blog y de otros. si quieres puedo contribuir con esto y como lo hice :3

Janny López
Humano
Janny López

Un tutorial muy completo, gracias!