openCV和python基于dlib库实现眨眼/睁闭眼检测--亲测高效

1、检测方法

(1)方法

与用于计算眨眼的传统图像处理方法不同,该方法通常涉及以下几种组合:

1、眼睛定位。
2、阈值找到眼睛的白色。
3、确定眼睛的“白色”区域是否消失了一段时间(表示眨眼)。
相反,眼睛长宽比是一种更为优雅的解决方案,它涉及基于眼睛面部轮廓之间的距离之比的非常简单的计算。

这种眨眼检测方法快速,高效且易于实现。

(2)眼睛纵横比

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

这也意味着我们可以通过了解特定面部部分的索引来提取特定面部结构:

在眨眼检测方面,我们只对两套面部结构感兴趣:眼睛。

每只眼睛都由6 (x,y)坐标表示,从坐标的左角开始(就像您在看那个人一样),然后沿该区域的其余部分顺时针旋转:
在这里插入图片描述

基于此图像,我们应该取消关键点:

这些坐标的宽度和高度之间存在关系。

根据Soukupová和Čech在2016年的论文《使用面部地标进行实时眼睛眨眼检测》的工作,我们可以得出一个反映这种关系的方程,称为眼睛纵横比(EAR):

在这里插入图片描述

其中p1,…,p6是2D面部界标位置。

该方程的分子计算垂直眼界标之间的距离,而分母计算水平眼界标之间的距离,对分母进行适当加权,因为只有一组水平点,但有两组垂直点。

(3)眨眼检测标准

睁开眼睛时眼睛的纵横比大约是恒定的,但是当眨眼时眼睛的纵横比会迅速降至零。

使用这个简单的方程式,我们可以避免使用图像处理技术,而只需依靠眼睛界标距离的比率来确定一个人是否在眨眼。

为了更清楚地说明这一点,请看下图:

在这里插入图片描述
图: 左上:当眼睛睁开时,眼睛界标的可视化。右上:闭上眼睛时的眼睛地标。底部:绘制随时间变化的眼睛纵横比。眼睛纵横比的下降表示眨眼

在左上角,我们的眼睛完全张开-此处的眼睛长宽比会很大(r),并且随着时间的推移会相对保持恒定。

但是,一旦眨眼(右上角),眼睛的宽高比就会急剧下降,接近零。

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

2、基于opencv的面部标志检测

(1)软硬件需求

我实在 基于英伟达定制的jetson nano ubuntu18.04系统上跑的,以下是我的版本信息,理论上ubuntu 和MacOS都跑的起来 关键opencv和dlib以及相关库安装好,相关安装自行解决。

在这里插入图片描述

要访问我们在磁盘上的视频文件(FileVideoStream )或内置的网络摄像头/ USB摄像头/ Raspberry Pi摄像头模块(视频流),我们需要使用我的imutils库(一组便捷函数)来简化OpenCV的使用。

如果没有安装imutils在系统上(或者如果您使用的是旧版本),请确保使用以下命令进行安装/升级:

pip3 install --upgrade imutils

(2)代码详解

首先,打开一个新文件并命名 detect_blinks.py。从那里,插入以下代码:

在这里插入图片描述

接下来,我们将定义 eye_aspect_ratio 功能

在这里插入图片描述

该函数接受单个必需参数,即给定脸部界标的(x,y)-坐标眼睛 。
第16和17行计算两组垂直眼界标之间的距离,而第21行计算水平眼界标之间的距离。

最后,第24行结合了分子和分母,以得出最终的眼睛长宽比,如上面的图4中所述。

然后,第27行将眼睛的宽高比返回给调用函数。

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

在这里插入图片描述
我们的 detect_blinks。py 脚本需要一个命令行参数,然后是第二个可选参数:

–shape_predictor:这是dlib预先训练的面部标志检测器的路径。

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

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

在这里插入图片描述

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

如果眼睛的宽高比下降到某个阈值以下,然后又上升到该阈值以上,那么我们将注册“眨眼”- EYE_AR_THRESH 是此阈值。我们将其默认设置为0. 3 因为这对我的应用程序最有效,但是您可能需要针对自己的应用程序进行调整。

然后我们有一个重要的常数, EYE_AR_CONSEC_FRAME —此值设置为 3 表示连续三个帧的眼睛长宽比小于EYE_AR_THRESH 必须进行眨眼才能注册眨眼。

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

第44和45行初始化两个计数器。柜台 是眼睛长宽比小于的连续帧的总数 EYE_AR_THRESH 尽管 全部的 是脚本运行期间发生的总闪烁次数。

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

在这里插入图片描述

dlib库使用预训练的面部检测器,该检测器基于对“定向梯度直方图+线性SVM”方法的修改,用于对象检测。

然后,我们在第51行初始化实际的面部界标预测变量。

dlib生成的面部标志遵循一个可索引列表

在这里插入图片描述

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

在这里插入图片描述

使用这些索引,我们将能够轻松提取眼睛区域。

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

在这里插入图片描述

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

否则,如果要使用内置网络摄像头或USB摄像头,请取消注释第62行。

对于Raspberry Pi相机模块,请取消注释第63行。

如果你有没有注释或者 行62或63号线,然后取消注释行64以及以表明你是不是从磁盘读取视频文件。

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

在这里插入图片描述

在第68行,我们开始循环播放视频流中的帧。

如果我们正在访问视频文件流,并且视频中没有剩余的帧,那么我们将退出循环(第71和72行)。

第77行从视频流中读取下一帧,然后调整其大小并将其转换为灰度(第78和79行)。

然后,我们通过dlib的内置面部检测器在82行的灰度帧中检测面部。

现在,我们需要遍历框架中的每个面孔,然后对每个面孔应用脸部界标检测:
在这里插入图片描述

第89行确定了面部区域的面部界标,而第90行将这些(x,y)坐标转换为NumPy数组。

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

从那里,我们在第96和97行上计算每只眼睛的眼睛纵横比。

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

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

在这里插入图片描述

至此,我们已经计算了(平均)眼睛长宽比,但实际上还没有确定是否发生眨眼,这将在下一部分中解决:在这里插入图片描述

第111行进行检查以查看眼睛长宽比是否低于眨眼阈值-如果是,则增加表示眨眼发生的连续帧数(第112行)。

否则,线116处理眼睛宽高比不低于眨眼阈值的情况。

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

如果检查通过,我们将增加 全部的 眨眼次数(第120行)。

然后,我们重置连续闪烁的次数 柜台 (第123行)。

我们的最终代码块仅用于在输出帧上绘制眨眼次数,并显示当前的眼睛长宽比:

在这里插入图片描述
要查看我们的眨眼检测器的运行情况,请继续进行下一部分。

(3)眨眼检测效果

眨眼检测结果

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

python detect_blinks.py \
	--shape-predictor shape_predictor_68_face_landmarks.dat \
	--video blink_detection_demo.mp4

要访问我的内置网络摄像头,我执行了以下命令(注意取消对正确注释的注释)。 视频流 类,如上所述):

python detect_blinks.py \
	--shape-predictor shape_predictor_68_face_landmarks.dat

这里我们测试一段摄像头和一段网上下载的video:

在这里插入图片描述

在这里插入图片描述

3、常见问题

(1) 参数设置问题

在这里插入图片描述

后面未设置参数
参考
要将眨眼检测器应用于示例视频,只需执行以下命令:

python detect_blinks.py \
	--shape-predictor shape_predictor_68_face_landmarks.dat \
	--video blink_detection_demo.mp4

要访问我的内置网络摄像头,我执行了以下命令(注意取消对正确注释的注释)。 视频流 类,如上所述):

python detect_blinks.py \
	--shape-predictor shape_predictor_68_face_landmarks.dat

(2)文件路径不对、摄像头未能启动

在这里插入图片描述
检查文件路径、检查示例视频源是否能正常播放解析,尝试换一段示例视频。

4、源码分享链接:

点击代码下载.

  • 4
    点赞
  • 79
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 6
    评论
### 回答1: MyBatis是一个流行的持久层框架,它可以将SQL语句和Java对象之间的映射关系定义在XML文件或注解中,并提供了丰富的查询语言和灵活的参数绑定方式。在使用MyBatis进行数据操作时,有时会遇到插入唯一异常的问题,下面让我们一起来看看如何解决这个问题。 1. 异常描述 当我们向数据插入一条记录时,如果违反了唯一性约束,就会抛出插入唯一异常,如下所示: ``` ### Error updating database. Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'xxx' for key 'name_unique' ### The error may involve com.example.mapper.UserMapper.insert-Inline ### The error occurred while setting parameters ### SQL: insert into user(name, age) values (?, ?) ### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry 'xxx' for key 'name_unique' ``` 其中,'xxx'表示违反唯一性约束的值,'name_unique'表示违反唯一性约束的字段名。 2. 解决方法 为了避免插入唯一异常,我们可以采取以下两种解决方法: 2.1 使用INSERT IGNORE语句 在MySQL中,可以使用INSERT IGNORE语句来向表中插入记录,如果遇到违反唯一性约束的情况,就会忽略该记录,而不是抛出异常。因此,我们可以将MyBatis的插入语句改为INSERT IGNORE语句,如下所示: ``` <insert id="insertUser" parameterType="com.example.entity.User"> INSERT IGNORE INTO user(name, age) VALUES (#{name}, #{age}) </insert> ``` 2.2 使用ON DUPLICATE KEY UPDATE语句 在MySQL中,还可以使用ON DUPLICATE KEY UPDATE语句来向表中插入记录,如果遇到违反唯一性约束的情况,就会更新该记录,而不是抛出异常。因此,我们可以将MyBatis的插入语句改为ON DUPLICATE KEY UPDATE语句,如下所示: ``` <insert id="insertUser" parameterType="com.example.entity.User"> INSERT INTO user(name, age) VALUES (#{name}, #{age}) ON DUPLICATE KEY UPDATE age = #{age} </insert> ``` 其中,ON DUPLICATE KEY UPDATE语句指定了更新操作的字段和值,这里我们只更新了年龄字段。 以上就是解决MyBatis插入唯一异常的两种方法,根据具体情况选择适合自己的方法即可。 ### 回答2: 在使用MyBatis进行插入操作时,可能会遇到插入唯一异常。该异常通常是由于数据表的唯一约束导致的。 当我们向数据表插入数据时,如果违反了唯一约束,数据将抛出异常,表示插入失败。常见的唯一约束有主键约束、唯一索引等。 解决这个问题的方法有两种: 1. 在程序中进行唯一性校验:在执行插入操作之前,可以先查询数据中是否已存在相同的数据。如果已存在,则不进行插入操作,避免了唯一异常的发生。这种方法比较消耗数据资源,但可以保证数据的唯一性。 2. 使用数据的"insert ignore"或"insert on duplicate key update"语句:这种方法是在插入操作时,使用特殊的语句来处理唯一异常。"insert ignore"语句会即使发生唯一异常,也不会抛出异常,而是直接忽略这条插入数据;"insert on duplicate key update"语句则是在发生唯一异常时,执行更新操作。这种方法相对较为简洁高效,但需要根据数据的不同进行调整。 总结来说,解决MyBatis插入唯一异常的方法有多种,可以通过程序中进行唯一性校验,或者使用特殊的数据插入语句来处理。需要根据具体情况选择最合适的方法来解决唯一异常问题。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

·菜鸟看世界

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值