利用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模拟登录12306的方法。分享给大家供大家参考。具体实现方法如下:#!/usr/bin/python# -*- c
- 前言今天给大家写一个个打地鼠小游戏,废话不多说直接开始~开发工具Python版本: 3.6.4相关模块:pygame模块;以及一些
- 一、创建数据库创建sqlite数据库的代码import sqlite3conn = sqlite3.connect("test.d
- 一、参照完整性参照完整性指的就是多表之间的设计,主要使用外键约束。多表设计: 一对多、多对多、一对一设计1.一对多关联主要语句:constr
- 我就废话不多说了,直接上代码吧!第一种def test1(): l = [] for i in range(1000
- 项目结构:运行效果:=========================================================代码部
- 这篇文章主要介绍了python global和nonlocal用法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学
- 在django中创建表,会自动创建一些django自带的表,先了解用户认证,认证登录 先要引用 ,from django.contrib i
- 在实际使用numpy时,我们常常会使用numpy数组的-1维度和”:”用以调用numpy数组中的元素。也经常因为数组的维度而感到困惑。总体来
- 前言对于使用Vue的前端而言,watch、computed和methods三个属性相信是不陌生的,是日常开发中经常使用的属性。但是对于它们的
- 举例写文章详情页面的时候的一个场景:首先更改文章详情中的 PV,然后读取文章详情,然后根据文章详情中文章 Id 查阅该文章评论和该文章作者信
- 什么是 channel 管道它是一个数据管道,可以往里面写数据,从里面读数据。channel 是 goroutine 之间数据通信桥梁,而且
- PHP的header函数 可以很少代码就能实现HTML代码中META 标签这里只说用 header函数来做页面的跳转1. HTML代码中页面
- 漏洞的产生原因代码层过滤不严。应用程序直接或间接使用了动态执行命令的危险函数,并且这个函数的运行参数是可控的系统的漏洞造成命令注入漏洞的本质
- 一、 腐蚀与膨胀1.1 腐蚀操作import cv2import numpy as npimg = cv2.imread('Data
- 视频地址我用20行代码,帮女神破解相册密码一、事情是这样的今早上班,公司女神小姐姐说,她去年去三亚旅游的照片打不开了好奇问了一下才知道。原来
- 问题1:解决没有NVSMI文件夹去英伟达官网下载显卡驱动,对显卡进行升级即可。问题2:nvidia-smi‘ 不是内部或
- 为了UED前端团队更好的协作开发同时提高项目编码质量,我们需要将Web前端使用工程化方式构建;目前需要一些简单的功能:  
- 圆形的绘制 :OpenCV中使用circle(img,center,radius,color,thickness=None,lineType
- 一、Mock介绍1、什么是Mock模拟接口接口Mock测试:在接口测试中,对于某些不容易构造或者不容易获取的接口,可以用一个模拟接口来代替2