人脸检测实战高级:使用 OpenCV、Python 和 dlib 完成眨眼检测(1)

先自我介绍一下,小编浙江大学毕业,去过华为、字节跳动等大厂,目前阿里P7

深知大多数程序员,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Python全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友。
img
img



既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上Python知识点,真正体系化!

由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、讲解视频,并且后续会持续更新

如果你需要这些资料,可以添加V获取:vip1024c (备注Python)
img

正文

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

construct the argument parse and parse the arguments

ap = argparse.ArgumentParser()

ap.add_argument(“-p”, “–shape-predictor”, required=True,

help=“path to facial landmark predictor”)

ap.add_argument(“-v”, “–video”, type=str, default=“”,

help=“path to input video file”)

args = vars(ap.parse_args())

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

  • –shape-predictor :这是 dlib 的预训练面部标志检测器的路径。 您可以使用本博文底部的“下载”部分将检测器以及源代码 + 示例视频下载到本教程中。

  • –video :此可选开关控制驻留在磁盘上的输入视频文件的路径。 如果您想使用实时视频流,只需在执行脚本时省略此开关即可。

我们现在需要设置两个重要的常量,您可能需要为自己的实现进行调整,同时初始化另外两个重要的变量,所以一定要注意这个解释:

定义两个常量,一个为眼睛纵横比来表示

闪烁然后第二个常量为连续的次数

帧眼睛必须低于阈值

EYE_AR_THRESH = 0.3

EYE_AR_CONSEC_FRAMES = 3

初始化帧计数器和闪烁总数

COUNTER = 0

TOTAL = 0

在确定视频流中是否发生眨眼时,我们需要计算眼睛纵横比。

如果眼睛纵横比低于某个阈值,然后又高于阈值,那么我们将注册一个“眨眼”——EYE_AR_THRESH 就是这个阈值。我们默认它的值为 0.3,因为这对我的应用程序最有效,但您可能需要为自己的应用程序调整它。

然后我们有一个重要的常量,EYE_AR_CONSEC_FRAME——这个值被设置为 3 以指示眼睛纵横比小于 EYE_AR_THRESH 的三个连续帧必须发生,以便注册眨眼。

同样,根据管道的帧处理吞吐率,您可能需要为自己的实现提高或降低此数字。

第 44 和 45 行初始化两个计数器。 COUNTER 是眼睛纵横比小于 EYE_AR_THRESH 的连续帧的总数,而 TOTAL 是脚本运行时发生的眨眼总数。

现在我们的导入、命令行参数和常量都已经处理好了,我们可以初始化 dlib 的人脸检测器和面部标记检测器:

初始化dlib的人脸检测器(基于HOG)然后创建

面部标志预测器

print(“[INFO] loading facial landmark predictor…”)

detector = dlib.get_frontal_face_detector()

predictor = dlib.shape_predictor(args[“shape_predictor”])

初始化实际的面部标志预测器。

dlib 生成的面部标志遵循可索引的列表,如下:

img

因此,我们可以确定开始和结束数组切片索引值,以便为下面的左眼和右眼提取 (x, y) 坐标:

获取左侧和面部标志的索引

右眼,分别

(lStart, lEnd) = face_utils.FACIAL_LANDMARKS_IDXS[“left_eye”]

(rStart, rEnd) = face_utils.FACIAL_LANDMARKS_IDXS[“right_eye”]

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

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

start the video stream thread

print(“[INFO] starting video stream thread…”)

vs = FileVideoStream(args[“video”]).start()

fileStream = True

vs = VideoStream(src=0).start()

vs = VideoStream(usePiCamera=True).start()

fileStream = False

time.sleep(1.0)

fps = 30 #保存视频的FPS,可以适当调整

size=(450,800)

videoWriter = cv2.VideoWriter(‘3.mp4’,-1,fps,size)#最后一个是保存图片的尺寸

如果您使用的是文件视频流,则保留代码原样。

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

对于 Raspberry Pi 摄像头模块,取消注释# vs = VideoStream(usePiCamera=True).start()。

定义帧数。

定义大小

定义视频写入对象

最后,我们到达了脚本的主循环:

loop over frames from the video stream

while True:

如果这是一个文件视频流,那么我们需要检查是否

缓冲区中还有更多帧要处理

if fileStream and not vs.more():

break

frame = vs.read()

if frame is None:

break

frame = imutils.resize(frame, width=450)

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

在灰度帧中检测人脸

rects = detector(gray, 0)

遍历视频流中的帧。

如果我们正在访问一个视频文件流并且视频中没有更多的帧,我们就会中断循环。

从视频流中读取下一帧,然后调整其大小并将其转换为灰度。

然后我们通过 dlib 的内置人脸检测器检测灰度帧中的人脸。

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

loop over the face detections

for rect in rects:

确定面部区域的面部标志,然后

将面部标志 (x, y) 坐标转换为 NumPy数组

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

确定面部区域的面部标志,将这些 (x, y) 坐标转换为 NumPy 数组。

使用本脚本前面的数组切片技术,我们可以分别提取左眼和右眼的 (x, y) 坐标。

然后,在第 96 和 97 行计算每只眼睛的眼睛纵横比。

按照 Soukupová 和 Čech 的建议,我们将两只眼睛的纵横比平均在一起以获得更好的眨眼估计(当然,假设一个人同时眨眼)。

我们的下一个代码块只是处理眼睛区域本身的面部标志的可视化:

计算左眼和右眼的凸包,然后

可视化每只眼睛

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)

在这一点上,我们已经计算了我们的(平均)眼睛纵横比,但我们实际上还没有确定是否发生了眨眼——这将在下一节中解决:

检查眼睛的纵横比是否低于眨眼

阈值,如果是,则增加闪烁帧计数器

if ear < EYE_AR_THRESH:

COUNTER += 1

否则,眼睛纵横比不低于眨眼

# 临界点

else:

如果眼睛闭上足够多的次数

然后增加闪烁的总数

if COUNTER >= EYE_AR_CONSEC_FRAMES:

TOTAL += 1

重置眼框计数器

COUNTER = 0

检查眼睛纵横比是否低于我们的眨眼阈值——如果是增加指示正在发生眨眼的连续帧的数量。

否则,处理眼睛纵横比不低于眨眼阈值的情况。

在这种情况下,再次检查以查看是否有足够数量的连续帧包含低于我们预定义阈值的眨眼率。

如果检查通过,我们增加闪烁的总次数。

然后我们重置连续闪烁的次数 COUNTER。

我们的最终代码块只是处理在我们的输出帧上绘制眨眼次数,以及显示当前眼睛纵横比:

绘制帧上闪烁的总数以及

计算出的帧的眼睛纵横比

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)

show the frame

cv2.imshow(“Frame”, frame)

videoWriter.write(frame)

key = cv2.waitKey(1) & 0xFF

if the q key was pressed, break from the loop

if key == ord(“q”):

break

videoWriter.release()

do a bit of cleanup

cv2.destroyAllWindows()

vs.stop()

眨眼检测结果

=================================================================

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

python detect_blinks.py --shape-predictor shape_predictor_68_face_landmarks.dat --video 11.mp4

测试结果:

frame

(1)Python所有方向的学习路线(新版)

这是我花了几天的时间去把Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

最近我才对这些路线做了一下新的更新,知识体系更全面了。

在这里插入图片描述

(2)Python学习视频

包含了Python入门、爬虫、数据分析和web开发的学习视频,总共100多个,虽然没有那么全面,但是对于入门来说是没问题的,学完这些之后,你可以按照我上面的学习路线去网上找其他的知识资源进行进阶。

在这里插入图片描述

(3)100多个练手项目

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了,只是里面的项目比较多,水平也是参差不齐,大家可以挑自己能做的项目去练练。

在这里插入图片描述

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注python)
img

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
img.cn/d66e3ad5592f4cdcb197de0dc0438ec5.png#pic_center)

(3)100多个练手项目

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了,只是里面的项目比较多,水平也是参差不齐,大家可以挑自己能做的项目去练练。

在这里插入图片描述

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化的资料的朋友,可以添加V获取:vip1024c (备注python)
[外链图片转存中…(img-8kqn33hk-1713450536614)]

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 29
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值