基于dlib的人脸68特征点提取(眨眼张嘴检测)python版本
这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入欢迎使用Ma.
引言
(1) 利用 Dlib 官方训练好的模型 “shape_predictor_68_face_landmarks.dat” 进行 68 个点标定;
(2)利用 OpenCv 进行图像化处理,在人脸上画出 68 个特征点,并标明特征点的序号实现的 68 个特征点;
(3)根据得到的点位进行简单的活体检测
开发环境和库
1.Window10
2.Anaconda3
3.Python 3.6
4.dlib 19.8.1
5.opencv-python 4.2.0.32 (openCV只是用来画图)
PS:dlib 的pip install 可能需要加上版本号才能成功下载安装
pip install dlib==19.8.1
# -*- coding: UTF-8 -*-
import dlib
from skimage import io
from scipy.spatial import distance as dist
import matplotlib.pyplot as plt
import numpy as np
import cv2
流程设计
- 68 点提取:
借助 Dlib 官方的 Demo: face_landmark_detection.py,可以得到脸部 68 个特征点的坐标;
- OpenCv 绘图:
使用 opencv 中 画圆函数 cv2.circle() 和 画字符函数 cv2.putText() ;
静态图片的检测
张嘴和闭眼的检测
参考:Eye blink detection with OpenCV, Python, and dlib
公式很简单,就是欧式距离公式,设定好纵横比(EAR)。
def eye_aspect_ratio(eye):
# 垂直眼标志(X,Y)坐标
A = dist.euclidean(eye[1],eye[5])#计算两个集合之间的欧式距离
B = dist.euclidean(eye[2],eye[4])
#水平
C = dist.euclidean(eye[0], eye[3])
ear = (A+B) / (2.0 * C)
return ear
def mouth_aspect_ratio(mouth):
#垂直点位
A = np.linalg.norm(mouth[2] - mouth[9])
B = np.linalg.norm(mouth[4] - mouth[7])
C = np.linalg.norm(mouth[0] - mouth[6])
mar = (A + B) / (2.0 * C)
return mar
还有可调试的常量
EYE_AR_THRESH = 0.2
EYE_AR_CONSEC_FRAMES = 2
MAR_THRESH = 0.5
MOUTH_AR_CONSEC_FRAMES = 3
COUNT = 0
TOTAL = 0
mCOUNT = 0
mTOTAL = 0
r_eye_ear = 0
l_eye_ear = 0
然后我们就可以把视频流的定帧数据输入到我们的函数里面解析,算出各个指标来判断是否触发张嘴闭眼。
cap = cv2.VideoCapture(0) #创建一个对象
cap.set(3,720)
isOpen = cap.isOpened() #检测是否开启
while isOpen:
#cap.read()
#返回两个值:
#一个布尔值 true/false,用来判断读取视频是否成功/是否到视频末尾
#图像对象,图像的三维矩阵
flag,im_rd = cap.read()
# 每帧数据延时 1ms,延时为 0 读取的是静态帧
k = cv2.waitKey(1)
img_gray = cv2.cvtColor(im_rd, cv2.COLOR_RGB2GRAY)
faces = detector(img_gray, 0)
font = cv2.FONT_HERSHEY_SIMPLEX
# 标点
if len(faces) != 0:
# 检测到人脸
for i in range(len(faces)):
landmarks = np.matrix([[p.x, p.y] for p in landmark_predictor(im_rd, faces[i]).parts()])
left_eye = landmarks[42:48]
right_eye = landmarks[36:41]
mouth_points = landmarks[48:68]
#print(left_eye)
l_eye_ear = eye_aspect_ratio(left_eye)
r_eye_ear = eye_aspect_ratio(left_eye)
t_ear = (l_eye_ear +r_eye_ear) / 2.0
mouth_ear = mouth_aspect_ratio(mouth_points)
if t_ear < 0.2:
COUNT += 1
else:
if COUNT >= EYE_AR_CONSEC_FRAMES:
TOTAL += 1
COUNT = 0
if mouth_ear > MAR_THRESH:
mCOUNT += 1
else:
if mCOUNT >= MOUTH_AR_CONSEC_FRAMES:
mTOTAL += 1
mCOUNT = 0
for idx,point in enumerate(landmarks):
# 68点打印
pos = (point[0, 0], point[0, 1])
#利用 cv2.circle 给每个特征点画一个圈,共 68 个
cv2.circle(im_rd, pos, 2, color=(139, 0, 0))
# 利用 cv2.putText 输出 1-68
#cv2.putText(im_rd, str(idx + 1), pos, font, 0.2, (187, 255, 255), 1, cv2.LINE_AA)
cv2.putText(im_rd, "faces: " + str(len(faces)), (20, 20), font, 1, (255,20,147), 1, cv2.LINE_AA)
#cv2.putText(im_rd, "L_Eye_Ear: " + str(l_eye_ear), (20, 60), font, 1, (0, 0, 0), 1, cv2.LINE_AA)
#cv2.putText(im_rd, "R_Eye_Ear: " + str(r_eye_ear), (20, 90), font, 1, (0, 0, 0), 1, cv2.LINE_AA)
cv2.putText(im_rd, "T_Ear: " + str(t_ear), (20, 40), font, 1, (255,20,147), 1, cv2.LINE_AA)
cv2.putText(im_rd, "BlinkNum: " + str(TOTAL), (20, 80), font, 1, (255,20,147), 1, cv2.LINE_AA)
cv2.putText(im_rd, "openMouth: " + str(mTOTAL), (20, 100), font, 1, (255,20,147), 1, cv2.LINE_AA)
else:
cv2.putText(im_rd, "no face", (20, 50), font, 1, (0, 0, 0), 1, cv2.LINE_AA)
cv2.putText(im_rd, "Press 'q': Quit", (20, 450),cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0,0,255),)
cv2.namedWindow("camera", 0)
cv2.imshow("camera", im_rd)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
更多推荐
所有评论(0)