En visión artificial, una de las tareas básicas es el reconocimiento de objetos, ya que es muy interesante disponer de algún modo de discriminar entre clases de objetos. Por ejemplo, un coche autónomo ha de ser capaz de reconocer a otros coches y distinguirlo de un peatón. Otra utilidad más mundana y que seguro conoces, es el reconocimiento de caras que hace tu móvil cuando vas a hacer una foto.
En este artículos vamos a ver cómo reconocer caras usando OpenCV. Ojo, cuando hablo de reconocer caras, me refiero a distinguir una cara de cualquier otra cosa, no de distinguir entre caras para, por ejemplo, reconocer a quién pertenece esa cara. Ese es otro problema diferente del que os hablaré en otro momento.
Como quiero abordar el problema desde un punto de vista práctico, vamos a usar la librería OpenCV con Python. Como imagen de ejemplo vamos a tomar la siguiente.
Nuestra misión es detectar las caras que hay en esta imagen, así que fije el rumbo señor Sulu.
import cv2 from matplotlib import pyplot as plt img = cv2.imread('TOS-crew.jpg')Tras importar las librerías OpenCV y Matplotlib para visualizar y manipular la imagen, comprobamos que se ha cargado correctamente y verificamos su tamaño.
img.shape
(1115, 2329, 3)Si queremos visualizar la imagen con Matplotlib primero debemos convertirla a la codificación RGB, ya que OpenCV por defecto trabaja con imagenes BGR.
img_RGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) plt.imshow(img_RGB)Si vamos a trabajar con imágenes grandes, a veces es mejor redimensionarlas para hacer las más pequeñas e incluso convertirlas a escala de grises para aliviar su tamaño. Como ejemplo, las líneas siguientes realizan estas dos operaciones.
img_gray = cv2.cvtColor(img_RGB, cv2.COLOR_RGB2GRAY) img_small = cv2.resize(img_gray, (800, 400)) plt.imshow(img_small)Ahora vamos a realizar las busqueda de las caras en la imagen. Con OpenCV es de lo más sencillo. Sólo necesitamos dos líneas de código Python. Sin entrar en detalles, os cuento que el clasificador que vamos a usar se conoce como Haar Cascade o también como algoritmo de Viola-Jones. Vamos a usarlo porque es de los clásicos (que no el mejor). Si queréis conocer más a fondo como funciona el algoritmo podéis consultar el artículo original de 2004 donde Paul Viola y Michael J. Jones presentaron este método en sociedad. Para que este algoritmo funcione hay que entrenarlo mostrandole caras, y otras cosas que no sean caras, para que aprenda a distinguirlos. El proceso puede ser tedioso, ya que son necesaria una relativamente grande cantidad de imágenes. Por suerte ya hay clasificadores preentrenados para reconocer caras (y otras muchas cosas), que están almacenas en formato .xml y que podemos cargar desde OpenCV. El que vamos a usar se llama haarcascade_frontalface_default.xml y se puede descargar de aquí. Está entrenado con caras mirando al frente, cómo las que queremos detectar. En esta página hay más clasificadores preentrenados.
# cargamos el clasificador preentrenado detector_caras = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') detecciones = detector_caras.detectMultiScale(img_RGB) # array de detecciones. una fila por cada cara. Las columnas con [pos_x, pos_y, size_x, size_y] detecciones
array([[ 936, 211, 58, 58], [ 495, 76, 191, 191], [ 708, 109, 235, 235], [1199, 120, 195, 195], [ 221, 124, 212, 212], [1810, 225, 216, 216], [1464, 325, 215, 215], [1540, 326, 215, 215], [1435, 564, 352, 352], [ 622, 572, 348, 348], [1296, 992, 62, 62]], dtype=int32)El array detecciones contiene una fila por cada cara detectada, con cuatro columnas cada una indicando la posición X e Y, así como la anchura y altura del recuadro imaginario que contiene la cara que ha detectado. En este caso vemos que ha detectado 11 caras, cuando en nuestra imagen sólo hay seis personajes. Algo no parece ir bien, así que vamos a mostrar la imagen sobre la que vamos a dibujar estos cuadrados que nos ha devuelto el clasificador.
for (x, y, w, h) in detecciones: cv2.rectangle(img_RGB, (x, y), (x+w, y+h), (0,255,0), 10) plt.imshow(img_RGB)La buena noticia es que ha detectado todas las caras (no ha habido falsos negativos), pero además de las autenticas caras, ha detectado como caras otras partes de la imagen (falsos positivos). Vamos a tratar de realizar algunos ajustes a ver si conseguimos mejorar el resultado. La función detectMultiScale busca las caras realizando varios barridos de la imagen con ventanas de diferentes tamaños (ya que puede haber caras grandes cercanas o pequeñas que estén más lejanas). El tamaño en que se incrementa la ventana en cada barrido se puede cambiar con el parámetro scaleFactor. Por ejemplo un valor de 1.1 (valor por defecto) quiere decir que la ventana seingrementa en un 10% en cada barrido, y un valor de 1.05, aumentaría la ventana en un 5%. Aquí hay que jugar con el valor según sea el tamaño de las caras que aparecen en la imagen. Para nuestra imagen, un valor de 1.7 parece funcionar bien
detecciones = detector_caras.detectMultiScale(img_RGB, scaleFactor = 1.7)Otro parámetro con el que podemos jugar es minNeighbors. Cuando el algoritmo va recorriendo la imagen, acaba reconociendo la misma cara en múltiples ocasiones (aunque sólo nos devuelva una ventana). Por ejemplo, puede reconocer la misma cara con la misma ventana al desplazarla sólo unos pocos pixeles, o en sus múltiples pasadas con diferentes tamaños de ventana. Con minNeighbors podemos indicar el número mínimo de detecciones de una cara que han de darse para que se considere una detección válida. Por ejemplo, la siguiente línea es capaz de detectar correctamente las caras a pesar de no utilizar el parámetro scaleFactor.
detecciones = detector_caras.detectMultiScale(img_RGB, minNeighbors = 20)Por último tenemos los parámetros minSize y maxSize, que permiten indicar el tamaño mínimo y máximo de la cara a detectar. Podemos ver la utilidad práctica con un ejemplo. Veamos qué detecta el clasificador con los siguientes parámetros.
detecciones = detector_caras.detectMultiScale(img_RGB, minNeighbors = 10)Vemos que hay un falso positivo en la oreja del capitán Kirk. Una forma de manejar este tipo de problemas, si sabemos que las caras van a ser mayores (o menores) de cierto tamaño, es indicar un tamaño mínimo (o máximo) para la detección.
detecciones = detector_caras.detectMultiScale(img_RGB, minNeighbors = 10, minSize = (100,100))Como dije al principio, hay otros tipos de clasificadores que tienen mayor rendimiento, pero este es bastante sencillo y eficiente incluso con baja capacidad de proceso, por lo que es muy interesante. En otra ocasión veremos si es posible, no sólo reconocer que hay una cara, sino, además, intentar saber de quién es la cara. Es lo que se denomina reconocimiento facial, o en general reconocimiento de objetos (o de caracteres, o de tipos de naves de la federación, etc.). Hasta entonces... larga vida y prosperidad.
Ecco Car
ResponderEliminarEl post es muy interesante, y es que, es increíble cómo lo que hace años parecía ser ciencia ficción, actualmente es realidad, eso pasa con los coches en la actualidad, los coches eléctricos con todo tipo de extras en tecnología están a la orden del día.