Python+Dlib活体检测实战:5分钟搞定眨眼、张嘴动作识别(附完整UI源码)
最近在开发一个需要验证用户真实性的小工具时,我遇到了一个挺有意思的问题:如何用最简单、最轻量的方法,让程序能判断摄像头前的是真人,而不是一张照片或者一段视频?这个问题在金融支付、门禁考勤甚至是一些互动娱乐应用里都很常见。传统的方案要么依赖昂贵的3D结构光硬件,要么需要训练复杂的深度学习模型,对于想快速验证想法或者构建轻量级应用的开发者来说,门槛有点高。
后来我发现,其实利用人脸关键点这个“老朋友”,配合一些简单的几何计算,就能实现一套相当可靠的配合式活体检测方案。核心思路就是让用户做几个简单的动作,比如眨眨眼、张张嘴,程序通过分析人脸关键点在这些动作中的变化规律,来判断操作者是否为活体。这种方法不依赖特定硬件,在普通RGB摄像头下就能工作,而且算法原理直观,代码实现也相对简单。
今天,我就带大家用Python和Dlib库,快速搭建一个能检测眨眼和张嘴动作的活体检测系统,并给它套上一个简洁的PyQt5图形界面。整个过程力求清晰直白,即使你是刚接触计算机视觉的Python爱好者,跟着步骤走,也能在短时间内看到成果。我们不会涉及复杂的模型训练,而是聚焦于如何利用现成的工具和清晰的逻辑,解决一个实际的问题。
1. 环境准备与核心工具介绍
工欲善其事,必先利其器。在开始编码之前,我们需要准备好运行环境。这个项目对硬件要求不高,一台普通的笔记本电脑就能胜任。软件方面,我们需要Python 3.7或以上版本(我个人习惯用3.8,稳定性很好),以及几个关键的库。
1.1 安装必要的Python库
打开你的终端(Windows上是CMD或PowerShell,macOS/Linux上是Terminal),我们通过pip命令来安装依赖。建议先创建一个独立的虚拟环境,避免包版本冲突。
# 创建并激活虚拟环境(可选,但推荐)
python -m venv liveness_env
# Windows:
liveness_env\Scripts\activate
# macOS/Linux:
source liveness_env/bin/activate
# 安装核心库
pip install dlib==19.24.0
pip install opencv-python==4.8.1.78
pip install PyQt5==5.15.9
pip install numpy==1.24.3
这里重点说一下dlib的安装。如果上述命令安装失败(特别是在Windows上),通常是因为缺少CMake或Visual C++编译工具。一个更稳妥的方法是使用预编译的wheel文件。你可以访问Python Extension Packages for Windows这个非官方站点,根据你的Python版本和系统位数(如cp38代表Python 3.8,win_amd64代表64位)下载对应的dlib的.whl文件,然后用pip install 下载的文件路径进行安装。
1.2 Dlib与人脸关键点模型
Dlib是一个包含机器学习算法的C++工具包,同时提供了Python接口。它在人脸检测和特征点定位上表现非常出色。我们主要用到它的两个功能:
- 人脸检测器 (
dlib.get_frontal_face_detector): 一个基于HOG(方向梯度直方图)特征和线性SVM(支持向量机)的检测器,速度快,适合实时应用。 - 人脸关键点预测器: 我们需要一个预训练模型来定位人脸上的68个关键点。Dlib官方提供了一个这样的模型,文件名为
shape_predictor_68_face_landmarks.dat。
你需要下载这个模型文件。可以从Dlib的官方源码仓库找到链接,或者直接在一些开源项目仓库里获取。下载后,将它放在你的项目目录下,比如一个叫做models的文件夹里。
这68个点按照固定的顺序分布,分别对应下巴、眉毛、眼睛、鼻子、嘴巴等轮廓。我们后续的眨眼、张嘴检测,就依赖于对这些点之间距离或比例的计算。
注意:确保模型文件路径正确,在代码中我们需要加载这个文件。如果路径不对,程序会报错。
2. 眨眼检测的原理与代码实现
眨眼检测是我们活体检测的第一个动作。其核心思想是计算眼睛的纵横比(Eye Aspect Ratio, EAR)。当眼睛睁开时,这个比值维持在一个相对稳定的数值;当眼睛闭合时,比值会急剧下降,趋近于零。
2.1 EAR(眼睛纵横比)的计算公式
我们选取每只眼睛的6个关键点(左眼是点37到42,右眼是点43到48)。EAR的定义如下:
EAR = (||p2 - p6|| + ||p3 - p5||) / (2 * ||p1 - p4||)
其中,p1到p6是眼睛轮廓上的六个点(从左到右)。分子计算的是眼睛垂直方向上两对点的距离之和,分母计算的是眼睛水平方向上的宽度。因此,EAR本质上反映了眼睛的“张开程度”。
下面是用Python和NumPy实现EAR计算的函数:
import numpy as np
def eye_aspect_ratio(eye):
"""
计算眼睛的纵横比 (EAR)
参数 eye: 一个包含6个(x, y)坐标的NumPy数组,对应一只眼睛的6个关键点。
"""
# 计算垂直方向的两组欧氏距离
A = np.linalg.norm(eye[1] - eye[5]) # p2 到 p6 的距离
B = np.linalg.norm(eye[2] - eye[4]) # p3 到 p5 的距离
# 计算水平方向的欧氏距离
C = np.linalg.norm(eye[0] - eye[3]) # p1 到 p4 的距离
# 计算EAR
ear = (A + B) / (2.0 * C)
return ear
2.2 实时视频流中的眨眼判断逻辑
有了EAR的计算方法,我们在视频的每一帧中就可以执行以下步骤:
- 使用Dlib检测人脸并获取68个关键点。
- 提取左眼和右眼的点坐标,分别计算它们的EAR。
- 取两只眼睛EAR的平均值作为当前帧的EAR值。
- 设定一个阈值(例如0.25)。当EAR低于这个阈值时,我们认为眼睛处于“闭合”状态。
- 为了过滤掉偶然的抖动或检测误差,我们引入一个连续帧计数器。只有当EAR连续低于阈值的帧数达到一个最小值(比如2帧),我们才认为发生了一次有效的眨眼动作。
这个逻辑的代码片段如下:
import dlib
import cv2
# 初始化检测器和预测器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("models/shape_predictor_68_face_landmarks.dat")
# 定义眼睛关键点的索引(基于68点模型)
LEFT_EYE_START, LEFT_EYE_END = 42, 48
RIGHT_EYE_START, RIGHT_EYE_END = 36, 42
# 阈值和计数器
EAR_THRESHOLD = 0.25 # EAR阈值,低于此值认为眼睛闭合
CONSECUTIVE_FRAMES = 2 # 判断为一次眨眼所需的连续闭合帧数
# 状态变量
blink_counter = 0 # 连续闭合帧计数器
total_blinks = 0 # 总眨眼次数
# 打开

&spm=1001.2101.3001.5002&articleId=152527200&d=1&t=3&u=01d19434410e4bd59e22f1bfed19580c)
3万+

被折叠的 条评论
为什么被折叠?



