Detección de FaceMask usando TensorFlow en Python

En este artículo, analizaremos nuestro detector de máscara facial COVID-19 de dos fases y detallaremos cómo se implementará nuestra canalización de aprendizaje profundo/visión por computadora.

Usaremos este script de Python para entrenar un detector de mascarillas y revisar los resultados. Dado el detector de máscara facial COVID-19 capacitado, procederemos a implementar dos scripts de Python adicionales que se utilizan para:

  • Detectar máscaras faciales COVID-19 en imágenes
  • Detecta máscaras faciales en transmisiones de video en tiempo real

Diagrama de flujo del sistema de detección de mascarillas

 

Para entrenar un detector de máscara facial personalizado, debemos dividir nuestro proyecto en dos fases distintas, cada una con sus respectivos subpasos (como se muestra en la Figura 1 anterior):

  • Entrenamiento: aquí nos centraremos en cargar nuestro conjunto de datos de detección de máscaras faciales desde el disco, entrenar un modelo (usando Keras/TensorFlow) en este conjunto de datos y luego serializar el detector de máscaras faciales en el disco.
  • Despliegue: una vez que se entrena el detector de mascarillas, podemos pasar a cargar el detector de mascarillas, realizar la detección de rostros y luego clasificar cada rostro como con_mascarilla o sin_mascarilla.

 

Usaremos estas imágenes para construir un modelo CNN usando TensorFlow para detectar si está usando una máscara facial usando la cámara web de su PC. ¡Además, también puedes usar la cámara de tu teléfono para hacer lo mismo!

Implementación paso a paso

Paso 1: visualización de datos

En el primer paso, visualicemos el número total de imágenes en nuestro conjunto de datos en ambas categorías. Podemos ver que hay 690 imágenes en la clase ‘sí’ y 686 imágenes en la clase ‘no’.

Número de imágenes con máscara facial etiquetada como ‘sí’: 690 
Número de imágenes con máscara facial etiquetada como ‘no’: 686

Paso 2: aumento de datos

En el siguiente paso, aumentamos nuestro conjunto de datos para incluir más imágenes para nuestro entrenamiento. En este paso de aumento de datos, rotamos y volteamos cada una de las imágenes en nuestro conjunto de datos. Vemos que, después del aumento de datos, tenemos un total de 2751 imágenes con 1380 imágenes en la clase ‘sí’ y ‘1371’ imágenes en la clase ‘no’.

Número de ejemplos: 2751 
Porcentaje de ejemplos positivos: 50,163576881134134 %, número de ejemplos pos: 1380 
Porcentaje de ejemplos negativos: 49,836423118865866 %, número de ejemplos negativos: 1371

Paso 3: dividir los datos

En este paso, dividimos nuestros datos en el conjunto de entrenamiento que contendrá las imágenes en las que se entrenará el modelo CNN y el conjunto de prueba con las imágenes en las que se probará nuestro modelo. En esto, tomamos split_size =0.8, lo que significa que el 80 % del total de imágenes se destinará al conjunto de entrenamiento y el 20 % restante de las imágenes se destinará al conjunto de prueba.

El número de imágenes con máscara facial en el conjunto de entrenamiento con la etiqueta ‘sí’: 1104
El número de imágenes con máscara facial en el conjunto de prueba con la etiqueta ‘sí’: 276
El número de imágenes sin máscara facial en el conjunto de entrenamiento con la etiqueta ‘no’: 1096
El número de imágenes sin máscara facial en el conjunto de prueba etiquetadas como ‘no’: 275

Después de dividir, vemos que el porcentaje deseado de imágenes se ha distribuido tanto al conjunto de entrenamiento como al conjunto de prueba como se mencionó anteriormente.

Paso 4: Construcción del modelo

En el siguiente paso, construimos nuestro modelo de CNN secuencial con varias capas, como Conv2D, MaxPooling2D, Flatten, Dropout y Dense. En la última capa densa, usamos la función ‘softmax’ para generar un vector que da la probabilidad de cada una de las dos clases.

Python3

model = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(100, (3, 3), activation='relu',
                           input_shape=(150, 150, 3)),
    tf.keras.layers.MaxPooling2D(2, 2),
  
    tf.keras.layers.Conv2D(100, (3, 3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2, 2),
  
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Dense(50, activation='relu'),
    tf.keras.layers.Dense(2, activation='softmax')
])
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['acc'])

Aquí, usamos el optimizador ‘adam’ y ‘binary_crossentropy’ como nuestra función de pérdida ya que solo hay dos clases. Además, incluso puede usar MobileNetV2 para una mayor precisión.

 

Paso 5: Pre-entrenamiento del modelo CNN

Después de construir nuestro modelo, creemos ‘train_generator’ y ‘validation_generator’ para adaptarlos a nuestro modelo en el siguiente paso. Vemos que hay un total de 2200 imágenes en el conjunto de entrenamiento y 551 imágenes en el conjunto de prueba.

Encontradas 2200 imágenes pertenecientes a 2 clases. 
Encontradas 551 imágenes pertenecientes a 2 clases.

Paso 6: Entrenamiento del modelo CNN

Este paso es el paso principal en el que ajustamos nuestras imágenes en el conjunto de entrenamiento y el conjunto de prueba en nuestro modelo secuencial que construimos usando la biblioteca keras. He entrenado el modelo durante 30 épocas (iteraciones). Sin embargo, podemos entrenar para una mayor cantidad de épocas para lograr una mayor precisión para que no se produzca un ajuste excesivo.

history = model.fit_generator(train_generator, epochs
                             =30,
                             validation_data=validation_generator,
                             callbacks=[checkpoint])
>>Época 30/30
220/220 [================== ============] – 231 s 1 s/paso – pérdida: 0,0368 – acc: 0,9886 – val_loss: 0,1072 – val_acc: 0,9619

Vemos que después de la época 30, nuestro modelo tiene una precisión del 98,86 % con el conjunto de entrenamiento y una precisión del 96,19 % con el conjunto de prueba. Esto implica que está bien entrenado sin ningún tipo de ajuste excesivo.

Paso 7: Etiquetado de la información

Después de construir el modelo, etiquetamos dos probabilidades para nuestros resultados. [‘0’ como ‘sin_máscara’ y ‘1’ como ‘con_máscara’] . También estoy configurando el color del rectángulo límite usando los valores RGB. [‘ROJO’ para ‘sin_mascarilla’ y ‘VERDE’ para ‘con_mascarilla]

etiquetas_dict={0:’sin_máscara’,1:’con_máscara’} 
color_dict={0:(0,0,255),1:(0,255,0)}

Paso 8: Importación del programa de detección de rostros

Después de esto, pretendemos usarlo para detectar si estamos usando una máscara facial usando la cámara web de nuestra PC. Para esto, primero, necesitamos implementar la detección de rostros. En esto, estamos utilizando los clasificadores en cascada basados ​​en características de Haar para detectar las características faciales.

face_clsfr=cv2.CascadeClassifier(‘haarcascade_frontalface_default.xml’)

Este clasificador en cascada está diseñado por OpenCV para detectar el rostro frontal entrenando miles de imágenes. El archivo .xml para el mismo debe descargarse y usarse para detectar el rostro. Hemos subido el archivo al repositorio de GitHub.

Paso 9: Detección de rostros con y sin máscaras

En el último paso, usamos la biblioteca OpenCV para ejecutar un bucle infinito para usar nuestra cámara web en la que detectamos la cara usando el Clasificador en cascada. El código webcam = cv2.VideoCapture(0) indica el uso de la cámara web.

El modelo predecirá la posibilidad de cada una de las dos clases ([sin_máscara, con_máscara]) . Según la probabilidad más alta, la etiqueta se elegirá y se mostrará alrededor de nuestras caras.

principal.py

Python3

# import the necessary packages
from tensorflow.keras.applications.mobilenet_v2 import preprocess_input
from tensorflow.keras.preprocessing.image import img_to_array
from tensorflow.keras.models import load_model
from imutils.video import VideoStream
import numpy as np
import imutils
import time
import cv2
import os
  
  
def detect_and_predict_mask(frame, faceNet, maskNet):
    
    # grab the dimensions of the frame and 
    # then construct a blob from it
    (h, w) = frame.shape[:2]
    blob = cv2.dnn.blobFromImage(frame, 1.0, (224, 224),
                                 (104.0, 177.0, 123.0))
  
    # pass the blob through the network 
    # and obtain the face detections
    faceNet.setInput(blob)
    detections = faceNet.forward()
    print(detections.shape)
  
    # initialize our list of faces, their
    # corresponding locations, and the list
    # of predictions from our face mask network
    faces = []
    locs = []
    preds = []
  
    # loop over the detections
    for i in range(0, detections.shape[2]):
        
        # extract the confidence (i.e.,
        # probability) associated with
        # the detection
        confidence = detections[0, 0, i, 2]
  
        # filter out weak detections by 
        # ensuring the confidence is
        # greater than the minimum confidence
        if confidence > 0.5:
            
            # compute the (x, y)-coordinates
            # of the bounding box for
            # the object
            box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
            (startX, startY, endX, endY) = box.astype("int")
  
            # ensure the bounding boxes fall 
            # within the dimensions of
            # the frame
            (startX, startY) = (max(0, startX), max(0, startY))
            (endX, endY) = (min(w - 1, endX), min(h - 1, endY))
  
            # extract the face ROI, convert it
            # from BGR to RGB channel
            # ordering, resize it to 224x224, 
            # and preprocess it
            face = frame[startY:endY, startX:endX]
            face = cv2.cvtColor(face, cv2.COLOR_BGR2RGB)
            face = cv2.resize(face, (224, 224))
            face = img_to_array(face)
            face = preprocess_input(face)
  
            # add the face and bounding boxes 
            # to their respective lists
            faces.append(face)
            locs.append((startX, startY, endX, endY))
  
    # only make a predictions if at least one
    # face was detected
    if len(faces) > 0:
        
        # for faster inference we'll make 
        # batch predictions on *all*
        # faces at the same time rather 
        # than one-by-one predictions
        # in the above `for` loop
        faces = np.array(faces, dtype="float32")
        preds = maskNet.predict(faces, batch_size=32)
  
    # return a 2-tuple of the face locations
    # and their corresponding locations
    return (locs, preds)
  
  
# load our serialized face detector model from disk
prototxtPath = r"face_detector\deploy.prototxt"
weightsPath = r"face_detector\res10_300x300_ssd_iter_140000.caffemodel"
faceNet = cv2.dnn.readNet(prototxtPath, weightsPath)
  
# load the face mask detector model from disk
maskNet = load_model("mask_detector.model")
  
# initialize the video stream
print("[INFO] starting video stream...")
vs = VideoStream(src=0).start()
  
# loop over the frames from the video stream
while True:
    # grab the frame from the threaded 
    # video stream and resize it
    # to have a maximum width of 400 pixels
    frame = vs.read()
    frame = imutils.resize(frame, width=400)
  
    # detect faces in the frame and 
    # determine if they are wearing a
    # face mask or not
    (locs, preds) = detect_and_predict_mask(frame, faceNet, maskNet)
  
    # loop over the detected face 
    # locations and their corresponding
    # locations
    for (box, pred) in zip(locs, preds):
        
        # unpack the bounding box and predictions
        (startX, startY, endX, endY) = box
        (mask, withoutMask) = pred
  
        # determine the class label and 
        # color we'll use to draw
        # the bounding box and text
        label = "Mask" if mask > withoutMask else "No Mask"
        color = (0, 255, 0) if label == "Mask" else (0, 0, 255)
  
        # include the probability in the label
        label = "{}: {:.2f}%".format(label, max(mask, withoutMask) * 100)
  
        # display the label and bounding box 
        # rectangle on the output frame
        cv2.putText(frame, label, (startX, startY - 10),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.45, color, 2)
        cv2.rectangle(frame, (startX, startY), (endX, endY), color, 2)
  
    # show the output frame
    cv2.imshow("Frame", frame)
    key = cv2.waitKey(1) & 0xFF
  
    # if the `q` key was pressed, break from the loop
    if key == ord("q"):
        break
  
# do a bit of cleanup
cv2.destroyAllWindows()
vs.stop()

Producción:

 

Publicación traducida automáticamente

Artículo escrito por diveshmandhyanlkodm03 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

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