利用Python实现眨眼计数器的示例代码
作者:一马归一码 发布时间:2021-04-16 10:39:53
一、前言
这几天宅在家里网上冲浪,无意间看到了一个比较有趣的项目,就是使用 Python 语言实现对视频中的人物的眨眼进行计数并描绘在图表中。我尝试了一下,发现是可以实现的,所以自己码了一遍代码并简单注释了一下,有兴趣的朋友可以浅试一下。
该项目大致效果如下:
Now, let's start!
二、实现步骤
对于创建项目文件夹配置环境以及如何安装第三方库这里就不再详细的介绍了,有不会的同学可以去翻我之前的文章或者其他博主的文章去了解学习吧,并不是很难。
1.第三方库
首先我们需要安装 cvzone(一个比较专业的计算机视觉包,在面部识别,手势、姿势检测中为我们提供了很多便利)。还有一个包是 mediapipe,我们将会使用它来实现面部检测网络,以便于对视频中的眼睛部位进行观察。
2.导入视频文件并播放
实现代码及效果如下:
import cv2
import cvzone
cap = cv2.VideoCapture('BlinkCounter.mp4')#获取需要检测的视频(添加视频路径即可,此处由于视频和Python文件在同一路径,直接调用即可)
while True:
success, img = cap.read()
img = cv2.resize(img, (640, 360)) #对图像尺寸进行调节
cv2.imshow("Image", img) #显示图像
cv2.waitKey(1)
3.让视频循环播放
我们要对视频中的眨眼次数进行计数,但通过上面的代码可以看出视频很快就播放结束了,所以我们采用检查视频帧数的方式,当达到视频的最后一帧时对其进行重置,达到循环播放视频的目的。代码如下:
#------------------------------------------------------------
#检查当前帧数是否等于视频的总体帧数,如果相等,将播放帧数重置为0
#------------------------------------------------------------
if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
4.创建面部检测器
该步骤需要使用到 cvzone 中的相应模块来实现,具体代码及注释如下:
import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector #调用面部检测模块
cap = cv2.VideoCapture('BlinkCounter.mp4')#获取需要检测的视频(添加视频路径即可,此处由于视频和Python文件在同一路径,直接调用即可)
detector = FaceMeshDetector(maxFaces = 1)#创建人脸网络检测器,检测面部数量为1
while True:
#------------------------------------------------------------
#检查当前帧数是否等于视频的总体帧数,如果相等,将播放帧数重置为0
#------------------------------------------------------------
if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
#------------------------------------------------------------
success, img = cap.read()
img, faces = detector.findFaceMesh(img)#绘制人脸网络
img = cv2.resize(img, (640, 360)) #对图像尺寸进行调节
cv2.imshow("Image", img) #显示图像
cv2.waitKey(1)
得到的结果如下:
5.对眼睛周围的点进行标记
由于面部检测器是对面部用点进行标记的,所以我们需要找到那些眼睛周围的点并将它们使用特殊的点来进行标记,从而达到检测眼睛闭合与张开的目的,相应的点数以及代码如下:
idList = [22, 23, 24, 26, 110, 157, 158, 159, 160, 161, 130, 243]#面部检测器中眼眶周围的像素点
color = (0, 0, 255)#将颜色设置为红色
#------------------------------------------------------------
#检测到面部时将面部的关于眼眶的点用圆圈表示出来,并填补完整
#------------------------------------------------------------
if faces:
face = faces[0]
for id in idList:
cv2.circle(img, face[id], 5, color, cv2.FILLED)
得到的效果如下,可以看出,已经对眼眶进行了标记:
我们可以对面部检测网络进行设置,让其他的一些点不再显示出来,只关注我们的目标点,具体操作方式是只需要在函数中添加一个参数即可,效果如下:
img, faces = detector.findFaceMesh(img, draw = False)#绘制人脸检测网络,将参数 draw 修改为 False 即可抹去其他的不必要的点
6.观察眼睛宽度和长度变化并进行计数
如果单纯的靠上下眼皮的变化来检测是否眨眼会造成判断错误,所以我们需要结合眼睛长度和宽度之比进行判断。将这项数据的变化趋势绘制在一个窗口中,就会使得我们的观察更加明显,得到的效果也将更加优良。具体代码如下:
#-------------------------------------------------------------
#使用眼眶周围不同的点之间的距离以及眼睛宽度和长度的对比进行眨眼计数
#-------------------------------------------------------------
leftUp = face[159]#定义不同部位的像素点
leftDown = face[23]
leftLeft = face[130]
leftRight = face[243]
lenghtVer, _ = detector.findDistance(leftUp, leftDown)#得到眼睛宽度
lenghtHor, _ = detector.findDistance(leftLeft, leftRight)#得到眼睛长度
cv2.line(img, leftUp, leftDown, (0, 200, 0), 3)#绘制与眼睛等宽的线段
cv2.line(img, leftLeft, leftRight, (0, 200, 0), 3)#绘制与眼睛等长的线段
ratio = int((lenghtVer / lenghtHor) * 100)#得到的数据并进行标准化,得到比率值
ratioList.append(ratio)#使用比率值填补列表
#------------------------------------------------------------------
#从之前的一共三个比率中得到平均值,如果比率数目大于3将会删去前面的比率值
#------------------------------------------------------------------
if len(ratioList) > 3:
ratioList.pop(0)
ratioAvg = sum(ratioList) / len(ratioList)#得到比率平均值
#------------------------------------
#通过比率平均值的变化对眨眼次数进行计数
#------------------------------------
if ratioAvg < 35 and counter == 0:
blinkCounter += 1#变化一次,计数器加一
color = (0, 200, 0)
counter = 1
if counter != 0:
counter += 1
if counter > 10:
counter = 0
color = (255, 0, 255)
#-----------------------------
#编写文本框来记录眨眼的总体次数
#------------------------------
cvzone.putTextRect(img, f'Blink Count: {blinkCounter}', (50, 250),
12, colorR = color)
imgPlot = plotY.update(ratioAvg, color)
img = cv2.resize(img, (400, 640)) # 对图像尺寸进行调节
imgStack = cvzone.stackImages([img, imgPlot], 2, 1)#将两幅图像放到一起,叠放为2列图像
else:
img = cv2.resize(img, (400, 640)) # 对图像尺寸进行调节
imgStack = cvzone.stackImages([img, img], 2, 1)
通过以上步骤大致就能实现眨眼计数了。
三、整体代码
整体代码如下,已经添加了注释,如果有解释的不清楚的地方可以在评论区交流。
import cv2
import cvzone
from cvzone.FaceMeshModule import FaceMeshDetector
from cvzone.PlotModule import LivePlot
cap = cv2.VideoCapture('BlinkCounter.mp4')#获取需要检测的视频(添加视频路径即可,此处由于视频和Python文件在同一路径,直接调用即可)
detector = FaceMeshDetector(maxFaces = 1)#创建人脸网络检测器,检测面部数量为1
plotY = LivePlot(640, 640, [20, 50], invert = True)#创建窗口来绘制数据的变化
idList = [22, 23, 24, 26, 110, 157, 158, 159, 160, 161, 130, 243]#面部检测器中眼眶周围的像素点
ratioList = []#创建一个空的比率列表
blinkCounter = 0
counter = 0#避免每一个帧节进行一次计数
color = (0, 0, 255)#将颜色设置为红色
while True:
#------------------------------------------------------------
#检查当前帧数是否等于视频的总体帧数,如果相等,将播放帧数重置为0
#------------------------------------------------------------
if cap.get(cv2.CAP_PROP_POS_FRAMES) == cap.get(cv2.CAP_PROP_FRAME_COUNT):
cap.set(cv2.CAP_PROP_POS_FRAMES, 0)
success, img = cap.read()#读取到的视频
img, faces = detector.findFaceMesh(img, draw = False)#绘制人脸检测网络
#------------------------------------------------------------
#检测到面部时将面部的关于眼眶的点用圆圈表示出来,并填补完整
#------------------------------------------------------------
if faces:
face = faces[0]
for id in idList:
cv2.circle(img, face[id], 5, color, cv2.FILLED)
#-------------------------------------------------------------
#使用眼眶周围不同的点之间的距离以及眼睛宽度和长度的对比进行眨眼计数
#-------------------------------------------------------------
leftUp = face[159]#定义不同部位的像素点
leftDown = face[23]
leftLeft = face[130]
leftRight = face[243]
lenghtVer, _ = detector.findDistance(leftUp, leftDown)#得到眼睛宽度
lenghtHor, _ = detector.findDistance(leftLeft, leftRight)#得到眼睛长度
cv2.line(img, leftUp, leftDown, (0, 200, 0), 3)#绘制与眼睛等宽的线段
cv2.line(img, leftLeft, leftRight, (0, 200, 0), 3)#绘制与眼睛等长的线段
ratio = int((lenghtVer / lenghtHor) * 100)#得到的数据并进行标准化,得到比率值
ratioList.append(ratio)#使用比率值填补列表
#------------------------------------------------------------------
#从之前的一共三个比率中得到平均值,如果比率数目大于3将会删去前面的比率值
#------------------------------------------------------------------
if len(ratioList) > 3:
ratioList.pop(0)
ratioAvg = sum(ratioList) / len(ratioList)#得到比率平均值
#------------------------------------
#通过比率平均值的变化对眨眼次数进行计数
#------------------------------------
if ratioAvg < 35 and counter == 0:
blinkCounter += 1#变化一次,计数器加一
color = (0, 200, 0)
counter = 1
if counter != 0:
counter += 1
if counter > 10:
counter = 0
color = (255, 0, 255)
#-----------------------------
#编写文本框来记录眨眼的总体次数
#------------------------------
cvzone.putTextRect(img, f'Blink Count: {blinkCounter}', (50, 250),
12, colorR = color)
imgPlot = plotY.update(ratioAvg, color)
img = cv2.resize(img, (400, 640)) # 对图像尺寸进行调节
imgStack = cvzone.stackImages([img, imgPlot], 2, 1)#将两幅图像放到一起,叠放为2列图像
else:
img = cv2.resize(img, (400, 640)) # 对图像尺寸进行调节
imgStack = cvzone.stackImages([img, img], 2, 1)
img = cv2.resize(img, (400, 640)) #对图像尺寸进行调节
cv2.imshow("Image", imgStack)
cv2.waitKey(1)
来源:https://blog.csdn.net/qq_52309640/article/details/122782136
猜你喜欢
- 通常来说,一个Python程序可以从键盘读取输入,也可以从文件读取输入;而程序的结果可以输出到屏幕上,也可以保存到文件中便于以后使用。本文就
- 感想我们在用jupyter notebook的时候,经常需要可视化一些东西,尤其是一些图像,我这里给个sample code环境opencv
- 1. Python字典的clear()方法(删除字典内所有元素)#!/usr/bin/python# -*- coding: UTF-8 -
- 数据聚合与分组运算对数据集进行分组并对各组应用一个函数(无论是聚合还是转换),通常是数据分析工作中的重要环节。在将数据集加载、融合、准备好之
- 第一种情况:有RAID,还需要做数据库备份吗?回答:需要。有了RAID,万一部份磁盘损坏,可以修复数据库,有的情况下数据库甚至可以继续使用。
- 代码如下:CREATE FUNCTION dbo.f_splitstr( @str varchar(8000) )RETURNS
- 从这一章开始进入正式的算法学习。首先我们学习经典而有效的分类算法:决策树分类算法。1、决策树算法决策树用树形结构对样本的属性进行分类,是最直
- ASP与MySQL的连接ASP和MySQL连接目前有两种方法:一种方法是使用MySQLX之类的组件,不过这种连接方法需要支付一定的费用;另外
- 前言对程序员来说,‘python’ 和’python ’看起
- 本文实例讲述了python实现获取序列中最小的几个元素。分享给大家供大家参考。具体方法如下:import heapq import rand
- Pyppeteer简介Puppeteer 是 Google 基于 Node.js 开发的一个工具,有了它我们可以通过 JavaScript
- mapmap(funcname, list)python的map 函数使得函数能直接以list的每个元素作为参数传递到funcname中,
- 知道两点坐标,怎么计算两点方向的方位角?答:首先计算坐标增量dx,dy(两个对应坐标分量相减,终点的减始点的)。若dx,dy中有一个为零时,
- python继承,python丰富的类因为继承而变得多姿多彩,如果语言不支持继承,那么类就没什么优势。1、首先我们来定义两个类一个dog类,
- MySQL使用环境变量TMPDIR的值作为保存临时文件的目录的路径名。如果未设置TMPDIR,MySQL将使用系统的默认值,通常为/tmp、
- def report_hook(count, block_size, total_size):... &n
- 简单的模型例如线性回归,LR等模型非常易于解释,但在实际应用中的效果却远远低于复杂的梯度提升树模型以及神经网络等模型。现在大部分互联网公司的
- 一、实验目标1、使用 K-means 模型进行聚类,尝试使用不同的类别个数 K,并分析聚类结果。2、按照 8:2 的比例随机将数据划分为训练
- 最近心血来潮加上有点闲情,动手写了第一个JavaScript版的俄罗斯方块Easy Tetris.先上Easy Tetris俄罗斯方块游戏截
- 本文主要是总结利用tensorflow实现迁移学习的基本步骤。所谓迁移学习,就是将上一个问题上训练好的模型通过简单的调整使其适用于一个新的问