dlib库关键点定位和疲劳检测
目录
一.dlib库关键点定位
1.创建检测器并检测人脸
2.加载检测人脸68关键点文件
3.循环处理每一个人脸信息
二.关键点轮廓绘制
三.疲劳检测
1.疲劳检测技术与原理
2.代码实现要点
①数据处理,计算纵横比
②基本处理
③获取左眼和右眼的坐标信息列表
④调用方法计算左眼和右眼的纵横比和平均纵横比
⑤防误报机制
⑥显示
⑦释放资源
一.dlib库关键点定位
1.创建检测器并检测人脸
import numpy as np
import cv2
import dlibimg=cv2.imread('img.png')
img = cv2.resize(img, (400, 700))
detector=dlib.get_frontal_face_detector()
faces=detector(img,0)
2.加载检测人脸68关键点文件
GitHub - davisking/dlib-models: Trained model files for dlib example programs.
shape_predictor_68_face_landmarks.dat文件提前从该网址下载
predictor=dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
3.循环处理每一个人脸信息
for face in faces:shape=predictor(img,face)landmarks=np.array([[p.x,p.y] for p in shape.parts()])for idx,point in enumerate(landmarks):pos=[point[0],point[1]]cv2.circle(img,pos,2,(0,255,0),-1)cv2.putText(img,str(idx),pos,cv2.FONT_HERSHEY_SIMPLEX,0.4,(255,255,255),1,cv2.LINE_AA)
cv2.imshow('img',img)
cv2.waitkey(0)
先通过predictor(img,face)获取68个关键点的信息
再将其中的坐标信息用矩阵保存
遍历矩阵在img上标出关键点小圆和序号
cv2.destroyAllWindows()
二.关键点轮廓绘制
大致与上述代码相同,不同是定义了两个方法
def drawLine(start,end):pts=shape[start:end]for l in range(1,len(pts)):ptA=tuple(pts[l-1])ptB=tuple(pts[l])cv2.line(image,ptA,ptB,(0,255,0),2)
例如drawLine(0,17)
通过切片操作,从完整的坐标列表中筛选出特定区域(如从第0到17点可以参考上图)的坐标数据PTS
使用for循环遍历筛选后的坐标数据,每次循环将连续的两个坐标点提取出来。
调用drawLine函数,根据步骤二中提取到的两个坐标点作为起点和终点,绘制一条线段。
def drawConvexHull(start,end):Facial=shape[start:end+1]mouthHull=cv2.convexHull(Facial)cv2.drawContours(image,[mouthHull],-1,(0,255,0),2)
例如drawConvexHull(36,41)
提取第36个到第41个关键点坐标
cv2.convexHull()
是 OpenCV 中用于计算凸包(Convex Hull)的函数,它可以从一组点集中找到能包含所有点的 最小凸多边形。这个概念源自计算几何,"凸" 意味着多边形内部任意两点的连线都完全在多边形内部,不存在凹陷。
最后将连接后的凸多边形当作轮廓画出
其余代码:
import numpy as np
import dlib
import cv2
image=cv2.imread('img.png')
image = cv2.resize(image, (400, 700))
detector=dlib.get_frontal_face_detector()
faces=detector(image,0)
predictor=dlib.shape_predictor('../关键点定位/shape_predictor_68_face_landmarks.dat')
for face in faces:shape=predictor(image,face)shape=np.array([[p.x,p.y] for p in shape.parts()])drawConvexHull(36,41)drawConvexHull(42,47)drawConvexHull(48,59)drawConvexHull(60,67)drawLine(0,17)drawLine(17,22)drawLine(22,27)drawLine(27,36)
cv2.imshow('Frame',image)
cv2.waitKey(0)
cv2.destroyAllWindows()
三.疲劳检测
1.疲劳检测技术与原理
- 核心思路:通过检测和分析人脸上的68个关键点,特别是眼睛区域的6个关键点,来判断用户是否处于疲劳状态。
- 核心指标:采用“眼睛横纵比”作为判断依据。此比值是通过计算竖直方向上两点间的距离(e.g., 点37到41和点38到40的平均值),除以水平方向的距离(e.g., 点36到41)得出。
- 判断阈值:
- 当比值大于0.3,表示眼睛正常睁开。
- 当比值小于等于0.3,表明可能处于闭合或疲劳状态。系统通过连续帧的监测来避免误报,例如连续50帧均低于0.3才会触发报警。
2.代码实现要点
①数据处理,计算纵横比
利用OpenCV的distance模块,高效地计算关键点之间的欧式距离。
- 数据维度注意:在调用距离计算函数时,需要注意传入参数必须为二维数组,因此在传参前需通过括号处理。
from sklearn.metrics.pairwise import euclidean_distances
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)/C#纵横比return ear
②基本处理
COUNNTER用于连续帧检测
COUNTER=0
video=cv2.VideoCapture(0)
detector=dlib.get_frontal_face_detector()
predictor=dlib.shape_predictor('../关键点定位/shape_predictor_68_face_landmarks.dat')
while True:ret,frame=video.read()faces = detector(frame, 0)for face in faces:shape=predictor(frame,face)shape=np.array([[p.x,p.y] for p in shape.parts()])
③获取左眼和右眼的坐标信息列表
rightEye=shape[36:42]leftEye=shape[42:48]
④调用方法计算左眼和右眼的纵横比和平均纵横比
rightEar=eye_aspect_ratio(rightEye)leftEar=eye_aspect_ratio(leftEye)ear=(leftEar+rightEar)/2.0
⑤防误报机制
if ear<0.3:COUNTER+=1if COUNTER>=50:frame=cv2_put_text_cn(frame,'!!!!危险!!!!',(250,250))else:COUNTER=0
设计了counter计数器,仅当单片帧信息低于阈值时计数加1;一旦遇到高于阈值的帧,将立即将计数器重置为0,确保报警的严谨性
⑥显示
def drawEye(eye):eyeHUll=cv2.convexHull(eye)cv2.drawContours(frame,[eyeHUll],-1,(0,255,0),-1)
def cv2_put_text_cn(img, text, org, font_size=20, color=(0, 255, 0)):"""在OpenCV图像上绘制中文参数:img: OpenCV图像(numpy数组)text: 要绘制的中文文本org: 文本起始位置(x, y)font_size: 字体大小color: 文本颜色,BGR格式返回:绘制了文本的图像"""# 转换OpenCV图像为PIL图像img_pil = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))# 创建绘制对象draw = ImageDraw.Draw(img_pil)# 加载中文字体,这里使用系统中的宋体# 注意:需要根据自己系统的字体路径进行调整try:# Windows系统常见字体路径font = ImageFont.truetype("C:/Windows/Fonts/simhei.ttf", font_size, encoding="utf-8")except:try:# Linux系统常见字体路径font = ImageFont.truetype("/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc", font_size)except:# Mac系统常见字体路径font = ImageFont.truetype("/System/Library/Fonts/PingFang.ttc", font_size)# 绘制中文draw.text(org, text, font=font, fill=(color[2], color[1], color[0]))# 转换回OpenCV格式return cv2.cvtColor(np.array(img_pil), cv2.COLOR_RGB2BGR)
drawEye(leftEye)drawEye(rightEye)info="EAR: {:.2f}".format(ear[0][0])frame=cv2_put_text_cn(frame,info,(0,30))cv2.imshow('frame',frame)if cv2.waitKey(1)==27:break
会在原视频画面中,用绿色填充检测出的特征点轮廓,并在左上角实时显示当前计算的平均横纵比数值。
⑦释放资源
video.release()
cv2.destroyAllWindows()