眼睛纵横比(EAR)

在讨论EAR之前,先看看68个人脸特征点: 


人脸特征点检测本身的算法是很复杂的,dlib中给出了相关的实现。

每只眼睛由6个(x,y)坐标表示,从眼睛的左角开始,然后围绕该区域的其余部分顺时针显示:

基于这个描述,我们应该抓住重点:这些坐标的宽度高度之间有一个关系。

Soukupová和Čech在其2016年的论文“使用面部标志实时眼睛眨眼检测”的工作,我们可以推导出反映这种关系的方程,称为眼睛纵横比(EAR):

其中p1,...,p6是2D面部地标位置。

这个方程的分子是计算垂直眼睛标志之间的距离,而分母是计算水平眼睛标志之间的距离,因为只有组水平点,但是两组垂直点,所以进行加权分母。

为什么这个方程如此有趣?

我们将会发现,眼睛的长宽比在眼睛张开的时候大致是恒定的,但是在发生眨眼时会迅速下降到零。

使用这个简单的方程,我们可以避免使用图像处理技术简单地依靠眼睛地标距比例来确定一个人是否眨眼。

为了更清楚地说明,看下面的图:

底部图中绘出了眼纵横比随时间的视频剪辑的曲线图。正如我们所看到的,眼睛纵横比是恒定的,然后迅速下降到接近零,然后再增加,表明一个单一的眨眼已经发生。

代码实现

# -*- coding: utf-8 -*-
# import the necessary packages
from scipy.spatial import distance as dist
from imutils.video import FileVideoStream
from imutils.video import VideoStream
from imutils import face_utils
import numpy as np
import argparse
import imutils
import time
import dlib
import cv2 def eye_aspect_ratio(eye):
# 计算两个集合之间的欧几里得距离
# 垂直眼标志(X,Y)坐标
A = dist.euclidean(eye[1], eye[5])
B = dist.euclidean(eye[2], eye[4])
# 计算水平之间的欧几里得距离
# 水平眼标志(X,Y)坐标
C = dist.euclidean(eye[0], eye[3])
# 眼睛长宽比的计算
ear = (A + B) / (2.0 * C)
# 返回眼镜的长宽比
return ear # 定义两个常数
# 眼睛长宽比
# 闪烁阈值
EYE_AR_THRESH = 0.2
EYE_AR_CONSEC_FRAMES = 3
# 初始化帧计数器和眨眼总数
COUNTER = 0
TOTAL = 0 # 初始化DLIB的人脸检测器(HOG),然后创建面部标志物预测
print("[INFO] loading facial landmark predictor...")
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat') # 分别获取左右眼面部标志的索引
(lStart, lEnd) = face_utils.FACIAL_LANDMARKS_IDXS["left_eye"]
(rStart, rEnd) = face_utils.FACIAL_LANDMARKS_IDXS["right_eye"] cap = cv2.VideoCapture(1) # 从视频流循环帧
while True:
ret, frame = cap.read() gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 检测灰度帧中的人脸
rects = detector(gray, 0) # 人脸检测循环
for rect in rects:
# 确定脸部区域的面部标志,然后将面部标志(x,y)坐标转换为数字阵列
shape = predictor(gray, rect)
shape = face_utils.shape_to_np(shape)
# 提取左眼和右眼坐标,然后使用坐标计算双眼的眼睛长宽比
leftEye = shape[lStart:lEnd]
rightEye = shape[rStart:rEnd]
leftEAR = eye_aspect_ratio(leftEye)
rightEAR = eye_aspect_ratio(rightEye)
# 双眼平均长宽比
ear = (leftEAR + rightEAR) / 2.0 # 计算左眼和右眼的标志点并绘制
leftEyeHull = cv2.convexHull(leftEye)
rightEyeHull = cv2.convexHull(rightEye)
cv2.drawContours(frame, [leftEyeHull], -1, (0, 255, 0), 1)
cv2.drawContours(frame, [rightEyeHull], -1, (0, 255, 0), 1) # 在图片中标注人脸,并显示
left = rect.left()
top = rect.top()
right = rect.right()
bottom = rect.bottom()
cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 3) '''
第一步检查眼睛纵横比是否低于我们的眨眼阈值,如果是,我们递增指示正在发生眨眼的连续帧数。否则,我们将处理眼高宽比不低于眨眼阈值的情况,我们对其进行检查,
看看是否有足够数量的连续帧包含低于我们预先定义的阈值的眨眼率。如果检查通过,我们增加总的闪烁次数。然后我们重新设置连续闪烁次数 COUNTER。
'''
if ear < EYE_AR_THRESH:
COUNTER += 1
else:
# 如果眼睛闭合足够数量,那么眨眼总数增加
if COUNTER >= EYE_AR_CONSEC_FRAMES:
TOTAL += 1
# 重置眼帧计数器
COUNTER = 0 for (x, y) in shape:
cv2.circle(frame, (x, y), 1, (0, 0, 255), -1) cv2.putText(frame, "COUNTER: {}".format(COUNTER), (150, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
cv2.putText(frame, "Blinks: {}".format(TOTAL), (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
cv2.putText(frame, "EAR: {:.2f}".format(ear), (300, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2) cv2.imshow("Frame", frame)
print(len(rects))
# if the `q` key was pressed, break from the loop
if cv2.waitKey(1) & 0xFF == ord('q'):
break # do a bit of cleanup
cv2.destroyAllWindows()

效果

最新文章

  1. java.lang.OutOfMemoryError: PermGen space及其解决方法
  2. Shell脚本学习第二课&#183;
  3. linux-3重置root密码
  4. iOS7中如何去除UINavigationbar下边的那条黑线
  5. json编解码
  6. MFC对话框中解决回车键、ESC键退出的方法
  7. windows phone 7 客户端和web的交互(WebBrowser的使用)
  8. HTML &lt;td&gt; 标签的 colspan 属性
  9. PHP操作Memcached
  10. 安卓高级7 vitamio 视频框架 从raw文件下获取文件uri
  11. 颜色空间之CIE2000色差公式
  12. Java: 在不同windows主题下,JFrame窗口设置最佳高度的解决方案
  13. .NET解决[Serializable] Attribute引发的Json序列化k_BackingField
  14. MongoDB基础命令
  15. SPA页面初试
  16. 用yaml来编写配置文件
  17. Object之equals和hashCode
  18. CodeForces 1070J Streets and Avenues in Berhattan 性质+动态规划
  19. (0.2.4)Mysql安装——yum源安装
  20. 022:SQL优化--JOIN算法

热门文章

  1. 02.Linux-CentOS系统NFS挂载时拒绝访问挂载问题
  2. 【LeetCode】智商题 brainteaser(共3题)
  3. 公私钥,数字证书,https
  4. java中的进制转换以及字符串类和数值类的相互转化
  5. [BZOJ5428][九省联考2018]双木棋
  6. python之字符串切分
  7. 比传统事务快10倍?一张图读懂阿里云全局事务服务GTS
  8. 阿里云数据库备份DBS商业化发布,数据库实时备份到OSS
  9. PHP curl_multi_close函数
  10. 【Linux】grub引导修复