Detecci贸n facial en Python con OpenCV

    Introducci贸n

    La detecci贸n facial es un caso de uso com煤n y poderoso del Machine Learning. Se puede utilizar para automatizar tareas manuales como la asistencia a la escuela y la aplicaci贸n de la ley. Por otro lado, se puede utilizar para la autorizaci贸n biom茅trica.

    En este art铆culo, realizaremos la detecci贸n facial en Python, usando OpenCV.

    OpenCV

    OpenCV es una de las bibliotecas de visi贸n por computadora m谩s populares. Fue escrito en C y C ++ y tambi茅n proporciona soporte para Python, adem谩s de Java y MATLAB. Si bien no es la biblioteca m谩s r谩pida que existe, es f谩cil trabajar con ella y proporciona una interfaz de alto nivel, lo que permite a los desarrolladores escribir c贸digo estable.

    Instalemos OpenCV para que podamos usarlo en nuestro c贸digo Python:

    $ pip install opencv-contrib-python
    

    Alternativamente, puede instalar opencv-python solo para los m贸dulos principales de OpenCV. los opencv-contrib-python contiene los m贸dulos principales, as铆 como los m贸dulos contrib que proporcionan funcionalidad ampliada.

    Detectar rostros en una imagen usando OpenCV

    Con OpenCV instalado, podemos importarlo como cv2 en nuestro c贸digo.

    Para leer una imagen, usaremos el imread() funci贸n, junto con la ruta a la imagen que queremos procesar. los imread() funci贸n simplemente carga la imagen del archivo especificado en una ndarray. Si la imagen no se pudo leer, por ejemplo, en caso de que falte un archivo o un formato no compatible, la funci贸n volver谩 None.

    Usaremos una imagen de Conjunto de datos de Kaggle:

    import cv2
    
    path_to_image="Parade_12.jpg"
    original_image = cv2.imread(path_to_image)
    

    La informaci贸n RGB completa no es necesaria para la detecci贸n facial. El color contiene mucha informaci贸n irrelevante en la imagen, por lo que es m谩s eficiente simplemente eliminarlo y trabajar con una imagen en escala de grises. Adem谩s, el algoritmo Viola-Jones, que funciona bajo el cap贸 con OpenCV, verifica la diferencia de intensidad del 谩rea de una imagen. Las im谩genes en escala de grises se帽alan esta diferencia de manera m谩s dram谩tica.

    Nota: En el caso de las im谩genes en color, las im谩genes decodificadas tendr谩n los canales almacenados en orden BGR, por lo que al cambiarlos a escala de grises, necesitamos utilizar el cv2.COLOR_BGR2GRAY bandera:

    image = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY)
    

    Esto podr铆a haberse hecho directamente al usar imread(), configurando el cv2.IMREAD_GRAYSCALE bandera:

    original_image = cv2.imread(path_to_image, cv2.IMREAD_GRAYSCALE)
    

    La biblioteca OpenCV viene con varios clasificadores entrenados previamente que est谩n entrenados para encontrar diferentes cosas, como caras, ojos, sonrisas, parte superior del cuerpo, etc.

    los Haar Las funciones para detectar estos objetos se almacenan como XML y, seg煤n c贸mo haya instalado OpenCV, se pueden encontrar con mayor frecuencia en Libsite-packagescv2data. Tambi茅n se pueden encontrar en el Repositorio OpenCV GitHub.

    Para acceder a ellos desde el c贸digo, puede utilizar un cv2.data.haarcascades y agregue el nombre del archivo XML que le gustar铆a usar.

    Podemos elegir qu茅 funciones de Haar queremos usar para nuestra detecci贸n de objetos, agregando la ruta del archivo al CascadeClassifier() constructor, que utiliza modelos previamente entrenados para la detecci贸n de objetos:

    face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
    

    Ahora, podemos usar esto face_cascade objeto para detectar caras en la imagen:

    detected_faces = face_cascade.detectMultiScale(image=image, scaleFactor=1.3, minNeighbors=4)
    

    Cuando los modelos de detecci贸n de objetos est谩n entrenados, est谩n entrenados para detectar rostros de cierto tama帽o y pueden pasar por alto rostros m谩s grandes o m谩s peque帽os de lo esperado. Teniendo esto en cuenta, se cambia el tama帽o de la imagen varias veces con la esperanza de que una cara termine siendo de un tama帽o “detectable”. los scaleFactor le permite a OpenCV saber cu谩nto escalar las im谩genes. En nuestro caso, 1.3 significa que puede escalar 30% abajo para intentar emparejar mejor las caras.

    En cuanto a minNeighbors par谩metro, se utiliza para controlar el n煤mero de falsos positivos y falsos negativos. Define el n煤mero m铆nimo de rect谩ngulos positivos (detectar rasgos faciales) que deben estar adyacentes a un rect谩ngulo positivo para que se considere realmente positivo. Si minNeighbors se establece en 0, el menor indicio de un rostro se contar谩 como un rostro definitivo, incluso si no se detectan otros rasgos faciales cerca de 茅l.

    Ambos scaleFactor y minNeighbors los par谩metros son algo arbitrarios y se establecen experimentalmente. Hemos elegido valores que funcionaron bien para nosotros y no dieron falsos positivos, con la compensaci贸n de m谩s falsos negativos (caras no detectadas).

    los detectMultiScale() El m茅todo devuelve una lista de rect谩ngulos de todos los objetos detectados (caras en nuestro primer caso). Cada elemento de la lista representa una cara 煤nica. Esta lista contiene tuplas, (x, y, w, h), donde el x, y Los valores representan las coordenadas superior izquierda del rect谩ngulo, mientras que w, h los valores representan el ancho y el alto del rect谩ngulo, respectivamente.

    Podemos usar la lista devuelta de rect谩ngulos y usar el cv2.rectangle() funci贸n para dibujar f谩cilmente los rect谩ngulos donde se detect贸 una cara. Tenga en cuenta que el color proporcionado debe ser una tupla en orden RGB:

    for (x, y, width, height) in detected_faces:
        cv2.rectangle(
            image,
            (x, y),
            (x + width, y + height),
            color,
            thickness=2
        )
    

    Ahora, pong谩moslo todo junto:

    import cv2
    
    def draw_found_faces(detected, image, color: tuple):
        for (x, y, width, height) in detected:
            cv2.rectangle(
                image,
                (x, y),
                (x + width, y + height),
                color,
                thickness=2
            )
    
    path_to_image="Parade_12.jpg"
    original_image = cv2.imread(path_to_image)
    
    if original_image is not None:
        # Convert image to grayscale
        image = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY)
    
        # Create Cascade Classifiers
        face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
        profile_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_profileface.xml")
        
        # Detect faces using the classifiers
        detected_faces = face_cascade.detectMultiScale(image=image, scaleFactor=1.3, minNeighbors=4)
        detected_profiles = profile_cascade.detectMultiScale(image=image, scaleFactor=1.3, minNeighbors=4)
    
        # Filter out profiles
        profiles_not_faces = [x for x in detected_profiles if x not in detected_faces]
    
        # Draw rectangles around faces on the original, colored image
        draw_found_faces(detected_faces, original_image, (0, 255, 0)) # RGB - green
        draw_found_faces(detected_profiles, original_image, (0, 0, 255)) # RGB - red
    
        # Open a window to display the results
        cv2.imshow(f'Detected Faces in {path_to_image}', original_image)
        # The window will close as soon as any key is pressed (not a mouse click)
        cv2.waitKey(0) 
        cv2.destroyAllWindows()
    else:
        print(f'En error occurred while trying to load {path_to_image}')
    

    Usamos dos modelos diferentes en esta imagen. El modelo predeterminado para detectar caras frontales y un modelo creado para detectar mejor las caras que miran hacia los lados.

    Caras detectadas con el frontalface El modelo est谩 delineado en verde y las caras detectadas con el profileface El modelo est谩 delineado en rojo. La mayor铆a de las caras que encontr贸 el primer modelo tambi茅n se habr铆an encontrado con el segundo, por lo que solo dibujamos rect谩ngulos rojos donde profileface modelo detect贸 una cara pero frontalface no:

    profiles_not_faces = [x for x in detected_profiles if x not in detected_faces]
    

    los imshow() El m茅todo simplemente muestra la imagen pasada en una ventana con el t铆tulo proporcionado. Con la imagen que seleccionamos, esto proporcionar铆a el siguiente resultado:

    Usando diferentes valores para scaleFactor y minNeighbors nos dar谩 resultados diferentes. Por ejemplo, usando scaleFactor = 1.1 y minNeighbors = 4 nos da m谩s falsos positivos y verdaderos positivos con ambos modelos:

    Podemos ver que el algoritmo no es perfecto, pero es muy eficiente. Esto es m谩s notable cuando se trabaja con datos en tiempo real, como una transmisi贸n de video de una c谩mara web.

    Detecci贸n de rostros en tiempo real mediante una c谩mara web

    Las secuencias de video son simplemente secuencias de im谩genes. Con la eficiencia del algoritmo Viola-Jones, podemos realizar la detecci贸n de rostros en tiempo real.

    Los pasos que debemos seguir son muy similares al ejemplo anterior con una sola imagen; lo realizaremos en cada imagen de la transmisi贸n.

    Para obtener la transmisi贸n de video, usaremos el cv2.VideoCapture clase. El constructor de esta clase toma un par谩metro entero que representa el flujo de video. En la mayor铆a de las m谩quinas, se puede acceder a la c谩mara web pasando 0, pero en m谩quinas con varias transmisiones de video, es posible que deba probar diferentes valores.

    A continuaci贸n, necesitamos leer im谩genes individuales del flujo de entrada. Esto se hace con el read() funci贸n, que devuelve retval y image. los image es simplemente el marco recuperado. los retval El valor de retorno se utiliza para detectar si un marco se ha recuperado o no, y ser谩 False si no es as铆.

    Sin embargo, tiende a ser inconsistente con las transmisiones de entrada de video (no detecta que la c谩mara web se haya desconectado, por ejemplo), por lo que ignoraremos este valor.

    Sigamos adelante y modifiquemos el c贸digo anterior para manejar una transmisi贸n de video:

    import cv2
    
    def draw_found_faces(detected, image, color: tuple):
        for (x, y, width, height) in detected:
            cv2.rectangle(
                image,
                (x, y),
                (x + width, y + height),
                color,
                thickness=2
            )
    
    # Capturing the Video Stream
    video_capture = cv2.VideoCapture(0)
    
    # Creating the cascade objects
    face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_frontalface_default.xml")
    eye_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + "haarcascade_eye_tree_eyeglasses.xml")
    
    while True:
        # Get individual frame
        _, frame = video_capture.read()
        # Covert the frame to grayscale
        grayscale_image = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        
    	# Detect all the faces in that frame
        detected_faces = face_cascade.detectMultiScale(image=grayscale_image, scaleFactor=1.3, minNeighbors=4)
        detected_eyes = eye_cascade.detectMultiScale(image=grayscale_image, scaleFactor=1.3, minNeighbors=4)
        draw_found_faces(detected_faces, frame, (0, 0, 255))
        draw_found_faces(detected_eyes, frame, (0, 255, 0))
    
        # Display the updated frame as a video stream
        cv2.imshow('Webcam Face Detection', frame)
    
        # Press the ESC key to exit the loop
        # 27 is the code for the ESC key
        if cv2.waitKey(1) == 27:
            break
    
    # Releasing the webcam resource
    video_capture.release()
    
    # Destroy the window that was showing the video stream
    cv2.destroyAllWindows()
    

    Conclusi贸n

    En este art铆culo, creamos una aplicaci贸n de detecci贸n facial usando Python y OpenCV.

    El uso de la biblioteca OpenCV es muy sencillo para los programas b谩sicos de detecci贸n de objetos. Ajustando experimentalmente el scaleFactor y minNeighbors Los par谩metros para los tipos de im谩genes que le gustar铆a procesar pueden dar resultados bastante precisos de manera muy eficiente.

     

    Etiquetas:

    Deja una respuesta

    Tu direcci贸n de correo electr贸nico no ser谩 publicada. Los campos obligatorios est谩n marcados con *