Detección de rostros y ojos con OpenCV en Python

Detectar los ojos es un segundo paso: primero se encuentra la cara y luego se buscan los ojos solo dentro de ella. Así se va más rápido y no aparecen «ojos» en la ropa o en el fondo.

Si vienes de un tutorial antiguo, esto te va a pasar. Desde OpenCV 5, el detector clásico CascadeClassifier ya no viene en el paquete normal. Con pip install opencv-python el código de siempre falla así:
AttributeError: module 'cv2' has no attribute 'CascadeClassifier'
Se ha trasladado al paquete opencv-contrib-python, y los archivos XML de las cascadas ya no se instalan con él: hay que bajarlos aparte. Lo que el paquete normal trae ahora es un detector basado en redes neuronales, mejor en casi todo. Las dos opciones están en esta página.

Con cascadas Haar

pip install opencv-contrib-python-headless

Hacen falta dos archivos de cascada, haarcascade_frontalface_default.xml y haarcascade_eye.xml, que se bajan del repositorio opencv_contrib. La versión anterior de esta página los cargaba desde C:/Users/decodigo/opencv-3.4.6/…, que solo existía en un ordenador.

import cv2

caras_det = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
ojos_det = cv2.CascadeClassifier("haarcascade_eye.xml")

imagen = cv2.imread("tripulacion.jpg")
gris = cv2.cvtColor(imagen, cv2.COLOR_BGR2GRAY)

for (x, y, w, h) in caras_det.detectMultiScale(gris, 1.1, 5, minSize=(60, 60)):
    cv2.rectangle(imagen, (x, y), (x + w, y + h), (255, 100, 30), 3)

    zona_gris = gris[y:y + h // 2, x:x + w]
    zona_color = imagen[y:y + h // 2, x:x + w]

    ojos = ojos_det.detectMultiScale(zona_gris, 1.1, 8, minSize=(15, 15))
    print(f"cara en ({x}, {y}): {len(ojos)} ojos")
    for (ox, oy, ow, oh) in ojos:
        cv2.rectangle(zona_color, (ox, oy), (ox + ow, oy + oh), (60, 200, 60), 2)

cv2.imwrite("resultado_ojos.jpg", imagen)
salidacara en (523, 164): 2 ojos
cara en (806, 354): 1 ojos
cara en (248, 332): 2 ojos
cara en (683, 596): 0 ojos
Armstrong, Collins y Aldrin con un recuadro azul en cada cara y recuadros verdes en los ojos detectados; a Aldrin solo se le detecta un ojo
Las tres caras con sus ojos. A Aldrin, a la derecha, solo se le detecta uno: está sonriendo con los ojos medio cerrados. La foto es la oficial de la tripulación del Apolo 11 —Armstrong, Collins y Aldrin—, de la NASA, en dominio público.

Lo que hay que entender del código

La zona de búsqueda es la mitad de arriba de la cara: gris[y:y + h // 2, x:x + w]. Una imagen en OpenCV es una matriz de NumPy, y recortarla es indexarla, primero por filas —la y— y luego por columnas —la x—, al revés de como se escriben las coordenadas. En la mitad de abajo no hay ojos, y buscando ahí la cascada confundiría las comisuras de la boca con ojos.

zona_color no es una copia, es una vista de la imagen original. Por eso los recuadros que se dibujan en ella aparecen en la imagen completa, en su sitio, sin sumar las coordenadas de la cara.

Los resultados cuentan una historia. A Aldrin se le escapa un ojo porque sonríe y casi lo cierra. Y la cuarta «cara», en (683, 596), tiene cero ojos: es el bolsillo del traje que la cascada confundió con una cara, como se explica en la página de detección de rostros. Exigir dos ojos es, de hecho, un filtro sencillo para descartar falsos positivos.

Con YuNet, los ojos ya vienen

El detector moderno de OpenCV devuelve, además del recuadro, cinco puntos de cada cara, y los dos primeros son los ojos. No hay que buscarlos en un segundo paso:

nombres = ["ojo der.", "ojo izq.", "nariz", "boca der.", "boca izq."]
print({n: (int(caras[0][4 + 2*i]), int(caras[0][5 + 2*i])) for i, n in enumerate(nombres)})
salida{'ojo der.': (282, 376), 'ojo izq.': (330, 374), 'nariz': (312, 402), 'boca der.': (284, 421), 'boca izq.': (328, 421)}

«Derecho» e «izquierdo» desde el punto de vista de la persona fotografiada, no del que mira. El ejemplo completo, con la instalación y el modelo, está en la página de detección de rostros. Y si necesitas mucho más detalle que cinco puntos —el contorno de los ojos, de la boca, de la mandíbula—, eso es lo que hace dlib.

Todo el código se ejecutó con Python 3.14 en un contenedor limpio antes de publicar esta página; las salidas están copiadas de esa ejecución.

16 comentarios en «Detección de rostros y ojos con OpenCV en Python»

  1. hola me arroja este error,saludos

    File «C:/Users/xxx/Desktop/open CV test.py», line 23
    if cv2.waitKey(1) & 0xFF == ord(‘q’):
    ^
    SyntaxError: invalid syntax

    Process finished with exit code 1

    Responder
  2. También me causaba error en línea 23, para corregir quiten esto: amp;
    y funciona muy bien. La ruta es de donde guaradron opencv, por ejemplo en mi caso es:

    face_cascade = cv2.CascadeClassifier(
    ‘C:/Users/maria/Downloads/opencv/sources/data/haarcascades/haarcascade_frontalface_default.xml’)

    Responder
  3. Hola, muy util tu ejemplo, me sirvio para terminar de comprender los haar***.xml, ya que el ejemplo de la documentacióon de opencv me daba un error de empty sobre faceCascade. Si quisiera consultarte por la constante 0xFF, que significa o a que hace referencia. Desde ya muchas gracias!

    Responder
    • Que tal Nelson, es una línea algo confusa en realidad.

      La respuesta es la siguiente:

      cv2.waitKey(1) & 0xFF == ord(‘q’)

      1.- cv2.waitKey(1) devuelve un entero de 32 bits correspondiente a la tecla presionada.

      2.- & 0xFF aplica una máscara al valor devuelto anteriormente, establece los 24 bits a la izquierda en cero, porque ord() devuelve un valor entre 0 y 255, ya que los valores del teclado tienen un conjunto de caracteres limitado.

      3.- Una vez que la máscara es aplicada, es posible comprobar si el valor capturado es igual a lo que devuelve la funcion ord(‘q’).

      En resumen, la operación & 0xFF te permite ajustar los valores para poder compararlos.

      Responder

Deja un comentario