目录
本代码将实现通过分析人脸的关键点进行疲劳检测,若持续闭眼则提示危险;考虑到大笑时也会眯眼,在同时检测到张嘴和眯眼时不做提醒。
1.导入库
import numpy as np
import dlib
import cv2
from sklearn.metrics.pairwise import euclidean_distances #欧氏距离
from PIL import Image, ImageDraw, ImageFont #中文
2.定义添加中文文本的函数
def cv2AddChineseText (img, text, position, textColor=(0, 255,10), textSize=30):
if (isinstance(img, np.ndarray)): # 判断是否是OpenCV图片类型
img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) # 实现array到image的转换
draw = ImageDraw.Draw(img) # 在img图片上创建一个绘图的对象
fontStyle = ImageFont.truetype("simsun.ttc", textSize, encoding = "utf-8") # 字体的格式
draw.text(position, text, textColor, font=fontStyle) # 绘制文本
return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR) # 转换为opencv
3.定义绘制眼框凸包的函数
def drawEye(eye) :#绘制眼框凸包
eyeHull = cv2.convexHull(eye)
cv2.drawContours(frame, [eyeHull], -1, (0, 255, 0), 1)
4.定义检测闭眼的函数
def eye_aspect_ratio(eye): # 闭眼
A = euclidean_distances(np.array(eye[1]), np.array(eye[5])) #计算关键点间的欧氏距离
B = euclidean_distances(np.array(eye[2]), np.array(eye[4]))
C = euclidean_distances(np.array(eye[0]), np.array(eye[3]))
ear = ((A + B) / 2.0) / C # 眼部纵横比
return ear
5.定义检测大笑的函数
def MAR(shape): # 计算嘴的宽高比
A = euclidean_distances(np.array(shape[50]), np.array(shape[58]))
B = euclidean_distances(np.array(shape[51]), np.array(shape[57]))
C = euclidean_distances(np.array(shape[52]), np.array(shape[56]))
D = euclidean_distances(np.array(shape[48]), np.array(shape[54]))
return ((A + B + C) / 3) / D # 嘴部纵向距离的平均值
6.构造检测器
COUNTER = 0 # 初始化一个计数器,用于后续跟踪连续检测到闭眼的帧数
detector = dlib.get_frontal_face_detector() #构造脸部位置检测器
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
# 构造关键点检测器
7.计算纵横比
cap=cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
rects = detector(frame, 0) # 检测所有人脸
for rect in rects:
shape = predictor(frame, rect) # 获取每个人脸的关键点
shape = np.matrix([[p.x, p.y] for p in shape.parts()])
mar = MAR(shape) # 计算嘴部的高宽比 大笑
rightEye = shape[36:42]
leftEye = shape[42:48] # 左眼,关键点索引从42到47 (不包含48)
rightEAR = eye_aspect_ratio(rightEye) # 计算右眼纵横比
leftEAR = eye_aspect_ratio(leftEye) # 计算左眼纵横比
ear = (leftEAR + rightEAR) / 2.0 # 左右眼均值处理
8.疲劳判定
if ear < 0.3 and mar < 0.5: # 小于0.3认为闭眼,也可能是眨眼
COUNTER += 1 # 每检测到一次,计数器将+1
if COUNTER >= 50: # 持续50帧都闭眼,则警报
frame = cv2AddChineseText(frame, "!!!!危险!!!!", (250, 250))
elif ear < 0.3 and mar > 0.5: # 可根据项目要求调整阈值 判定大笑
frame = cv2AddChineseText(frame, "大笑", (250, 250))
else:
COUNTER = 0 # 宽高比>0.3,则计数器清零、解除疲劳标志
9.可视化输出
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()
标签:eye,frame,cv2,shape,np,array,源代码,dlib,摄像头
From: https://blog.csdn.net/2301_77444219/article/details/139745741