ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于OpenCV与LBPH的人脸识别考勤系统源码解析与实战

基于OpenCV与LBPH的人脸识别考勤系统源码解析与实战 简介基于OpenCV的人脸识别考勤系统Python源码与数据是一份面向计算机专业毕业设计、课程设计及期末大作业的高分参考项目同时适合人脸识别项目实战的入门学习。压缩包共26个文件整体约239MB包含3个Python核心脚本界面测试、人脸识别处理、15张PNG图片涵盖用户信息列表、考勤状态、背景等界面素材以及配置文件、说明文档、字体和图标素材。目前已有346人浏览学习项目经导师指导并获98分评审整体完整度与实用性强适合作为毕业设计参考或项目实战练习。源码覆盖人脸识别、考勤信息管理、用户列表展示等关键模块附带UI测试脚本与静态界面资源便于直接运行、调试或二次开发。配套介绍与说明文字也能帮助快速梳理实现思路为论文写作、答辩演示与后续功能扩展提供支撑。1. 为什么这份毕设源码值得拆开看答辩拿到 98 分的人脸考勤系统听起来像个噱头但真正打开源码包之后你会发现它把一个计算机视觉毕业设计该有的模块都收进去了OpenCV 做检测和识别、LBPH 生成特征模型、PyQt 搭界面、文件目录里还备好了训练数据和字体资源。对于正要交毕设或者想练手完整项目的人来说比网上散装的人脸识别 demo 有价值得多因为它不是单点功能演示而是一条能跑通的业务闭环。这套系统最值得学习的地方在于它没有依赖云服务所有行为都在本地完成。录入的人脸样本经过 Haar 级联检测后裁剪成统一尺寸交给 LBPH 算法训练出模型考勤时摄像头逐帧提取人脸区域与模型比对后返回 ID 和置信度再把结果同步到界面和记录文件里。整个链路清晰没有复杂的分布式概念适合用来理解传统计算机视觉里的识别流程也能让有经验的人快速看出哪些模块可以替换成更现代的方案。2. OpenCV 人脸考勤的技术选型与源码结构2.1 为什么选 OpenCV 而不是云端识别 API拿到手的第一件事是看技术选型。这套系统选择的是开源 OpenCV而非调用百度、阿里的人脸识别接口原因很简单毕业设计需要展示算法层面的工作量同时考勤场景对实时性有要求本地推理能避免网络延迟和接口费用。OpenCV 在 4.x 版本里原生支持 LBPH、EigenFaces、FisherFaces 三种经典人脸识别算子配合 Haar 级联检测器完全可以在普通笔记本 CPU 上跑到 20 帧以上足够应付课堂和实验室的小规模点名。另一个潜在理由是隐私。人脸数据属于敏感信息如果走云端 API就必须把采集到的照片传到第三方服务器这在课程设计场景里会引起不必要的审查问题。纯本地方案把数据文件、模型文件、识别结果全部留在项目目录内更符合主流价值观和学校对数据安全的预期。如果你在工作中做私有化部署这个思路也有参考价值。2.2 解压后的目录到底长什么样源码包解开后是一套典型的 Python GUI 项目结构。主程序是Ui_test_01.py负责创建窗口、绑定按钮、启动摄像头预览face.py是核心识别模块封装了人脸检测、样本采集、模型训练和预测函数静态资源放在static目录包括背景图、logo、用户列表底图以及一个empty_bg.png空状态占位图。配置文件不管存放格式如何一般用来维护数据库连接和设备号这类运行参数。我习惯先把目录结构过一遍再读__init__.py和face.py判断模块之间的依赖关系。常见的文件组织方式如下master/ ├── face.py # 人脸检测、训练、识别核心逻辑 ├── Ui_test_01.py # PyQt 主程序控制摄像头和界面 ├── config # 配置目录存摄像头编号、记录路径 ├── static/ # 界面图片资源 │ ├── llz_background.png │ ├── llz_user_list_bg.png │ └── empty_bg.png ├── back/ # 历史考勤记录备份 ├── api/ # 业务接口层封装数据读写 ├── msyh.ttf # 微软雅黑字体解决界面中文乱码 └── __init__.py这种按「界面层 - 逻辑层 - 资源层」分离的组织方式很值得借鉴。face.py不依赖任何 PyQt 控件可以单独在命令行里测试Ui_test_01.py只负责把识别结果渲染到表格和标签上不直接操作像素矩阵。两者通过几个公开函数衔接比如采集人脸、训练模型、预测 ID。你做其他毕设时也应该保持这种解耦别把 cv2 调用和 QLabel 更新混在同一个函数里。2.3 依赖环境与 OpenCV 版本兼容性运行这套代码前需要确认 Python 环境和 OpenCV 安装方式。项目原生的依赖大概率只写了 opencv-python但我建议同时安装 opencv-contrib-python因为cv2.face.LBPHFaceRecognizer_create()这个接口在 opencv-python 主包里有时不可用。另外PyQt 版本会影响Ui_test_01.py里的导入语句PyQt5 和 PyQt6 的信号槽写法有差异。依赖库版本建议说明opencv-python4.x核心图像处理与 Haar 级联检测opencv-contrib-python4.x提供cv2.face模块PyQt5 / PyQt65.15 或 6.x界面框架版本与Ui_test_01.py中 import 对应numpy1.21图像矩阵运算和数组转换安装完成后用一行命令验证cv2.face是否可用避免跑到一半才发现模型训练函数不存在。这个检查对急着交作业的人来说很关键ModuleNotFoundError: No module named cv2.face是新手最常见的一道坎。3. 人脸录入与 LBPH 模型训练核心代码怎么跑通3.1 Haar 级联检测先找到人脸再谈识别人脸检测和识别是两件事。这里用的是 OpenCV 自带的 Haar 级联分类器通过CascadeClassifier加载haarcascade_frontalface_default.xml模型文件在灰度图上滑动窗口判断是否有人脸。这套算法对正脸效果最好侧面和低头场景漏检率会明显上升所以在做考勤时我一般会提示使用者在录入阶段正对摄像头最好保持光照均匀。face.py里实现检测的代码逻辑大多是把读取到的样本逐个转换尺寸再喂给级联检测器。常见做法的核心片段如下import cv2 import numpy as np detector cv2.CascadeClassifier(haarcascade_frontalface_default.xml) def get_training_data(data_path): image_paths [str(p) for p in Path(data_path).glob(*.jpg)] faces [] labels [] for path in image_paths: img cv2.imread(path, cv2.IMREAD_GRAYSCALE) # 样本文件名约定为 userId.序号.jpg例如 1.1.jpg 表示用户1的第1张图 label int(path.split(/)[-1].split(.)[0]) detected detector.detectMultiScale( img, scaleFactor1.1, minNeighbors5, minSize(80, 80) ) for (x, y, w, h) in detected: face_region img[y:y h, x:x w] faces.append(face_region) labels.append(label) return faces, labels这段代码有两个关键点一是读取时直接转成灰度因为 LBPH 只需要亮度信息彩色图反而增加计算量二是样本文件名携带用户 ID 标签split(.)[0]取出 ID 作为训练标注。如果你打不开这份源码可以用Path(data_path).glob(*.jpg)替代原本的os.listdir遍历方式效果一样但代码更整洁。3.2 LBPH 训练流程与参数含义LBPHLocal Binary Pattern Histogram的核心思想是把人脸图像分成若干小区域在每块区域内计算局部二值模式直方图再拼接成整张人脸的特征向量。识别时计算当前人脸特征向量与训练集中各样本的距离距离最小的那个标签就是预测结果这个距离就是后续会用到的置信度。训练部分通常把采集到的所有人脸样本交给LBPHFaceRecognizer训练最后通过write导出模型文件recognizer cv2.face.LBPHFaceRecognizer_create() faces, labels get_training_data(data/face_samples) recognizer.train(faces, np.array(labels)) recognizer.write(trainer/trainer.yml) print(f训练完成共 {len(set(labels))} 位用户)这里有一个容易踩的坑labels必须转换成一维整数数组直接传 list 会导致部分 OpenCV 版本抛出类型错误。另外训练样本要保证每位用户至少有 10 到 15 张不同角度的正脸图太少的话 LBPH 的直方图统计不稳定识别时置信度会普遍偏高最终导致系统把任何人都判定为陌生人。3.3 数据目录与标签文件怎么对应back目录里出现2018-08-16这样的日期子目录说明这套系统会按天归档考勤结果。对应的训练数据的目录结构一般是data/face_samples/1.1.jpg、1.2.jpg、2.1.jpg这种命名方式。文件名第一部分是用户 ID第二部分是样本序号。face.py训练时按split(.)[0]取 ID所以目录采集规则不要随意改动否则会出现“训练完谁都不认识”的惨剧。文件或目录作用常见问题data/face_samples/存放原始人脸样本图缺少正样本时训练报错trainer/trainer.yml识别模型训练后生成首次运行必须先训练再识别back/2018-08-16/每日考勤明细归档日期目录不存在时需自动创建msyh.ttf界面中文字体字体缺失导致乱码实际项目里face.py还会在训练前检查trainer/trainer.yml是否存在不存在就提示先录入人脸。这套机制很朴素但保证了人脸识别考勤系统第一次启动时不会因为读不到模型而崩溃。4. 实时识别与考勤记录Ui_test_01.py 怎么串起来4.1 摄像头帧处理流程Ui_test_01.py的主循环负责从摄像头读取画面对每一帧执行灰度转换和人脸检测。检测到人脸后把区域交给识别器预测得到(id, confidence)元组然后根据置信度决定显示姓名还是标注 Unknown。整个流程可以用一段伪代码还原import cv2 cap cv2.VideoCapture(0, cv2.CAP_DSHOW) recognizer cv2.face.LBPHFaceRecognizer_create() recognizer.read(trainer/trainer.yml) cascade cv2.CascadeClassifier(haarcascade_frontalface_default.xml) while True: success, frame cap.read() if not success: break gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces cascade.detectMultiScale(gray, scaleFactor1.2, minNeighbors5, minSize(80, 80)) for (x, y, w, h) in faces: face_region gray[y:y h, x:x w] user_id, confidence recognizer.predict(face_region) if confidence 60: cv2.putText(frame, fID: {user_id}, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 255, 0), 2) else: cv2.putText(frame, Unknown, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2) cv2.imshow(Attendance, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这里我刻意强调的是cv2.CAP_DSHOW参数。在 Windows 上不指定后端的摄像头打开延迟会很高甚至出现摄像头被占用打不开的问题。很多在 Ubuntu 上跑得好好的考勤系统搬到 Windows 上第一步就栽在这个细节上所以建议读取摄像头时明确写出后端参数。4.2 置信度阈值怎么调才合理LBPH 的置信度是一个距离度量值越小表示当前人脸与训练模型中的对应样本越相似。默认阈值因人脸库规模和环境光照差别很大不能用网上的固定值硬套。项目里face.py通常会暴露一个阈值变量推荐设置在 50 到 80 之间。阈值表现适用场景低于 40识别严格稍有光线变化就拒识固定光照的实验室50~60平衡型适合普通教室大部分课程考勤场景高于 80宽松容易误识别样本数量少、要求低漏报的场合调阈值不需要重新训练模型改完立刻生效。具体做法是观察打印出来的 confidence 值让测试者坐在摄像头前缓慢左右转头记录正常识别和误识别时的数值区间取中间值作为最终阈值。如果发现所有用户 ID 都错乱通常是训练样本不够或者脸没裁准而不是阈值问题。4.3 考勤记录如何落盘识别成功后需要记录考勤时间Ui_test_01.py里一般会有一个按时写入文件或数据库的逻辑。常见做法是把打卡结果以 CSV 行追加到当日目录下文件名包含日期避免单文件无限增长。from datetime import datetime import csv import os def mark_attendance(user_id, status正常): today datetime.now().strftime(%Y-%m-%d) now datetime.now().strftime(%H:%M:%S) record_dir os.path.join(back, today) os.makedirs(record_dir, exist_okTrue) file_path os.path.join(record_dir, attendance.csv) with open(file_path, a, newline, encodingutf-8) as f: writer csv.writer(f) writer.writerow([user_id, now, status])这段代码每次识别到用户后追加一行而不是反复打开关闭整个文件。用os.makedirs(..., exist_okTrue)保证跨天时自动创建新目录省去手工建目录的步骤。想要避免重复打卡可以在写入前读一下文件末尾判断这个 userId 今天是否已经存在记录。5. 部署排错与后续改造把毕设变成能演示的考勤工具5.1 启动阶段最常踩的坑这份源码第一次运行时最容易遇到的问题集中在三处。第一是缺少opencv-contrib-python导致cv2.face.LBPHFaceRecognizer_create()直接报出AttributeError: module cv2 has no attribute face解决方法是执行pip install opencv-contrib-python不要只依赖 opencv-python。第二是模型文件trainer.yml不存在启动识别前必须先走一遍人脸录入和训练流程。第三是中文乱码界面把用户姓名显示成方框原因是没有正确加载msyh.ttf字体建议用QFont显式指定from PyQt5.QtGui import QFont font QFont() font.setFamily(微软雅黑) font.setPointSize(11) app.setFont(font)注意msyh.ttf必须与Ui_test_01.py放在同一路径下或者把字体文件路径写进config否则打包给别人时同样会乱码。5.2 识别准确率不理想时先检查数据质量很多人在运行这套系统后发现识别率波动很大第一反应就是调CascadeClassifier参数。我的建议是先统计一下data/face_samples里每个人的样本数量。低于 10 张的训练结果基本不可用直接补拍样本比调任何参数都有效。样本质量同样重要如果录入时背景太杂Haar 检测会把背景区域也裁进去训练出的模型特征就会偏离人脸结构。检查裁剪区域是否正确的方法是直接显示裁剪后的face_region并检查是否包含耳朵、衣领等无关区域。5.3 低成本改造方向做完演示后想进一步放大这套源码的价值可以朝两个方向修改。一是把 LBPH 替换成 OpenCV DNN 人脸识别重新用训练好的分类模型做人脸嵌入替换点在face.py的predict调用上界面层完全不用动。二是把attendance.csv的写入改为 sqlite3 或 MySQL并加上简单的统计报表功能。这两个改动既不会破坏整个系统的运行逻辑又能让你在问辩时聊出工程化思维。最后提一个容易忽略的细节摄像头设备号在部分笔记本上不是 0 而是 1VideoCapture打开失败时可以尝试切换设备索引再把结果回写到config文件里。本文还有配套的精品资源点击获取
返回列表