史上很强副驾驶——开车打瞌睡?Python叫醒你

本文转载自公众号“读芯术”(ID:AI_Discovery)

道路千万条,安全第一条!疲劳驾驶可谓交通事故几大罪魁祸首之一,根据美国一项研究显示,司机睡眠不足4小时,交通事故肇事几率等同于醉驾。

史上很强副驾驶——开车打瞌睡?Python叫醒你

为了减少疲劳驾驶现象,驾驶员疲劳检测应运而生。这是一项安全技术,可以预防驾驶员在驾驶过程中因疲劳而导致的安全事故。

该Python中级项目的目的是建立一个驾驶员疲劳检测系统,用于检测人眼闭合时长。当检测到驾驶员疲劳驾驶时,该系统将发出警告。

驾驶员疲劳检测系统

本Python项目将使用OpenCV收集来自网络摄像头的图像,将其输入到“深度学习”模型中,由该模型对人眼按“睁开”或“闭合”进行分类。该Python项目将采取的方法如下:

第1步-从相机中获取图像作为输入。

第2步-检测图像中的脸部并创建一个感兴趣区(ROI)。

第3步-从ROI中检测人眼并将其输入分类器。

第4步-分类器将按睁开或闭合对人眼进行分类。

第5步-计算分数判断驾驶员是否处于疲劳状态。

在学习先决条件、数据集和模型结构前,如果您是新手,建议您参考Python MasterSheet先了解Python编程语言所需的一切概念。

先决条件

该Python项目需要一个网络摄像头,用于捕获图像。您需要在系统上安装Python(建议使用3.6版),然后使用pip安装所需的软件包。

  • OpenCV – 使用pip安装opencv-python(面部和眼部检测)。
  • TensorFlow – 使用pip安装tensorflow(keras使用TensorFlow作为后端)。
  • Keras – 使用pip安装keras(建立分类模型)。
  • Pygame – 使用pip安装pygame(播放警告提示音)。

数据集

需要创建用于此模型的数据集。为创建数据集,我们编写了一个脚本来捕获摄像机中的人眼图像并将其存储在本地磁盘中,将人眼图像分为“睁开”或“闭合”状态两类,通过删除构建模型不需要的图像来手动清理数据。

数据包括大约7000张在不同光照条件下的人眼图像。在数据集上训练模型后,我们附加了最终权重和模型结构文件“models /cnnCat2.h5”。现在,你可以使用此模型按人眼睁开还是闭合对图像进行分类。

模型结构

我们使用的模型是Keras通过卷积神经网络(CNN)构建的。卷积神经网络是一种特殊类型的深度神经网络,在图像分类方面表现非常出色。

CNN基本上由一个输入层、一个输出层和一个可以包含多个层的隐藏层组成。通过过滤器在这些层上执行卷积运算,该滤波器在层和过滤器上执行2D矩阵乘法。

CNN模型结构包括以下几层:

  • 卷积层;32个节点,内核大小为3
  • 卷积层;32个节点,内核大小为3
  • 卷积层;64个节点,内核大小为3
  • 完全连接层;128个节点

最后一层也是具有2个节点的完全连接层。在所有层中,除了使用Softmax的输出层外,均使用Relu激活函数。

Python项目进行驾驶员疲劳检测的步骤

从zip下载python项目源代码并提取系统中的文件:Python项目Zip文件。

zip的目录为:

1.“haar级联文件/ cascade files”文件夹包含从图像中检测对象所需的xml文件。在本案例中,需要检测人脸和人眼。

2.模型文件夹包含我们的模型文件“cnnCat2.h5”,该文件是在卷积神经网络上进行训练的。

3.我们有一段音频“alarm.wav”,用于在驾驶员昏昏欲睡时播放。

4.“Model.py”文件包含一个程序,通过该程序对数据集进行训练来构建分类模型。您可以从此文件中了解卷积神经网络的执行情况。

5.“Drowsinessdetection.py”是本项目的主要文件。开始检测时,我们必须要运行此文件。

接下来。让我们逐步了解该算法是怎么工作的。

第1步-从相机中获取图像作为输入

使用网络摄像头获取图像作为输入。为了访问网络摄像头,我们进行了无限循环以捕获每一帧。我们使用OpenCV提供的方法cv2.VideoCapture(0)来访问摄像机并设置捕获对象(cap)。cap.read()将读取每一帧,并将图像存储在帧变量中。

第2步-检测图像中的脸部并创建一个感兴趣区(ROI)

为了检测图像中的人脸,首先需要将图像模式转换为灰度,因为用于对象检测的OpenCV算法需要输入灰度图像。因此无需颜色信息即可检测物体。

我们将使用haar级联分类器来检测人脸。通过face =cv2.CascadeClassifier('抵达haar级联xml文件的路径')设置分类器,然后使用faces =face.detectMultiScale(gray)执行检测。进而产生带有x、y坐标以及高度(对象边界框的宽度)的检测数组。现在我们可以迭代这些脸并为每张人脸绘制边界框。

for (x,y,w,h)in faces:cv2.rectangle(frame,(x,y), (x+w, y+h), (100,100,100), 1 ) 

第3步-从ROI中检测人眼并将其输入分类器

检测人脸的过程也同样适用于检测人眼。

首先,我们分别在leye和reye中为眼睛设置级联分类器,然后使用left_eye =leye.detectMultiScale(gray)来检测人眼。现在,我们只需要从完整图像中提取出人眼数据即可。这可以通过提取眼睛的边界框来实现,然后可以使用此代码从帧中提取眼睛图像。

l_eye =frame[ y : y+h, x : x+w ] 

l_eye仅包含左眼的图像数据。这将被输入到CNN分类器中,该分类器将预测眼睛是处于睁开还是闭合状态。同样,我们将右眼的数据提取到r_eye中。

第4步-分类器将按睁开或闭合对眼睛进行分类。

使用CNN分类器预测眼睛状态。因为模型需要从正确的维度开始,因此将图像输入模型之前需要执行一些操作。

首先,使用r_eye = cv2.cvtColor(r_eye,cv2.COLOR_BGR2GRAY)将彩色图像转换为灰度图像。

然后,由于模型是在24 * 24像素的图像上测试,需要将图像也调整为24 * 24像素:

cv2.resize(r_eye,(24,24))。我们将数据标准化以实现更好的收敛性:r_eye = r_eye/ 255(所有值都在0-1之间)。扩展维度以输入到分类器中。使用model = load_model(‘models / cnnCat2.h5’)来加载模型。

现在我们用模型预测每只眼睛的状态:lpred =model.predict_classes(l_eye)。如果lpred [0]= 1,则说明眼睛是睁开的;如果lpred [0]= 0,则说明眼睛是闭合的。

第5步-计算分数判断驾驶员是否处于疲劳状态

分数基本上是一个值,用于确定驾驶员闭眼的时长。因此,如果双眼都闭合,得分将不断增加,而双眼睁开时,得分将降低。使用cv2.putText()函数在屏幕上绘制结果,该函数将显示驾驶员的实时状态。

cv2.putText(frame,“Open”, (10, height-20), font, 1, (255,255,255), 1, cv2.LINE_AA ) 

阈值由以下方法确定:例如,如果得分大于15意味着该驾驶员闭眼时间较长,则阈值为15。此时,我们将使用sound.play()发出警报。

主要文件的源代码如下:

import cv2 
import os 
fromkeras.models 
importload_model 
import numpy asnp 
from pygameimport mixer 
import time 
mixer.init() 
sound =mixer.Sound('alarm.wav') 
face =cv2.CascadeClassifier('haar cascade files\haarcascade_frontalface_alt.xml') 
leye =cv2.CascadeClassifier('haar cascade files\haarcascade_lefteye_2splits.xml') 
reye =cv2.CascadeClassifier('haar cascade files\haarcascade_righteye_2splits.xml') 
lbl=['Close','Open'] 
model =load_model('models/cnncat2.h5') 
path =os.getcwd() 
cap = cv2.VideoCapture(0) 
font =cv2.FONT_HERSHEY_COMPLEX_SMALL 
count=0 
score=0 
thicc=2 
rpred=[99] 
lpred=[99] 
while(True): 
    ret, frame = cap.read() 
    height,width = frame.shape[:2] 
    gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) 
    faces =face.detectMultiScale(gray,minNeighbors=5,scaleFactor=1.1,minSize=(25,25)) 
    left_eye = leye.detectMultiScale(gray) 
    right_eye = reye.detectMultiScale(gray) 
    cv2.rectangle(frame, (0,height-50) ,(200,height) , (0,0,0) , thickness=cv2.FILLED ) 
    for (x,y,w,h) in faces: 
cv2.rectangle(frame,(x,y) , (x+w,y+h) , (100,100,100) , 1 ) 
    for (x,y,w,h) in right_eye: 
        r_eye=frame[y:y+h,x:x+w] 
        count=count+1 
        r_eye =cv2.cvtColor(r_eye,cv2.COLOR_BGR2GRAY) 
        r_eye = cv2.resize(r_eye,(24,24)) 
        r_eye= r_eye/255 
        r_eye= r_eye.reshape(24,24,-1) 
        r_eye = np.expand_dims(r_eye,axis=0) 
        rpred = model.predict_classes(r_eye) 
        if(rpred[0]==1): 
            lbl='Open' 
        if(rpred[0]==0): 
            lbl='Closed' 
        break 
    for (x,y,w,h) in left_eye: 
        l_eye=frame[y:y+h,x:x+w] 
        count=count+1 
        l_eye = cv2.cvtColor(l_eye,cv2.COLOR_BGR2GRAY) 
        l_eye = cv2.resize(l_eye,(24,24)) 
        l_eye= l_eye/255 
        l_eye=l_eye.reshape(24,24,-1) 
        l_eye = np.expand_dims(l_eye,axis=0) 
        lpred = model.predict_classes(l_eye) 
        if(lpred[0]==1): 
            lbl='Open' 
        if(lpred[0]==0): 
            lbl='Closed' 
        break 
    if(rpred[0]==0 and lpred[0]==0): 
        score=score+1 
       cv2.putText(frame,"Closed",(10,height-20), font,1,(255,255,255),1,cv2.LINE_AA) 
    # if(rpred[0]==1 or lpred[0]==1): 
    else: 
        score=score-1 
       cv2.putText(frame,"Open",(10,height-20), font,1,(255,255,255),1,cv2.LINE_AA) 
    if(score<0): 
        score=0 
   cv2.putText(frame,'Score:'+str(score),(100,height-20), font,1,(255,255,255),1,cv2.LINE_AA) 
    if(score>15): 
        #person is feeling sleepy so we beepthe alarm 
       cv2.imwrite(os.path.join(path,'image.jpg'),frame) 
        try: 
            sound.play() 
        except: # isplaying = False 
            pass 
        if(thicc<16): 
            thicc= thicc+2 
        else: 
            thicc=thicc-2 
            if(thicc<2): 
                thicc=2 
       cv2.rectangle(frame,(0,0),(width,height),(0,0,255),thicc) 
    cv2.imshow('frame',frame) 
    if cv2.waitKey(1) & 0xFF == ord('q'): 
        break 
cap.release() 
cv2.destroyAllWindows() 

Python项目示例

开始项目,查看项目运作情况。要启动该项目,需要打开命令提示符,转到主文件“ drowsinessdetection.py”所在的目录。使用如下命令运行脚本。

python“drowsiness detection.py” 

可能需要几秒钟来打开网络摄像头并开始检测。

示例截图:

史上很强副驾驶——开车打瞌睡?Python叫醒你

输出截图:

1.闭眼检测

史上很强副驾驶——开车打瞌睡?Python叫醒你

2. 睁眼检测

史上很强副驾驶——开车打瞌睡?Python叫醒你

3. 疲劳警告

史上很强副驾驶——开车打瞌睡?Python叫醒你

此Python项目构建了一个驾驶员疲劳警报系统,你可以通过多种方式实施该系统。我们通过Haar级联分类器,使用OpenCV检测人脸和人眼,然后根据CNN模型预测状态。