文章目录
- 一、疲劳检测实现的思想
- 二、代码实现
一、疲劳检测实现的思想
- 了解以下几篇文章有助于了解疲劳检测的方法
- 基于dlib库的人脸检测
- https://blog.csdn.net/weixin_73504499/article/details/142977202?spm=1001.2014.3001.5501
- 基于dlib库的人脸关键点定位
- https://blog.csdn.net/weixin_73504499/article/details/142990867?spm=1001.2014.3001.5501
- 基于dlib库的人脸关键部位的轮廓检测
- https://blog.csdn.net/weixin_73504499/article/details/143027371?spm=1001.2014.3001.5501
- 基于dlib库的人脸检测
- 实现疲劳检测的方法核心方法是通过眼睛的关键点定位来实现的,具体思想如下:
-
通过68个人脸关键点定位后的效果如下:
-
通过[36-41]和[42~45]这分别两组6个关键点来确定左眼和右眼的位置,眼睛的闭合程度会改变这些点的位置, 因此可以通过这6个点来计算眼睛睁开时的宽高比
-
设定一个阈值来判断眼睛的闭合程度,低于这个阈值则表示眼睛处于非正常睁开状态,若长时间都低于这个阈值,则会判定为是处于疲劳状态
-
具体实现如下图
- 取眼睛的6个关键点的上下两组点,分别求出两个距离,并取平均值,作为眼睛镇开时的高度
- 取左右两个点,计算距离,作为眼睛镇开时的宽度
- 高度与宽度的比值与设定的阈值进行比较,并做出判断
-
二、代码实现
好未写完!!!!!!!!!!!!!!!!
-
定义计算眼睛纵横比的函数
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)): # 判断是否是OpenCV图片类型 img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) # 实现 array 到 image 的转换 draw = ImageDraw.Draw(img) # 在img图片上创建一个绘图的对象 # 字体的格式 C 盘中的 Windows/Fonts 中,复制到此文件夹下可看到文件名 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 格式
-
完整代码:
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)): # 判断是否是OpenCV图片类型 img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) # 实现 array 到 image 的转换 draw = ImageDraw.Draw(img) # 在img图片上创建一个绘图的对象 # 字体的格式 C 盘中的 Windows/Fonts 中,复制到此文件夹下可看到文件名 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 格式 """ 绘制眼眶凸包 """ def drawEye(eye): eyeHull = cv2.convexHull(eye) cv2.drawContours(frame, [eyeHull], -1, (0, 255, 0)) 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() frame = cv2.flip(frame, 1) 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(不包含42) leftEye = shape[42:48] # 左眼,关键点索引从42到47(不包含48) rightEAR = eye_aspect_ratio(rightEye) # 计算右眼纵横比 leftEAR = eye_aspect_ratio(leftEye) # 计算左眼纵横比 ear = (rightEAR + leftEAR) / 2.0 # 均值处理 if ear < 0.3: # 小于0.3认为闭眼,也可能是眨眼(可根据实际调整) COUNTER += 1 # 每检测到一次,将+1 if COUNTER >= 50: # 持续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) # 检查是否按下ESC键(ASCII码27),如果按下则退出循环 if cv2.waitKey(10) == 27: break # 释放摄像头资源 cap.release() # 关闭所有OpenCV创建的窗口 cv2.destroyAllWindows()