news 2026/10/16 12:48:40

Python+OpenCV实时人眼识别与眨眼检测:基于EAR的疲劳监测源码实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python+OpenCV实时人眼识别与眨眼检测:基于EAR的疲劳监测源码实战

简介:这份资源面向计算机视觉初学者与需要落地人脸眼部状态检测的开发者,提供基于Python与OpenCV的实时人眼识别、眨眼检测和闭眼检测完整实现。代码在Ubuntu环境下开发运行,借助Haar级联分类器定位眼睛区域,并通过连续帧差异分析判断眨眼与持续闭眼状态,可作为课程设计、疲劳监测原型或视觉入门练手项目。压缩包共61个文件,约75.34MB,以37个py源码文件为核心,配合png、jpg示例图、dat预训练模型、pdf教程及md说明等,覆盖从环境配置到代码原理的讲解,目录结构清晰便于按模块查阅。目前已有4345人学习下载,适合希望快速跑通眼部状态检测流程、理解帧差与特征分析思路的读者参考复用。

1. 从摄像头到 EAR:这套 Python+OpenCV 源码到底能跑出什么

很多人第一次做疲劳驾驶或在线课堂注意力检测,都会卡在同一个地方:人脸框出来了,眼睛在哪、什么时候眨、闭眼持续了多久,全靠猜。这套「Python+OpenCV 实时人眼识别+眨眼检测+闭眼检测」源码,解决的正是这个从「看到脸」到「判断眼睛状态」的最后一公里。它用 OpenCV 抓摄像头帧,用 dlib 的 68 点人脸关键点定位眼部区域,再通过 EAR(Eye Aspect Ratio,眼睛纵横比)把「睁眼/闭眼」变成一个可阈值判断的数值。适合做课程设计、疲劳监测原型、网课专注度统计的从业者,也适合刚学完 python 基础、想找一个能跑起来的 opencv 图像处理项目练手的人。整套逻辑不依赖深度学习训练,CPU 上就能实时跑,这是它比很多「大模型方案」更接地气的地方。

2. 环境搭建与依赖选型:为什么是 dlib 而不是纯 Haar

2.1 三个核心库的分工与版本边界

这套源码的依赖链其实很短:opencv-python 负责视频采集和图像预处理,dlib 负责关键点回归,numpy 负责 EAR 的向量计算。很多人一上来就pip install opencv-python dlib,结果在 Windows 上编译 dlib 直接翻车,因为 dlib 的源码编译需要 CMake 和 C++ 编译环境。常见做法是先用 conda 装 dlib,或者直接下预编译的 whl 包。

# 推荐用 conda 建独立环境,避免污染系统 python conda create -n eye_detect python=3.8 conda activate eye_detect # opencv 用 pip 装即可,dlib 走 conda 预编译 pip install opencv-python numpy conda install -c conda-forge dlib

这里 python 3.8 是个稳妥选择,dlib 和 opencv 的兼容轮子最全。如果你坚持用 pip 装 dlib,Windows 下大概率会遇到CMake must be installed或Microsoft Visual C++ 14.0 is required,这不是代码问题,是编译链问题。参数上,opencv-python 选 4.x 任意小版本都行,dlib 选 19.22 以上,关键点模型才稳定。

2.2 关键点模型文件的获取与放置

dlib 的 68 点检测靠一个预训练模型shape_predictor_68_face_landmarks.dat,这个文件不在 pip 包里,必须单独下载。源码包里一般会附带,如果没有,去 dlib 官方模型页拿。放的位置很关键,很多人RuntimeError: Unable to open shape_predictor_68_face_landmarks.dat就是路径写错。

import dlib import os # 用相对路径时,确保工作目录和模型文件同级 MODEL_PATH = os.path.join(os.path.dirname(__file__), "shape_predictor_68_face_landmarks.dat") if not os.path.exists(MODEL_PATH): raise FileNotFoundError(f"模型文件缺失: {MODEL_PATH}") detector = dlib.get_frontal_face_detector() predictor = dlib.shape_predictor(MODEL_PATH)

逻辑说明:get_frontal_face_detector()返回的是基于 HOG 的人脸检测器,比 Haar 级联稳,但比 CNN 慢一点,CPU 上够用。shape_predictor加载模型后,输入人脸框,输出 68 个坐标点。参数上,模型文件约 99MB,别用 git 直接传,容易超限。

2.3 摄像头采集与帧率控制

实时检测最怕卡顿,采集环节要设对分辨率和缓冲。

import cv2 cap = cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) cap.set(cv2.CAP_PROP_FPS, 30) if not cap.isOpened(): raise RuntimeError("摄像头打开失败,检查索引或驱动") while True: ret, frame = cap.read() if not ret: break frame = cv2.flip(frame, 1) # 镜像,符合直觉 # 后续检测逻辑

640x480 是实时性和精度的平衡点,再高 CPU 占用明显上升。cv2.flip镜像后,左右眼索引不会乱,因为 dlib 的点序是固定的。注意cap.read()返回 False 时要 break,否则会死循环。

3. EAR 算法落地:从 68 点到眨眼计数的完整链路

3.1 眼睛关键点索引与 EAR 公式

dlib 68 点里,左眼是 36-41,右眼是 42-47,各 6 个点。EAR 的定义是垂直距离和水平距离的比值:

import numpy as np from scipy.spatial import distance as dist def eye_aspect_ratio(eye): # eye 是 6 个 (x, y) 点,顺序为顺时针 # 垂直距离:上下两组点 A = dist.euclidean(eye[1], eye[5]) B = dist.euclidean(eye[2], eye[4]) # 水平距离:左右眼角 C = dist.euclidean(eye[0], eye[3]) ear = (A + B) / (2.0 * C) return ear

逻辑说明:睁眼时 EAR 约 0.25-0.35,闭眼时降到 0.1 以下。A、B 是上下眼睑的距离,C 是眼角距离,除以 2C 做归一化,抵消人脸远近影响。参数上,dist.euclidean来自 scipy,如果不想装 scipy,用 numpy 手写np.linalg.norm也行。

3.2 眨眼判定:阈值、连续帧与计数器

单帧 EAR 低于阈值不算眨眼,可能是噪声。标准做法是连续 N 帧低于阈值才计一次眨眼。

EYE_AR_THRESH = 0.25 # EAR 阈值 EYE_AR_CONSEC_FRAMES = 3 # 连续帧数 COUNTER = 0 TOTAL = 0 def update_blink(ear): global COUNTER, TOTAL if ear < EYE_AR_THRESH: COUNTER += 1 else: if COUNTER >= EYE_AR_CONSEC_FRAMES: TOTAL += 1 COUNTER = 0 return TOTAL

逻辑说明:COUNTER记录连续低 EAR 帧数,一旦 EAR 回升且之前累计超过 3 帧,判定为一次完整眨眼。阈值 0.25 是经验值,戴眼镜或光线暗时要下调到 0.2。连续帧数 3 对应 30fps 下约 100ms,符合真实眨眼时长。

3.3 闭眼检测与疲劳预警的衔接

闭眼检测和眨眼共用 EAR,区别在持续时间。眨眼是瞬时,闭眼是持续低 EAR。

CLOSED_EYE_FRAMES = 15 # 约 0.5 秒 closed_counter = 0 def check_drowsy(ear): global closed_counter if ear < EYE_AR_THRESH: closed_counter += 1 if closed_counter >= CLOSED_EYE_FRAMES: return True # 触发疲劳预警 else: closed_counter = 0 return False

逻辑说明:15 帧在 30fps 下是 0.5 秒,超过这个时长基本可判定为闭眼而非眨眼。参数可按场景调,驾驶场景建议 0.4-0.6 秒,网课场景可放宽到 1 秒。返回 True 后可以接蜂鸣器或日志。

3.4 把检测结果画回画面

可视化是调试的关键,不然你不知道点抓没抓准。

from scipy.spatial import ConvexHull def draw_eye(frame, eye_points): hull = ConvexHull(eye_points) hull_points = eye_points[hull.vertices] cv2.drawContours(frame, [hull_points], -1, (0, 255, 0), 1) return frame # 主循环里 left_eye = np.array([(shape.part(i).x, shape.part(i).y) for i in range(36, 42)]) right_eye = np.array([(shape.part(i).x, shape.part(i).y) for i in range(42, 48)]) ear = (eye_aspect_ratio(left_eye) + eye_aspect_ratio(right_eye)) / 2.0 frame = draw_eye(frame, left_eye) frame = draw_eye(frame, right_eye) cv2.putText(frame, f"EAR: {ear:.2f}", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)

逻辑说明:ConvexHull把 6 个点包成凸多边形,画出来就是眼眶轮廓。左右眼 EAR 取平均,比单眼稳。putText把 EAR 实时显示,方便你调阈值。

4. 避坑与排查:那些让检测失效的细节

4.1 现象:EAR 一直高于阈值,闭眼也不降

原因:关键点没对准眼睛,常见于侧脸、刘海遮挡或模型文件版本不对。解决:先单独跑一帧,把 68 点全画出来,确认 36-47 落在眼睛上。如果点飘到眉毛,说明人脸框检测偏了,可以调detector的upsample参数,或换 CNN 检测器。

4.2 现象:眨眼计数疯狂累加

原因:阈值太高或连续帧数太小,噪声被当成眨眼。解决:把EYE_AR_THRESH从 0.25 降到 0.2,EYE_AR_CONSEC_FRAMES从 3 提到 4-5。同时检查光照,逆光会让 EAR 整体偏低。

4.3 现象:摄像头帧率掉到个位数

原因:每帧都跑 dlib 检测,CPU 吃满。解决:不要每帧都检测人脸,可以隔帧检测,中间帧用上一帧的关键点做光流跟踪。或者把分辨率降到 320x240,检测完再放大显示。

4.4 现象:ModuleNotFoundError: No module named 'cv2'

原因:装的是 opencv-python 但环境不对,或者装了 opencv-contrib 冲突。解决:pip uninstall opencv-python opencv-contrib-python后只装opencv-python。conda 环境里确认which python指向当前环境。

4.5 现象:模型文件加载报错但文件明明存在

原因:路径含中文或空格,dlib 的 C++ 层读不了。解决:把模型文件和脚本放在纯英文路径下,用os.path.abspath打印真实路径确认。

5. 进阶技巧:让这套源码从 demo 变成能用的工具

5.1 用 EAR 基线自适应替代固定阈值

固定阈值在不同人、不同光线下表现差异很大。更稳的做法是前 3 秒采集睁眼 EAR 均值作为基线,阈值取基线的 70%。

baseline_samples = [] baseline_ready = False def adaptive_threshold(ear): global baseline_ready if not baseline_ready: baseline_samples.append(ear) if len(baseline_samples) >= 90: # 约 3 秒 baseline = np.mean(baseline_samples) baseline_ready = True return baseline * 0.7 return 0.25 # 默认值 return baseline * 0.7

逻辑说明:90 帧在 30fps 下是 3 秒,足够采集自然睁眼状态。基线乘 0.7 是经验系数,闭眼时 EAR 通常降到基线的 40%-60%。这个改动能让同一套代码适应不同人,不用手动调参。

5.2 双眼一致性校验排除误检

单眼被遮挡时,另一只眼的 EAR 会误导判断。加一个双眼差值校验:

def is_valid_eye_state(left_ear, right_ear): # 双眼 EAR 差异过大,说明一只眼被遮挡或检测异常 if abs(left_ear - right_ear) > 0.1: return False return True

逻辑说明:正常睁眼或闭眼时,双眼 EAR 接近。差值超过 0.1 时,大概率是单眼关键点飘了,这一帧不参与眨眼计数,避免误判。

5.3 用队列平滑 EAR 曲线

原始 EAR 有抖动,用固定长度队列做滑动平均,曲线更干净。

from collections import deque ear_history = deque(maxlen=5) def smooth_ear(ear): ear_history.append(ear) return np.mean(ear_history)

逻辑说明:deque的maxlen=5自动丢弃旧值,滑动窗口平均能压掉单帧噪声,代价是引入约 5 帧延迟,实时性要求极高的场景可以降到 3。

5.4 验证方法:用录制视频回放代替实时调试

实时调参很痛苦,因为眨眼瞬间就过去了。把一段包含多次眨眼的视频存下来,用cv2.VideoCapture("test.mp4")回放,逐帧打印 EAR,你就能清楚看到阈值该设在哪。

cap = cv2.VideoCapture("blink_test.mp4") frame_idx = 0 while True: ret, frame = cap.read() if not ret: break # 检测逻辑同上 print(f"frame {frame_idx}, EAR={ear:.3f}") frame_idx += 1

逻辑说明:回放视频能复现,方便对比不同阈值的效果。建议录一段正常眨眼、一段闭眼 2 秒、一段侧脸,覆盖主要边界。

5.5 一个我踩过的坑

最早我把EYE_AR_CONSEC_FRAMES设成 1,结果每帧 EAR 波动都计一次眨眼,一分钟跑出 200 多次。后来改成 3 并加了双眼校验,才稳定在正常范围。从那以后我每次调这类阈值,都强制先用录制视频跑一遍全流程,确认计数曲线合理再上实时。希望这套源码和上面的参数思路,能帮你少走几段弯路。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 12:46:37

亚马逊广告接入 ChatGPT 后,卖家该如何布局 AI 电商营销?

随着生成式 AI 不断进入电商消费场景&#xff0c;广告流量的获取方式也在发生变化。2026 年 9 月 10 日&#xff0c;亚马逊广告宣布与 OpenAI 建立合作&#xff0c;支持广告主将亚马逊广告活动拓展至 ChatGPT。目前&#xff0c;该合作仍处于美国部分广告主参与的试点阶段。与此…

作者头像 李华
网站建设 2026/10/16 12:48:03

玉米病害图像分类:2800张标注数据实战与PyTorch训练流程

简介&#xff1a;这套玉米病害图像分类数据集聚焦深度学习图像分类方向&#xff0c;包含约2800张已标注的玉米叶片图片&#xff0c;覆盖尾孢叶斑灰、普通锈蚀等4个类别&#xff0c;专门服务于需要训练数据支撑的CNN分类实验、本科毕设或入门级视觉项目。压缩包共计2000个文件&a…

作者头像 李华
网站建设 2026/10/15 13:41:07

很好玩!用TaoToken统一Key让OpenClaw通过CLI控制网易云听歌

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/15 4:39:16

5G大规模MIMO导频污染仿真与量化分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/15 22:06:11

H3 全套模型搬上昇腾 910:200 秒到 76 秒,国产 NPU 推理翻身仗?

H3 全套模型搬上昇腾 910&#xff1a;200 秒到 76 秒&#xff0c;国产 NPU 推理翻身仗&#xff1f; 【免费下载链接】MiniMax-H3 MiniMax H3 是一个通用的全模态生成系统。它支持对由文本、图像、视频和音频组成的多模态上下文进行统一理解&#xff0c;并能生成分辨率高达 2K、…

作者头像 李华
网站建设 2026/10/16 7:06:43

博主写作必备:项目信息提交格式与示例解析

我注意到你这次没有提供具体的【项目标题】、项目正文、关键词和摘要描述。要写出一篇贴合实际的博主风格博文&#xff0c;我需要你按下面格式给我输入信息&#xff0c;我就能直接开写。请按这个格式提供内容&#xff1a;项目标题: [你的项目标题] 项目正文: [对项目的零散描述…

作者头像 李华