赞
踩
参考博客:Dlib模型之驾驶员疲劳检测二(打哈欠)
因为人在疲倦时大概会产生两种状态: 眨眼:正常人的眼睛每分钟大约要眨动10-15次,每次眨眼大概0.2-0.4秒,如果疲倦时眨眼次数会增多,速度也会变慢。打哈欠:此时嘴会长大而且会保持一定的状态。因此检测人是否疲劳可以从眼睛的开合度,眨眼频率,以及嘴巴张合程度来判断一个人是否疲劳。
第一步:使用dlib.get_frontal_face_detector() 获得脸部位置检测器 第二步:使用dlib.shape_predictor获得脸部特征位置检测器 第三步:分别获取左右眼面部标志的索引 第四步:打开cv2 本地摄像头 第五步:从视频流进行循环,读取图片,并对图片做维度扩大,并进灰度化 第六步:使用detector(gray, 0) 进行脸部位置检测 第七步:循环脸部位置信息,使用predictor(gray, rect)获得脸部特征位置的信息 第八步:将脸部特征信息转换为数组array的格式 第九步:提取左眼和右眼坐标 第十步:构造函数计算左右眼的EAR值,使用平均值作为最终的EAR 第十一步:使用cv2.convexHull获得凸包位置,使用drawContours画出轮廓位置进行画图操作 第十二步:进行画图操作,用矩形框标注人脸 第十三步:分别计算左眼和右眼的评分求平均作为最终的评分,如果小于阈值,则加1,如果连续3次都小于阈值,则表示进行了一次眨眼活动 第十四步:进行画图操作,68个特征点标识 第十五步:进行画图操作,同时使用cv2.putText将眨眼次数进行显示 第十六步:统计总眨眼次数大于50次屏幕显示睡着。 原文链接:https://blog.csdn.net/cungudafa/article/details/103477960
常用来测量欧氏距离的函数方法有两个:np.linalg.norm()和dist.euclidean(),所以可以大概测量一下这两个运算速度的快慢:
from scipy.spatial import distance as dist
import numpy as np
import time
points = [[1, 3], [8, 7]]
points = [np.array(val) for val in points]
tic = time.clock()
for i in range(50000):
temp1 = (np.linalg.norm(points[0] - points[1]))
toc = time.clock()
print("np.linalg.norm: %.3fs" % (toc - tic))
tic = time.clock()
for i in range(50000):
temp2 = (dist.euclidean(points[0], points[1]))
toc = time.clock()
print("dist.euclidean: %.3fs " % (toc - tic))
np.linalg.norm: 0.284s
dist.euclidean: 0.596s
所以看出np.linalg.norm()函数的运算速度要比dist.euclidean()快一点。所以用前者来测量眼睛和嘴巴的欧氏距离。
import numpy as np from imutils import face_utils #imutils是在OpenCV基础之上的一个封装 import imutils import dlib import cv2 #定义眼睛阈值和嘴阈值算式函数 def eye_detect_1(eye): #np.linalg.norm计算时间要比dist.euclidean要快 因此使用Numpy的算法 A = np.linalg.norm(eye[1] - eye[5]) B = np.linalg.norm(eye[2] - eye[4]) C = np.linalg.norm(eye[0] - eye[3]) ear = (A + B) /(2.0 * C) return ear def mouth_detect_1(mouth): A = np.linalg.norm(mouth[2] - mouth[10]) # 51, 59 B = np.linalg.norm(mouth[4] - mouth[8]) # 53, 57 C = np.linalg.norm(mouth[0] - mouth[6]) # 49, 55 mar = (A + B) / (2.0 * C) return mar #常数:眼睛长宽比/闪烁阈值 eye_Aspect_rato = 0.2 eye_Flicker_threshold = 3 #常数:嘴长宽比/闪烁阈值 mouth_Aspect_rato = 0.5 mouth_Flicker_threshold = 3 #计数常数 eCOUNTER = 0 eTOTAL = 0 mCOUNTER = 0 mTOTAL = 0 #脸部位置检测器 #返回值就是一个矩形 detect = dlib.get_frontal_face_detector() #脸部特征位置检测器 predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat') #获得左右眼和嘴的标志索引 (lstart,lend) = face_utils.FACIAL_LANDMARKS_IDXS['left_eye'] (rstart,rend) = face_utils.FACIAL_LANDMARKS_IDXS['right_eye'] (mstart,mend) = face_utils.FACIAL_LANDMARKS_IDXS['mouth'] cap = cv2.VideoCapture(0) while True: ret,frame = cap.read() frame = imutils.resize(frame)#, width=720) gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY) #返回值为脸部区域的矩形框,数组形式 rects = detect(gray,0) #print(rects) # #循环脸部信息 for rect in rects: #检测器检测特征点 shape = predictor(gray,rect) #将特征点转化为数组组,返回值是68个特征点坐标 shape = face_utils.shape_to_np(shape) #print(shape) #获取左右眼睛和嘴的坐标 lefteye = shape[lstart:lend] righteye = shape[rstart:rend] mouth = shape[mstart:mend] #计算左右眼的ear值,嘴的mar值。 leftear = eye_detect_1(lefteye) rightear = eye_detect_1(righteye) ear = (leftear + rightear) / 2.0 mar = mouth_detect_1(mouth) #cv2.convexHull为获取图像凸包位置的函数 lefteyehull = cv2.convexHull(lefteye) righteyehull = cv2.convexHull(righteye) mouthhull = cv2.convexHull(mouth) #print(lefteyehull) #cv2.drawContours是轮廓绘制函数 #第一个参数是指明在哪幅图像上绘制轮廓;image为三通道才能显示轮廓 #第二个参数是轮廓本身,在Python中是一个list; #第三个参数指定绘制轮廓list中的哪条轮廓,如果是-1,则绘制其中的所有轮廓。 cv2.drawContours(frame,[lefteyehull],-1,(0,255,0),1) cv2.drawContours(frame,[righteyehull],-1,(0,255,0),1) cv2.drawContours(frame,[mouthhull],-1,(0,255,0),1) # 进行画图操作,用矩形框标注人脸 # left = rect.left() # top = rect.top() # right = rect.right() # bottom = rect.bottom() # cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 3) #循环,满足条件的眨眼次数+1 if ear < eye_Aspect_rato: #阈值0.2 eCOUNTER += 1 #连续3帧都满足条件的计为一次闭眼 else: if eCOUNTER >= eye_Flicker_threshold: #阈值3 eTOTAL += 1 eCOUNTER = 0 cv2.putText(frame,'Blinks:{}'.format(eTOTAL),(10,30),cv2.FONT_HERSHEY_SIMPLEX,0.7,(0,0,255),2) cv2.putText(frame,'eCounter:{}'.format(eCOUNTER), (150, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) cv2.putText(frame,'Ear:{:.2f}'.format(ear), (300, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) if mar > mouth_Aspect_rato: #阈值0.5 mCOUNTER += 1 else: if mCOUNTER >= mouth_Flicker_threshold: #阈值3 mTOTAL += 1 mCOUNTER = 0 cv2.putText(frame, 'Yawning:{}'.format(mTOTAL), (10,60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) cv2.putText(frame, 'mCounter:{}'.format(mCOUNTER), (300,60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) cv2.putText(frame, 'Mar:{:.2f}'.format(mar), (450, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) #进行画图操作,68个特征点标识 #for (x,y) in shape: #shape为68特征点的坐标 #cv2.circle(frame,(x,y),1,(0,0,255),-1) #假设1秒为60帧,则1帧为1/60秒,一个TOTAL为3帧为1/20秒 if eTOTAL >= 12 or mTOTAL >= 6: cv2.putText(frame,"SLEEP!SLEEP!!",(360,360),cv2.FONT_HERSHEY_SIMPLEX,1,(84,255,200),2) cv2.imshow('pilao',frame) if cv2.waitKey(1) & 0xFF == ord('q'): break #也许是因为我用的opencv-python是4.1.0 所以加上最后这两行总是报错,我删掉后就可以运行了 #cap.release() #cv2.destroyAllWindows()
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。