教你快速使用OpenCV/Python/dlib进行眨眼检测识别!

2018 年 1 月 8 日 全球人工智能


-欢迎加入AI技术专家社群>>

- 日薪5K-10K招兼职AI讲师>>

摘要: 图像识别的新思路:眼睛纵横比,看看大牛如果用这种思路玩转识别眨眼动作!

今天我们来使用面部标志和OpenCV 检测和计算视频流中的眨眼次数。为了构建我们的眨眼检测器,我们将计算一个称为眼睛纵横比(EAR)的指标,由Soukupová和Čech在其2016年的论文“使用面部标志实时眼睛眨眼检测中介绍

今天介绍的这个方法与传统的计算眨眼图像处理方法是不同的,使用眼睛的长宽比是更为简洁的解决方案,它涉及到基于眼睛的面部标志之间的距离比例是一个非常简单的计算。

OpenCVPythondlib进行眼睛眨眼检测

我们的眨眼检测实验分为四个部分:

  1. 第一步,我们将讨论眼睛的纵横比以及如何用它来确定一个人是否在给定的视频帧中闪烁。

  2. 第二步,我们将编写Python,OpenCV和dlib代码来执行面部标志检测和检测视频流中的眨眼。

  3. 第三步,基于代码,我们将应用我们的方法来检测示例摄像头流中的眨眼以及视频文件。

  4. 最后,我将通过讨论改进我们的眨眼检测器的方法来结束。

1.了解眼睛横比EAR

我们可以应用面部标志检测来定位脸部的重要区域,包括眼睛,眉毛,鼻子,耳朵和嘴巴:

这也意味着我们可以通了解特定的索引来提取特定的

在眨眼检测方面,我们眼睛结构感兴趣

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

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

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

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

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

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

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

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

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

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

2.用面部志和OpenCV检测眨眼(代码篇)

请打开一个新文件并将其命名为detect_blinks.py。插入以下代码:

要访问磁盘上的视频文件(FileVideoStream)或内置的网络摄像头/ USB摄像头/Raspberry Pi摄像头模块(VideoStream),我们需要使用imutils,它可以使OpenCV更容易工作。

如果您的系统上没有安装 imutils,请确保使用以下命令安装/升级:

pip install --upgrade imutils

注意:如果您正在使用Python虚拟环境(OpenCV安装教程),请确保使用 workon命令首先访问您的虚拟环境,然后安装/升级 imutils

例外的是dlib,如果您的系统上没有安装dlib,请按照我的dlib安装教程配置您的机器。

接下来,我们将定义eye_aspect_ratio函数:

def eye_aspect_ratio(eye):
	# compute the euclidean distances between the two sets of
	# vertical eye landmarks (x, y)-coordinates
	A = dist.euclidean(eye[1], eye[5])
	B = dist.euclidean(eye[2], eye[4])
	# compute the euclidean distance between the horizontal
	# eye landmark (x, y)-coordinates
	C = dist.euclidean(eye[0], eye[3])
	# compute the eye aspect ratio
	ear = (A + B) / (2.0 * C)
	# return the eye aspect ratio
	return ear

这个函数接受单一的参数,即给定的眼睛面部标志的(x,y)坐标  。

A,B是计算两组垂直眼睛标志之间的距离,而C是计算水平眼睛标志之间的距离。

最后,将分子和分母相结合,得出最终的眼睛纵横比。然后将眼图长宽比返回给调用函数。

让我们继续解析我们的命令行参数:

detect_blinks.py脚本需要一个命令行参数,然后第二个是可选的参数:

1.--shape-predictordlib预训练面部检测器的路径。

2.--video:它控制留在磁上的视频文件的路径。如果您想要使用实时视频流需在行脚本省略此开关。

我们现在需要设置两个重要的常量,您可能需要调整实现,并初始化其他两个重要的变量。

当确定视频流中是否发生眨眼时,我们需要计算眼睛的长宽比。

如果眼睛长宽比低于一定的阈值,然后超过阈值,那么我们将记录一个“眨眼” -EYE_AR_THRESH是这个阈值,我们默认它的值为 0.3,您也可以为自己的应用程序调整它。另外,我们有一个重要的常量,EYE_AR_CONSEC_FRAME,这个值被设置为 3,表明眼睛长宽比小于3时,接着三个连续的帧一定发生眨眼动作。

同样,取决于视频的帧处理吞吐率,您可能需要提高或降低此数字以供您自己实施。

接着初始化两个计数器,COUNTER是眼图长宽比小于EYE_AR_THRESH的连续帧的总数,而 TOTAL则是脚本运行时发生的眨眼的总次数。

现在我们的输入,命令行参数和常量都已经写好了,接着可以初始化dlib的人脸检测器和面部标志检测器:

dlib库使用一个预先训练的人脸检测器,该检测器基于对用于对象检测的定向梯度直方图+线性SVM方法的修改。然后,我们初始化的实际面部标志预测值predictor。

您可以在本博客文章中了解更多关于dlib的面部标志性探测器(即它是如何工作的,它在哪些数据集上进行了训练等)。

由dlib生成的面部标记遵循可索引列表,正如我所描述的那样

因此,我可以确定下面的左眼和右眼提取(xy的起始和束数切片索引

使用这些索引,我们将能够毫不费力地提取眼部区域。

接下来,我们需要决定是否使用基于文件的视频流或实时USB/网络摄像头/ Raspberry Pi摄像头视频流:

如果您使用的是文件视频流,请保持原样。

如果您想使用内置摄像头或USB摄像头,取消注释:# vs = VideoStream(src=0).start()

Raspberry Pi相机模块,取消注释:# vs = VideoStream(usePiCamera=True).start()

如果您未注释上述两个,你可以取消注释# fileStream = False以及以表明你是不是从磁盘读取视频文件。

最后,我们已经完成了我们脚本的主要循环:

# loop over frames from the video streamwhile True:
	# if this is a file video stream, then we need to check if
	# there any more frames left in the buffer to process
	if fileStream and not vs.more():
		break
	# grab the frame from the threaded video file stream, resize
	# it, and convert it to grayscale
	# channels)
	frame = vs.read()
	frame = imutils.resize(frame, width=450)
	gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
	# detect faces in the grayscale frame
	rects = detector(gray, 0)

while我们开始从视频流循环帧。

如果我们正在访问视频文件流,并且视频中没有剩余的帧,我们从循环中断。

从我们的视频流中读取下一帧,然后调整大小并将其转换为灰度。然后,我们通过dlib内置的人脸检测器检测灰度帧中的人脸。

我们现在需要遍历帧中的每个面,然后对其中的每个面应用面部标志检测:

# loop over the face detections
	for rect in rects:
		# determine the facial landmarks for the face region, then
		# convert the facial landmark (x, y)-coordinates to a NumPy
		# array
		shape = predictor(gray, rect)
		shape = face_utils.shape_to_np(shape)
		# extract the left and right eye coordinates, then use the
		# coordinates to compute the eye aspect ratio for both eyes
		leftEye = shape[lStart:lEnd]
		rightEye = shape[rStart:rEnd]
		leftEAR = eye_aspect_ratio(leftEye)
		rightEAR = eye_aspect_ratio(rightEye)
		# average the eye aspect ratio together for both eyes
		ear = (leftEAR + rightEAR) / 2.0

shape确定面部区域的面部标志,接着将这些(x,y)坐标转换成NumPy阵列。

使用我们之前在这个脚本中的数组切片技术,我们可以分别为左眼left eye和右眼提取(x,y)坐标,然后我们计算每只眼睛的眼睛长宽比  。

下一个代码块简单地处理可视化眼部区域的面部标志:

# compute the convex hull for the left and right eye, then
		# visualize each of the eyes
		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)

我们已经计算了我们的(平均的)眼睛长宽比,但是我们并没有真正确定是否发生了眨眼,这在下一部分中将得到关注:

# check to see if the eye aspect ratio is below the blink
		# threshold, and if so, increment the blink frame counter
		if ear < EYE_AR_THRESH:
			COUNTER += 1
		# otherwise, the eye aspect ratio is not below the blink
		# threshold
		else:
			# if the eyes were closed for a sufficient number of
			# then increment the total number of blinks
			if COUNTER >= EYE_AR_CONSEC_FRAMES:
				TOTAL += 1
			# reset the eye frame counter
			COUNTER = 0

第一步检查眼睛纵横比是否低于我们的眨眼阈值,如果是,我们递增指示正在发生眨眼的连续帧数。否则,我们将处理眼高宽比低于眨眼阈值的情况,我们对进行检查,看看是否有足够数量的连续帧包含低于我们预先定义的阈值的眨眼率。如果检查通过,我们增加总的闪烁次数。然后我们重新设置连续闪烁次数 COUNTER。

我们的最终代码块只是简单地处理在输出帧上绘制闪烁的次数,以及显示当前的眼图高宽比:

3.眨眼检测结

在执行之前,请务必使用本指南下载”源代码+示例视频+预训练的dlib面部标记预测器。

要将我们的眨眼检测器应用于示例视频,只需执行以下命令:

$python detect_blinks.py \

       --shape-predictor shape_predictor_68_face_landmarks.dat \

       --video blink_detection_demo.mp4

后来,在旅馆里,我记录下了眨眼检测器的实时流,并将其变成了屏幕录像。

要访问我的内置摄像头,我执行了下面的命令(注意取消注释正确的VideoStream类,如上所述):

4.的眨眼检测

我们只关注眼睛纵横比作为定量指标,以确定一个人是否在视频流中眨了眨眼睛。

为了使我们的眨眼检测器更加强大的显示中可能挑战,Soukupová和Čech建议:为了改善我们的眨眼检测器,Soukupová和Čech建议构建眼长宽比(第N帧,第  N-6 帧和第  N + 6帧)的13维特征向量,然后将该特征向量馈送到线性SVM分类。

↓ 点击阅读原文,进入学院

登录查看更多
3

相关内容

一个跨平台的计算机视觉处理库,全称是Open Source Computer Vision。
【实用书】学习用Python编写代码进行数据分析,103页pdf
专知会员服务
194+阅读 · 2020年6月29日
【实用书】Python机器学习Scikit-Learn应用指南,247页pdf
专知会员服务
266+阅读 · 2020年6月10日
专知会员服务
171+阅读 · 2020年6月4日
【实用书】Python技术手册,第三版767页pdf
专知会员服务
234+阅读 · 2020年5月21日
Python计算导论,560页pdf,Introduction to Computing Using Python
专知会员服务
73+阅读 · 2020年5月5日
【干货书】机器学习Python实战教程,366页pdf
专知会员服务
340+阅读 · 2020年3月17日
Sklearn 与 TensorFlow 机器学习实用指南,385页pdf
专知会员服务
129+阅读 · 2020年3月15日
算法与数据结构Python,369页pdf
专知会员服务
162+阅读 · 2020年3月4日
【精通OpenCV 4】Mastering OpenCV 4 - Third Edition 随书代码
专知会员服务
39+阅读 · 2019年11月13日
多目标追踪器:用 OpenCV 实现多目标追踪(C++/Python)
使用TensorFlow目标检测和OpenCV分析足球视频
极市平台
5+阅读 · 2018年7月10日
微表情检测和识别的研究进展与趋势
中国计算机学会
15+阅读 · 2018年3月23日
Python | 50行代码实现人脸检测
计算机与网络安全
3+阅读 · 2018年1月23日
用 Python 和 OpenCV 检测图片上的条形码
Python开发者
5+阅读 · 2018年1月20日
【机器视觉】人脸检测与识别总结
产业智能官
7+阅读 · 2017年12月6日
荐书丨OpenCV算法精解:基于Python与C++
程序人生
18+阅读 · 2017年11月18日
Clustered Object Detection in Aerial Images
Arxiv
5+阅读 · 2019年8月27日
Arxiv
8+阅读 · 2019年3月28日
Arxiv
3+阅读 · 2018年2月24日
Arxiv
5+阅读 · 2018年1月17日
VIP会员
相关VIP内容
【实用书】学习用Python编写代码进行数据分析,103页pdf
专知会员服务
194+阅读 · 2020年6月29日
【实用书】Python机器学习Scikit-Learn应用指南,247页pdf
专知会员服务
266+阅读 · 2020年6月10日
专知会员服务
171+阅读 · 2020年6月4日
【实用书】Python技术手册,第三版767页pdf
专知会员服务
234+阅读 · 2020年5月21日
Python计算导论,560页pdf,Introduction to Computing Using Python
专知会员服务
73+阅读 · 2020年5月5日
【干货书】机器学习Python实战教程,366页pdf
专知会员服务
340+阅读 · 2020年3月17日
Sklearn 与 TensorFlow 机器学习实用指南,385页pdf
专知会员服务
129+阅读 · 2020年3月15日
算法与数据结构Python,369页pdf
专知会员服务
162+阅读 · 2020年3月4日
【精通OpenCV 4】Mastering OpenCV 4 - Third Edition 随书代码
专知会员服务
39+阅读 · 2019年11月13日
相关资讯
多目标追踪器:用 OpenCV 实现多目标追踪(C++/Python)
使用TensorFlow目标检测和OpenCV分析足球视频
极市平台
5+阅读 · 2018年7月10日
微表情检测和识别的研究进展与趋势
中国计算机学会
15+阅读 · 2018年3月23日
Python | 50行代码实现人脸检测
计算机与网络安全
3+阅读 · 2018年1月23日
用 Python 和 OpenCV 检测图片上的条形码
Python开发者
5+阅读 · 2018年1月20日
【机器视觉】人脸检测与识别总结
产业智能官
7+阅读 · 2017年12月6日
荐书丨OpenCV算法精解:基于Python与C++
程序人生
18+阅读 · 2017年11月18日
相关论文
Clustered Object Detection in Aerial Images
Arxiv
5+阅读 · 2019年8月27日
Arxiv
8+阅读 · 2019年3月28日
Arxiv
3+阅读 · 2018年2月24日
Arxiv
5+阅读 · 2018年1月17日
Top
微信扫码咨询专知VIP会员