Detecta si una persona lleva mascarilla ? | OpenCV con Python

Por Administrador

En este tutorial te mostraré como puedes construir tu propio detector de mascarillas de una forma fácil y rápida. Además estaré usando contenido que habíamos visto antes, para la detección de rostros MediaPipe Face Detection y para el entrenamiento LBPH FaceRecognizer que usamos en el tutorial de Reconocimiento Facial. ¡Anímate a probarlo!.

CONTENIDO

Detectar si una persona lleva puesta mascarilla

  1.  Dataset
  2.  Entrenamiento
  3. ¡A probar el modelo!

Detectar si una persona lleva puesta mascarilla

Para la realización de este proyecto necesitaremos tener instalados en python: Numpy, OpenCV Y MediaPipe. 

He dividido a este proyecto en 3 secciones de las cuales haré una descripción además del código empleado en cada una de ellas (a excepción de la primera, ya que para esa sección no usamos código).

NOTA: Para más información sobre el código que veremos en este tutorial, por favor dirígete al videotutorial.

1) Dataset

Figura 1: Ilustración del dataset que usaremos en este tutorial.

Para comenzar veremos un dataset con dos clases, por un lado tendremos imágenes a color de rostros con mascarillas, y en otro directorio imágenes de rostros de personas sin mascarillas. Estas imágenes fueron obtenidas luego de aplicar la detección de rostros con mediapipe, para ser redimensionadas a cierto alto y ancho. 

Para acceder a este dataset puedes visitar mi repositorio en github: https://github.com/GabySol/OmesTutorials2021/tree/main/Mascarillas%20dataset

2) Entrenamiento

Una vez que hemos descargado el dataset, vamos a entrenar un modelo con Local Binary Patter Histogram Face Recognizer, que es uno de los métodos que habíamos visto en el tutorial de reconocimiento facial. De este modo vamos a experimentar si este método nos puede servir para ver si una persona lleva mascarilla o no, ya que este método se suele usar para el reconocimiento facial. Para ello construiremos el siguiente script llamado train.py.

import cv2
import os
import numpy as np

dataPath = ".../Dataset_faces"
dir_list = os.listdir(dataPath)
print("Lista archivos:", dir_list)

labels = []
facesData = []
label = 0

for name_dir in dir_list:
     dir_path = dataPath + "/" + name_dir
     
     for file_name in os.listdir(dir_path):
          image_path = dir_path + "/" + file_name
          print(image_path)
          image = cv2.imread(image_path, 0)
          #cv2.imshow("Image", image)
          #cv2.waitKey(10)

          facesData.append(image)
          labels.append(label)
     label += 1

print("Etiqueta 0: ", np.count_nonzero(np.array(labels) == 0))
print("Etiqueta 1: ", np.count_nonzero(np.array(labels) == 1))

# LBPH FaceRecognizer
face_mask = cv2.face.LBPHFaceRecognizer_create()

# Entrenamiento
print("Entrenando...")
face_mask.train(facesData, np.array(labels))

# Almacenar modelo
face_mask.write("face_mask_model.xml")
print("Modelo almacenado")

En la línea 5, debes cambiar el path por aquel en donde almacenaste la carpeta que contenga el dataset.

Al momento de ejecutar el script, verás algo similar a lo siguiente:

Figura 2: Visualización del modelo obtenido luego de entrenamiento.

En la figura 2 podemos apreciar que tenemos: la carpeta del dataset, el modelo obtenido luego de ejecutar el script train.py.

3) ¡A probar el modelo!

Figura 3: Ilustración del procedimiento que se sigue para probar las detecciones.

Por último, vamos a probar nuestro modelo entrenado, para ello tendremos que a las imágenes de entrada, aplicarles la detección de rostros con mediapipe (que es lo que se aplicó para obtener las imágenes del entrenamiento).

Luego tendremos que recortar la imagen del rostro, para aplicarle escala de grises y redimensionarla. De este modo estaremos aplicando los mismos procedimientos tanto a las imágenes que teníamos de entrenamiento, como con las que vamos a probar nuestro modelo. 

Para probar nuestro modelo crearemos un script llamado test_face_mask.py.

import cv2
import os
import mediapipe as mp

mp_face_detection = mp.solutions.face_detection

LABELS = ["Con_mascarilla", "Sin_mascarilla"]

# Leer el modelo
face_mask = cv2.face.LBPHFaceRecognizer_create()
face_mask.read("face_mask_model.xml")

cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)

with mp_face_detection.FaceDetection(
     min_detection_confidence=0.5) as face_detection:

     while True:
          ret, frame = cap.read()
          if ret == False: break
          frame = cv2.flip(frame, 1)

          height, width, _ = frame.shape
          frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
          results = face_detection.process(frame_rgb)

          if results.detections is not None:
               for detection in results.detections:
                    xmin = int(detection.location_data.relative_bounding_box.xmin * width)
                    ymin = int(detection.location_data.relative_bounding_box.ymin * height)
                    w = int(detection.location_data.relative_bounding_box.width * width)
                    h = int(detection.location_data.relative_bounding_box.height * height)
                    if xmin < 0 and ymin < 0:
                         continue
                    #cv2.rectangle(frame, (xmin, ymin), (xmin + w, ymin + h), (0, 255, 0), 5)

                    face_image = frame[ymin : ymin + h, xmin : xmin + w]
                    face_image = cv2.cvtColor(face_image, cv2.COLOR_BGR2GRAY)
                    face_image = cv2.resize(face_image, (72, 72), interpolation=cv2.INTER_CUBIC)
                    
                    result = face_mask.predict(face_image)
                    #cv2.putText(frame, "{}".format(result), (xmin, ymin - 5), 1, 1.3, (210, 124, 176), 1, cv2.LINE_AA)

                    if result[1] < 150:
                         color = (0, 255, 0) if LABELS[result[0]] == "Con_mascarilla" else (0, 0, 255)
                         cv2.putText(frame, "{}".format(LABELS[result[0]]), (xmin, ymin - 15), 2, 1, color, 1, cv2.LINE_AA)
                         cv2.rectangle(frame, (xmin, ymin), (xmin + w, ymin + h), color, 2)

          cv2.imshow("Frame", frame)
          k = cv2.waitKey(1)
          if k == 27:
               break

cap.release()
cv2.destroyAllWindows()

Recuerda que para una explicación más extendida sobre el código, puedes echarle un vistazo al videotutorial. 

Veamos algunas imágenes de las pruebas que hemos hecho para probar el detector de mascarillas:

Figura 4: Pruebas realizadas de la detección de mascarillas.

Si quieres ver algunas pruebas que he realizado de este programa puedes ver el siguiente video:

Y hemos llegado al final de este tutorial, espero que te haya parecido útil. Nos vemos en un siguiente, ¡chao, chao!. ?