dlib庫檢測人臉使用方法與簡單的疲勞檢測應用

簡介:python

    dlib庫是一個很經典的用於圖像處理的開源庫,shape_predictor_68_face_landmarks.dat是一個用於人臉68個關鍵點檢測的dat模型庫,使用這個模型庫能夠很方便地進行人臉檢測,並進行簡單的應用。web

    簡單實現一下疲勞檢測功能,對視頻中每幀圖片檢測眼睛長/寬的值是否大於閾值,連續超過50次則認爲已經「睡着」,閾值的獲取方式是:先採集30次數據,取其平均值做爲默認的值。爲了數據的準確,採集數據時應該平視攝像頭。數組

    (不過僅經過檢測眼睛是否閉合來判斷是否疲勞存在不少偏差,也由於受各方面干擾比較難處理,最準確的大概是檢測生理信息吧,然而檢測生理信息又很不實用_(:з)∠)_。。。)ide

人臉68個特徵點分佈圖:idea

 

 

人臉68個特徵點模型庫shape_predictor_68_face_landmarks.dat下載地址:spa

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()

檢測結果:code

相關文章
相關標籤/搜索