Detector de sueño en vehículo

Detector de sueño en vehículo

Cierta vez cuando me trasladaba a una localidad cercana de la ciudad de Tacna (locumba) para dictar clases, digamos un tiempo de viaje de una hora y media aproximadamente, iba sentado en el asiento de copiloto del auto que brindaba el servicio de taxi colectivo, noté en el rostro del conductor  signos de cansancio que me llamaron la atención. En todo el trayecto en forma disimulada volteaba la mirada a ver si pestañeaba, tenía conocimiento de accidentes esporádicos suscitados en los últimos años, inclusive alguien conocido me contó que había sido víctima de un accidente algún tiempo atrás, al parecer por cansancio del conductor, habiendo tenido para su suerte solo golpes y fracturas, no llegando a un desenlace fatal, dejando entrever que poco después había logrado recuperarse.

Recuerdo también que hace tiempo por situaciones laborales realicé algunas capacitaciones básicas sobre seguridad vial. En tal caso, me propuse buscar información actualizada sobre  la prevención de accidentes de tránsito, que por cierto pueden tener muchas causas. Hasta mi entender los elementos que intervienen en la seguridad vial son tres, según matriz de Haddón: peatón, vehículo y vía, aunque también se considera al medio ambiente (lluvias, tormentas, temperatura, etc.) pero son considerados como elementos externos, al menos en nuestra localidad. Bien, cualquier determinación inusual o falla de alguno de estos tres elementos produce un accidente de tránsito. Según el Consejo Nacional de Seguridad Vial que publicó un artículo a inicios del 2020, en su estudio refiere que la causa de mortalidad que ha venido escalando desde 1998 a 2020 ha sido el de accidentes de tráfico o tránsito, la respuesta es simple el parque automotor ha ido aumentado en forma acelerada. En nuestro país el 90% de accidentes está relacionado por fallas humanas, que a su vez puede darse por múltiples causas. 

Como podemos apreciar el parque automotor viene creciendo y la probabilidad de la ocurrencia de accidente de tránsito también. A continuación presentamos un sistema de visión artificial para detectar la somnolencia del conductor captado por una cámara web capaz de activar un sensor o alarma para  prevenir accidentes de tránsito, seguro para los interesados en el tema podría serviles como el inicio de algún proyecto o como base a la creación de sistemas embebidos o similares tendientes a mitigar estos eventos que muchas veces son fatales.

Explicación y funcionamiento del sistema

Primero preparamos y configuramos la cámara web, para realizar el monitoreo de captación de rostros.

Figura 1. Monitoreo de rostros por cámara web

Al detectar un rostro o rostros, internamente se enmarca mediante un rectángulo las coordenadas inicial y final, seguidamente se determina los 68 puntos de referencia, pero el sistema solo dibuja los puntos de referencia de los ojos, en nuestro caso con líneas de color verde.

Figura 2. Detección de puntos de referencia de ojos

Ahora que capturamos los ojos, se calcula la relación aspecto de ojo (RAO) cuyo valor inferior a la constante 0.3 determinará que los ojos están cerrados. Cuando están cerrados por unos cuantos segundos se considera un estado de sueño del conductor, entonces se activará la alarma y se visualizará en el video un mensaje de alerta.

Figura 3. Activación de alarma al detectar un estado de sueño

Primeramente importamos las librerias necesarias. Para detectar los rostros usaremos  el metodo de la librería DLIB get_frontal_face_detector(), de igual forma para predecir los puntos de referencia faciales  usaremos el  shape_predictor_68_ face_landmarks.dat; Si algunas librerías no estuvieran disponibles en su ambiente de trabajo, solo deberá de invocar con pip install nombrepaquete o si estuviera en un ambiente de anaconda conda install nombrepaquete

from scipy.spatial import distance as dist
# si usamos un archivo de video desactivar comentario
#from imutils.video import FileVideoStream  
from imutils.video import VideoStream
from imutils import face_utils
import imutils
import time
import dlib
import cv2
import numpy as np

Estas librerías necesarias se cargan al ejecutarse el algoritmo y solamente mostrará la región de los ojos.

detector = dlib.get_frontal_face_detector()
PREDICTOR_PATH = "shape_predictor_68_face_landmarks.dat"
predictor = dlib.shape_predictor(PREDICTOR_PATH)
#Extracción de puntos referenciales de los ojos, almacenado en variable tipo TUPLA
(lStart, lEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eye"]  
(rStart, rEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eye"] 

 

Bien, ahora crearemos una función que retorne el valor de la relación de aspecto del ojo (RAO), esto permitirá saber si los ojos están cerrados o abiertos, ya que realiza el cálculo de distancias entre dos puntos A, B y C (distancia euclidiana). En nuestro caso, toma la distancia vertical y horizontal de los seis puntos referenciales (landmarks) de los ojos. El resultado es la suma de las 2 distancias verticales dividido entre la distancia horizontal multiplicada por 2.

def relacion_aspecto_ojo(ojo):    
     A = dist.euclidean(ojo[1], ojo[5])   
     B = dist.euclidean(ojo[2], ojo[4])   
     C = dist.euclidean(ojo[0], ojo[3]) 
     rao = (A + B) / (2.0 * C)   
     return rao 

 

Procedemos a la captura de video en tiempo real capturando y almacenando los cuadros de imágenes en la variable cap, congelamos cada segundo para reiniciar la captura de video.

cap = cv2.VideoCapture(0)
time.sleep(1.0)  

Una vez realizado esto, se confecciona tres bloques de código anidados que contendrán el proceso principal de ejecución del algoritmo detector de sueño.

Mientras la cámara esta activa (true) que lea los cuadros de imágenes  o frame, lo convierta a escala de grises  y se asigne los rostros detectados en la variable rects.

while True:
   ret, frame = cap.read()
   gray = cv2.cvtColor(frame,  cv2.COLOR_BGR2GRAY) 
   rects = detector(gray, 0)    

Este bucle for evalúa cada rostro contenido en la variable rects, invoca al metodo predictor y le pasa las variables rect y gray con el fin de predecir los hitos faciales solo de los ojos derecho e izquierdo, las coordenadas (x,y) que corresponde a cada hito se asignan a una variable shape que previamente son convertidos a forma de matriz con numpy. Ahora se calcula la rao para cada ojo invocando la función creada  relacion_aspecto_ojo(argumento). En este argumento se ingresa la variable en forma de matriz, luego se calcula el promedio para establecer el valor verdadero de rao , éste  finalmente servirá para determinar el estado de somnolencia.

for rect in rects:
    shape = predictor(gray, rect) 
    shape = face_utils.shape_to_np(shape)  
    leftEye = shape[lStart:lEnd]   
    rightEye = shape[rStart:rEnd]  
    leftRAO = relacion_aspecto_ojo(leftEye)     
    rightRAO = relacion_aspecto_ojo(rightEye)
    rao = (leftRAO + rightRAO) / 2.0
    leftEyeHull = cv2.convexHull(leftEye)
    rightEyeHull = cv2.convexHull(rightEye)
    cv2.drawContours(frame, [leftEyeHull],-1, (0, 255, 0), 1)
    cv2.drawContours(frame, [rightEyeHull],-1, (0, 255, 0), 1)

En este bloque condicionamos, si rao es menor que el valor establecido como constante EYE_AR_THRESH  = 0.3, Si es verdad que incremente contador en 1,  hasta que contador sea mayor al valor consecutivo de frames EYE_AR_CONSEC_FRAMES = 48  se asigna este valor, teniendo en cuenta que las web cam en 2 segundos por lo menos recorren 50 frames. Al superar el valor de 48, valga la redundancia que muestre un mensaje de alerta. Caso contrario, si rao es mayor que la constante 0.3, que reinicie el conteo desde cero.

if rao < EYE_AR_THRESH:
    CONTADOR = CONTADOR + 1         
    if CONTADOR >= EYE_AR_CONSEC_FRAMES:  
        cv2.putText(frame, "ESTADO DE SUEÑO..ALERTA!!", (10,30), 
            cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,0,255), 2)        
else:
    CONTADOR = 0

Bien, espero haya sido de su interés, decirles también que es posible mejorarlo, una idea podría ser empleando una interfaz de Arduino para monitorear otros sensores.  No olviden dejar sus comentarios y compartirlo.

Deja una respuesta