文章目录
疲劳检测
使用OpenCV实现疲劳检测 通常依赖于面部特征分析,特别是眼睛的状态(如眼睛开合程度)以及闭眼的时间。
一、面部识别
通过Dlib库构造人脸检测器 ,用于检测人脸,然后通过shape_predictor()加载模型用于定位检测到的人脸的关键点:
python
detector = dlib.get_frontal_face_detector() # 构造人脸检测器
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat") # 定位关键点模型
cap = cv2.VideoCapture(0)
二、主循环
1. 计算眼睛纵横比
通过euclidean_distances()函数计算两点间的距离:
python
def eye_aspect_ratio(eye):
"""-----计算眼睛纵横比-----"""
A = euclidean_distances(eye[1].reshape(1,2),eye[5].reshape(1,2))
B = euclidean_distances(eye[2].reshape(1,2),eye[4].reshape(1,2))
C = euclidean_distances(eye[0].reshape(1,2),eye[3].reshape(1,2))
ear = ((A+B)/2.0) / C # 纵横比
return ear
python
COUNTER = 0 # 闭眼持续帧数统计
while True:
ret,frame = cap.read()
faces = detector(frame,0)
for face in faces:
shape = predictor(frame,face)# 获取关键点
# 将关键点转换为坐标(x,y)的形式
shape = np.array([[p.x,p.y] for p in shape.parts()])
rightEye = shape[36:42] # 右眼,关键点索引从36到41
leftEye = shape[42:48] # 左眼,关键点索引从42到47
rightEAR = eye_aspect_ratio(rightEye) # 计算右眼纵横比
leftEAR = eye_aspect_ratio(leftEye) # 计算左眼纵横比
ear = (leftEAR + rightEAR) / 2.0 # 均值处理
2. 判断疲劳状态
当宽高比小于0.3,且连续50帧保持这个状态,则认定他处于疲劳状态:
python
def cv2ADDChineseText(img,text,position,textColor=(0,255,0),textSize=30):
"""像图片中添加中文"""
if (isinstance(img,np.ndarray)):
img = Image.fromarray(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img)
fontStyle = ImageFont.truetype("simfang.ttf",textSize,encoding="Utf-8")
draw.text(position,text,textColor,font=fontStyle)
return cv2.cvtColor(np.asarray(img),cv2.COLOR_BGR2RGB)
if ear < 0.3: # 小于0.3认为闭眼,也可能是眨眼
COUNTER += 1
if COUNTER >= 50:
frame = cv2ADDChineseText(frame,"!!!危险!!!",(250,250))
# 宽高比 > 0.3,则计数器清零,解除疲劳标志
else:
COUNTER = 0 # 闭眼次数清零
3. 绘制双眼凸包
将双眼绘制出来:
python
def drawEye(eye): # 绘制眼眶凸包
eyeHull = cv2.convexHull(eye)
cv2.drawContours(frame,[eyeHull],-1,(0,255,0),1)
drawEye(leftEye) # 绘制左眼凸包
drawEye(rightEye) # 绘制右眼凸包
4. 显示眼睛闭合程度值
python
info = "EAR:{:.2f}".format(ear[0][0])
frame = cv2ADDChineseText(frame,info,(0,30)) # 显示眼睛闭合程度值
5. 显示图像
python
cv2.imshow("Frame",frame)
if cv2.waitKey(1) == 27:
break
三、释放资源
python
cv2.destroyAllWindows()
cap.release()
四、完整代码展示
python
import numpy as np
import dlib
import cv2
from sklearn.metrics.pairwise import euclidean_distances
from PIL import Image,ImageDraw,ImageFont
def eye_aspect_ratio(eye):
"""-----计算眼睛纵横比-----"""
A = euclidean_distances(eye[1].reshape(1,2),eye[5].reshape(1,2))
B = euclidean_distances(eye[2].reshape(1,2),eye[4].reshape(1,2))
C = euclidean_distances(eye[0].reshape(1,2),eye[3].reshape(1,2))
ear = ((A+B)/2.0) / C # 纵横比
return ear
def cv2ADDChineseText(img,text,position,textColor=(0,255,0),textSize=30):
"""像图片中添加中文"""
if (isinstance(img,np.ndarray)):
img = Image.fromarray(cv2.cvtColor(img,cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img)
fontStyle = ImageFont.truetype("simfang.ttf",textSize,encoding="Utf-8")
draw.text(position,text,textColor,font=fontStyle)
return cv2.cvtColor(np.asarray(img),cv2.COLOR_BGR2RGB)
def drawEye(eye): # 绘制眼眶凸包
eyeHull = cv2.convexHull(eye)
cv2.drawContours(frame,[eyeHull],-1,(0,255,0),1)
COUNTER = 0 # 闭眼持续帧数统计
detector = dlib.get_frontal_face_detector() # 构造人脸检测器
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat") # 定位关键点模型
cap = cv2.VideoCapture(0)
while True:
ret,frame = cap.read()
faces = detector(frame,0)
for face in faces:
shape = predictor(frame,face)# 获取关键点
# 将关键点转换为坐标(x,y)的形式
shape = np.array([[p.x,p.y] for p in shape.parts()])
rightEye = shape[36:42] # 右眼,关键点索引从36到41
leftEye = shape[42:48] # 左眼,关键点索引从42到47
rightEAR = eye_aspect_ratio(rightEye) # 计算右眼纵横比
leftEAR = eye_aspect_ratio(leftEye) # 计算左眼纵横比
ear = (leftEAR + rightEAR) / 2.0 # 均值处理
if ear < 0.3: # 小于0.3认为闭眼,也可能是眨眼
COUNTER += 1
if COUNTER >= 50:
frame = cv2ADDChineseText(frame,"!!!危险!!!",(250,250))
# 宽高比 > 0.3,则计数器清零,解除疲劳标志
else:
COUNTER = 0 # 闭眼次数清零
drawEye(leftEye) # 绘制左眼凸包
drawEye(rightEye) # 绘制右眼凸包
info = "EAR:{:.2f}".format(ear[0][0])
frame = cv2ADDChineseText(frame,info,(0,30)) # 显示眼睛闭合程度值
cv2.imshow("Frame",frame)
if cv2.waitKey(1) == 27:
break
cv2.destroyAllWindows()
cap.release()
总结
本篇介绍了,如何通过人脸部眼睛的变化来简单的进行疲劳检测。