zoukankan      html  css  js  c++  java
  • dlib库检测人脸使用方法与简单的疲劳检测应用

    简介:

        dlib库是一个很经典的用于图像处理的开源库,shape_predictor_68_face_landmarks.dat是一个用于人脸68个关键点检测的dat模型库,使用这个模型库可以很方便地进行人脸检测,并进行简单的应用。

        简单实现一下疲劳检测功能,对视频中每帧图片检测眼睛长/宽的值是否大于阈值,连续超过50次则认为已经“睡着”,阈值的获取方式是:先采集30次数据,取其平均值作为默认的值。为了数据的准确,采集数据时应该平视摄像头。

        (不过仅通过检测眼睛是否闭合来判断是否疲劳存在很多误差,也因为受各方面干扰比较难处理,最准确的大概是检测生理信息吧,然而检测生理信息又很不实用_(:з)∠)_。。。)

    人脸68个特征点分布图:

    人脸68个特征点模型库shape_predictor_68_face_landmarks.dat下载地址:

    https://pan.baidu.com/s/133Rk9f7iWAF2WApl-a69-A   密码:sl19

    python代码实现:

    from scipy.spatial import distance as dis
    from imutils.video import VideoStream
    from imutils import face_utils
    from threading import Thread
    import numpy as np
    import pyglet
    import argparse
    import imutils
    import time
    import dlib
    import cv2
    
    #计算嘴的长宽比,euclidean(u, v, w=None)用于计算两点的欧几里得距离
    def mouthRatio(mouth):
        left=dis.euclidean(mouth[2],mouth[10])
        mid=dis.euclidean(mouth[3],mouth[9])
        right=dis.euclidean(mouth[4],mouth[8])
        horizontal=dis.euclidean(mouth[0],mouth[6])
        return 10.0*horizontal/(3.0*left+4.0*mid+3.0*right)
    
    #计算眼睛的长宽比
    def eyesRatio(eye):
        left = dis.euclidean(eye[1], eye[5])
        right = dis.euclidean(eye[2], eye[4])
        horizontal = dis.euclidean(eye[0], eye[3])
        return 2.0*horizontal/(left+right)
    
    #创建一个解析对象,向该对象中添加关注的命令行参数和选项,然后解析
    ap = argparse.ArgumentParser()
    ap.add_argument("-w", "--webcam", type=int, default=0)
    args = vars(ap.parse_args())
    
    #眼睛长宽比的阈值,如果超过这个值就代表眼睛长/宽大于采集到的平均值,默认已经"闭眼"
    eyesRatioLimit=0
    #数据采集的计数,采集30次然后取平均值
    collectCount=0
    #用于数据采集的求和
    collectSum=0
    #是否开始检测
    startCheck=False
    
    #统计"闭眼"的次数
    eyesCloseCount=0
    
    #初始化dlib
    detector=dlib.get_frontal_face_detector()
    predictor=dlib.shape_predictor("68_face_landmarks.dat")
    
    #获取面部各器官的索引
    #左右眼
    (left_Start,left_End)=face_utils.FACIAL_LANDMARKS_IDXS["left_eye"]
    (right_Start,right_End)=face_utils.FACIAL_LANDMARKS_IDXS["right_eye"]
    #
    (leftMouth,rightMouth)=face_utils.FACIAL_LANDMARKS_IDXS['mouth']
    #下巴
    (leftJaw,rightJaw)=face_utils.FACIAL_LANDMARKS_IDXS['jaw']
    #鼻子
    (leftNose,rightNose)=face_utils.FACIAL_LANDMARKS_IDXS['nose']
    #左右眉毛
    (left_leftEyebrow,left_rightEyebrow)=face_utils.FACIAL_LANDMARKS_IDXS['left_eyebrow']
    (right_leftEyebrow,right_rightEyebrow)=face_utils.FACIAL_LANDMARKS_IDXS['right_eyebrow']
    
    #开启视频线程,延迟2秒钟
    vsThread=VideoStream(src=args["webcam"]).start()
    time.sleep(2.0)
    
    #循环检测
    while True:
        #对每一帧进行处理,设置宽度并转化为灰度图
        frame = vsThread.read()
        frame = imutils.resize(frame, width=720)
        img = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    
        #检测灰度图中的脸
        faces = detector(img, 0)
        for k in faces:
            #确定面部区域的面部特征点,将特征点坐标转换为numpy数组
            shape = predictor(img, k)
            shape = face_utils.shape_to_np(shape)
    
            #左右眼
            leftEye = shape[left_Start:left_End]
            rightEye = shape[right_Start:right_End]
            leftEyesVal = eyesRatio(leftEye)
            rightEyesVal = eyesRatio(rightEye)
            #凸壳
            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)
            #取两只眼长宽比的的平均值作为每一帧的计算结果
            eyeRatioVal = (leftEyesVal + rightEyesVal) / 2.0
    
            #
            mouth=shape[leftMouth:rightMouth]
            mouthHull=cv2.convexHull(mouth)
            cv2.drawContours(frame, [mouthHull], -1, (0, 255, 0), 1)
    
            #鼻子
            nose=shape[leftNose:rightNose]
            noseHull=cv2.convexHull(nose)
            cv2.drawContours(frame, [noseHull], -1, (0, 255, 0), 1)
    
            #下巴
            jaw=shape[leftJaw:rightJaw]
            jawHull=cv2.convexHull(jaw)
            cv2.drawContours(frame, [jawHull], -1, (0, 255, 0), 1)
    
            #左眉毛
            leftEyebrow=shape[left_leftEyebrow:left_rightEyebrow]
            leftEyebrowHull=cv2.convexHull(leftEyebrow)
            cv2.drawContours(frame, [leftEyebrowHull], -1, (0, 255, 0), 1)
    
            #右眉毛
            rightEyebrow=shape[right_leftEyebrow:right_rightEyebrow]
            rightEyebrowHull=cv2.convexHull(rightEyebrow)
            cv2.drawContours(frame, [rightEyebrowHull], -1, (0, 255, 0), 1)
    
            if collectCount<30:
                collectCount+=1
                collectSum+=eyeRatioVal
                cv2.putText(frame, "DATA COLLECTING", (300, 30),cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)
                startCheck=False
            else:
                if not startCheck:
                    eyesRatioLimit=collectSum/(1.0*30)
                    print('眼睛长宽比均值',eyesRatioLimit)
                startCheck=True
    
            if startCheck:
                #如果眼睛长宽比大于之前检测到的阈值,则计数,闭眼次数超过50次则认为已经"睡着"
                if eyeRatioVal > eyesRatioLimit:
                    eyesCloseCount += 1
                    if eyesCloseCount >= 50:
                        cv2.putText(frame, "SLEEP!!!", (580, 30),cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)
                else:  
                    eyesCloseCount = 0
                print('眼睛实时长宽比:{:.2f} '.format(eyeRatioVal))
                #眼睛长宽比
                cv2.putText(frame, "EYES_RATIO: {:.2f}".format(eyeRatioVal), (20, 30),cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 160, 0), 2)
                #闭眼次数
                cv2.putText(frame,"EYES_COLSE: {}".format(eyesCloseCount),(320,30),cv2.FONT_HERSHEY_SIMPLEX,0.6,(0,160,0),2)
    
                #通过检测嘴的长宽比检测有没有打哈欠,后来觉得没什么卵用
                #cv2.putText(frame,"MOUTH_RATIO: {:.2f}".format(mouthRatio(mouth)),(30, 30),cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
    
        cv2.imshow("Frame", frame)
        key = cv2.waitKey(1) & 0xFF
        #停止
        if key == ord("S"):  break
    
    cv2.destroyAllWindows()
    vsThread.stop()

    检测结果:

  • 相关阅读:
    k-d tree
    K近邻算法-KNN
    ORB特征提取与匹配
    ZeroMQ一个更小、更快、更简单的智能传输层协议
    ROS导航之参数配置和自适应蒙特卡罗定位
    cmake实战第二篇:让我们的代码更像个工程
    gcc/g++实战之动态链接库与静态链接库编写
    gcc/g++ 实战之编译的四个过程
    通过 LPeg 介绍解析表达式语法(Parsing Expression Grammars)
    Forth 语言概要
  • 原文地址:https://www.cnblogs.com/nibolyoung/p/10882612.html
Copyright © 2011-2022 走看看