资讯详情

基于Python与face_recognition的人脸识别考勤系统:从摄像头到SQLite完整实现

📅 2026/10/19 7:17:21 | 华诺云谱 👁 阅读
基于Python与face_recognition的人脸识别考勤系统:从摄像头到SQLite完整实现
简介面向计算机相关专业毕业设计与课程设计需求这份基于深度学习的人脸识别考勤系统源码提供了人脸检测、特征提取、打卡记录等完整流程。项目经导师指导并通过评审得分98分适合正在做大作业、期末项目或毕设开发的学生参考。资源包共25个文件压缩后约239.41MB。其中3个Python脚本负责主程序、界面与人脸识别API调用15张PNG图片涵盖界面背景、考勤状态等静态资源另含ttf字体、ico图标、config配置、docx使用手册等方便直接运行或移植复用。整体将核心算法模块、界面代码与静态资源分目录存放结构清晰。目前已有166人浏览学习。通过该案例可掌握深度学习人脸识别与Python桌面端应用的整合思路也能参考其代码组织、配置方式与文档撰写快速搭建自己的考勤系统是毕业设计、课程设计或项目实战的完整范本。1. 人脸识别考勤系统教室门口一次「抬头」完成签到早课点名最怕什么不是学生不来而是点名浪费的几分钟和替答到的尴尬。这套基于深度学习的人脸识别考勤系统把摄像头放在教室门口或讲台上学生进来只要看一下屏幕系统就自动完成签到和签退全程不需要掏手机、排队按指纹。从代码层面看它不是一个花架子人脸录入、实时识别、考勤记录、用户管理、历史查询这些毕设该有的模块都有界面用 PyQt5 编写评审分拿到 98 分。适合正在做毕设、课程设计、期末大作业的计算机专业学生也适合想通过一个完整项目把深度学习落地链路走通的学习者。下面我会从架构选型、核心代码、运行步骤、踩坑记录到二次开发把一个真实能跑的项目拆开讲。2. 项目架构与技术选型这套系统为什么这么搭2.1 技术栈全景Python face_recognition PyQt5 SQLite先交代底子。这个系统没有从零训练自己的卷积网络而是站在 face_recognition 的肩膀上这是目前做毕业设计最务实的选型。face_recognition 基于 dlib 的深度学习人脸识别模型能做人脸检测、关键点定位和 128 维特征向量提取识别精度在教室这种受控光照场景下完全够用。底层的模型是预训练好的你不需要准备上万张训练图片只需要给每个学生录入 2 到 3 张照片系统就能在考勤时准确认人。从零训练 CNN 不是不可以但要考虑数据集标注、训练时长和效果不稳定的风险对毕设周期来说性价比很低。用预训练模型相当于把最难的部分交给社区验证过的模型你专注在业务逻辑上这个取舍在答辩时也能自圆其说——讲的是系统集成与业务设计不是造轮子。界面部分选了 PyQt5 而不是 Tkinter原因很直接PyQt5 可以用 QSS、贴图做出像样的界面而且 QThread 处理摄像头视频流非常顺手不至于让界面卡顿。数据库用 SQLite零配置、单文件答辩演示时不用现场配 MySQLconfig 文件里留了数据库路径和摄像头设备号想换 MySQL 是后面改造的事。选 SQLite 还有一个现实考虑答辩现场经常没有网络MySQL 服务不一定能及时启动而 SQLite 一个文件拷过去就能跑演示不翻车。整体架构上项目把「识别」和「业务」分离了face.py 只管人脸特征提取和比对back 目录管考勤记录和用户管理api 目录封装内部接口Ui_test_01.py 作为主程序把摄像头画面、识别结果、考勤状态串起来。这样每个模块都能单独改不会出现为了调一个按钮事件把识别逻辑翻个底朝天的情况。2.2 目录结构与文件职责拿到压缩包先看哪里解压项目后第一件事不是急着运行而是先看清目录结构。这个项目的根目录不算复杂但有几个地方值得注意文件/目录类型职责Ui_test_01.py文件主程序入口PyQt5 界面、摄像头线程、业务调度face.py文件人脸识别核心负责特征提取、比对、识别结果返回back/目录考勤业务逻辑签到/签退、记录查询api/目录接口层给 UI 和业务之间提供调用入口config文件配置文件数据库路径、摄像头 ID、识别阈值static/目录静态资源背景图、Logo、按钮图片、人脸样本目录msyh.ttf文件微软雅黑字体文件解决中文乱码手册.docx文件项目使用说明书答辩前必读face-master/目录内置的 face_recognition 源码环境失败时从本地安装这里我要多说一句 face-master 这个目录。很多毕设项目会把 face_recognition 的源码直接放一份原因太现实了face_recognition 依赖 dlib而 dlib 在 Windows 上的编译是个玄学问题稍后会在避坑章节细讲。有这份源码在pip 装不上时还能从本地源码安装这是很多项目把环境问题兜底做进压缩包的习惯。static 目录里那些 llz 开头的 PNG 是 UI 的装饰资源llz_background.png 是背景大图llz_video_rect.png 是摄像头预览区的边框llz_user_list_*.png 是右侧学生列表的区域背景。想换肤的话把这些图替换掉就行但别改代码里写死的坐标否则界面布局会乱。config 配置文件是排查问题时的第一站它通常长这样[db] path attendance.db [camera] device_id 0 [recognition] tolerance 0.45device_id 是摄像头设备号笔记本一般 0外接摄像头可能是 1 或 2tolerance 是识别阈值越小人脸比对越严格教室光线不好时可以适当调大到 0.5但别超过 0.6否则容易认错人。api 目录这层接口很多人不理解为什么要单独存在它的作用是把 back 里的业务函数再封装成参数更友好的接口供 UI 调用将来把界面换成 Web 前端时api 可以重新实现成 REST 接口back 和 face.py 不用动。3. 核心模块拆解从摄像头画面到考勤落库的完整链路3.1 人脸识别核心face.py 中的特征提取与距离比对人脸识别模块是整个系统的技术核心也是答辩时老师必问的地方。face.py 做两件事离线加载已知人脸特征在线比对当前帧人脸。import face_recognition import numpy as np import os def load_known_faces(face_dirstatic/faces): 遍历人脸样本目录把每个人的照片转成128维特征向量 known_encodings [] known_names [] for name in os.listdir(face_dir): person_dir os.path.join(face_dir, name) if not os.path.isdir(person_dir): continue for img_name in os.listdir(person_dir): img_path os.path.join(person_dir, img_name) # 加载图片并提取第一张人脸特征 img face_recognition.load_image_file(img_path) encodings face_recognition.face_encodings(img) if encodings: known_encodings.append(encodings[0]) known_names.append(name) return known_encodings, known_names这段代码注意几点目录组织方式是一个人名对应一个子目录子目录里放该学生的照片名字从目录名来这样录入新学生只需要建新文件夹放照片不用改代码。face_encodings 返回的是一个列表因为一张照片里可能有多张脸代码里只用 encodings[0]也就是检测到的第一张脸。所以录入照片时尽量用单人照这是很多人忽略的坑。识别部分是这样的def recognize(frame, known_encodings, known_names, tolerance0.45): # 缩小帧尺寸识别速度提升接近4倍 small_frame cv2.resize(frame, (0, 0), fx0.5, fy0.5) rgb_small_frame cv2.cvtColor(small_frame, cv2.COLOR_BGR2RGB) # 检测位置和特征 face_locations face_recognition.face_locations(rgb_small_frame) face_encodings face_recognition.face_encodings(rgb_small_frame, face_locations) results [] for encoding in face_encodings: # compare_faces 返回和已知人脸逐个比对的布尔列表 matches face_recognition.compare_faces(known_encodings, encoding, tolerance) # face_distance 返回欧氏距离距离越小越像 distances face_recognition.face_distance(known_encodings, encoding) best_idx np.argmin(distances) name Unknown if matches[best_idx]: name known_names[best_idx] results.append((name, distances[best_idx])) return results逻辑说明face_encodings 得到当前帧所有脸的特征然后逐张与已知特征比对。compare_faces 的 tolerance 参数本质上对距离做阈值截断默认 0.6这里给 0.45 是为了课堂场景更严格。face_distance 返回所有已知人的距离数组np.argmin 取最小值的索引也就找到了最像的那个人。注意先缩放到 0.5 倍再识别这是实时的关键——原分辨率跑 face_recognition 在普通笔记本上只有几帧每秒缩小后能到 15 帧以上UI 才不会像幻灯片。3.2 考勤业务逻辑签到、签退与重复打卡的状态机识别人脸只回答了「你是谁」考勤系统还要回答「你今天签到了没有」。这块逻辑在 back 目录里核心是一个状态判断import sqlite3, datetime, config def handle_attendance(user_id): 一次识别结果进入考勤流程返回给UI展示的提示信息 today datetime.date.today().isoformat() now datetime.datetime.now().strftime(%H:%M:%S) conn sqlite3.connect(config.DB_PATH) cur conn.cursor() # 查这个人今天是否已经有记录 cur.execute(SELECT id, sign_out_time FROM attendance WHERE user_id? AND date?, (user_id, today)) row cur.fetchone() if row is None: # 今天第一次识别记为签到 cur.execute(INSERT INTO attendance(user_id, date, sign_in_time) VALUES(?, ?, ?), (user_id, today, now)) msg 签到成功 elif row[1] is None: # 已有签到但没有签退时间本次识别记为签退 cur.execute(UPDATE attendance SET sign_out_time? WHERE id?, (now, row[0])) msg 签退成功 else: # 签到和签退都完成了提示重复 msg 今天已完成考勤请勿重复打卡 conn.commit() conn.close() return msg这段考勤代码是一个很典型的「一天两态」状态机签到状态和签退状态都在同一条记录里。第一次识别写入 sign_in_time第二次识别补上 sign_out_time第三次直接拒绝。数据库表里至少需要这几个字段id、user_id、date、sign_in_time、sign_out_time其中 user_id 关联学生用户表。注意这里用的是「当天日期 user_id」作为唯一维度避免同一个人当天生成多条脏数据。这个设计的优点是逻辑简单、适合演示缺点是它没有处理跨天未签退的情况——如果某人早上签到了中午没签退就离开第二天再来系统会因为查不到今天的记录而直接新建一条昨天那条就永远缺一个签退时间。实际跑起来影响不大但如果追求严谨可以在初始化时把昨天未签退的记录补上异常标记这是二开的一个方向。3.3 UI 与业务调度Ui_test_01.py 里摄像头线程怎么工作UI 主程序是 Ui_test_01.py它做的事情比看上去多初始化界面、加载已知人脸、启动摄像头线程、在画面里画框、把识别结果送到 handle_attendance。摄像头不能放在主线程里否则视频帧读取会阻塞 Qt 事件循环界面必然卡死。常见做法是开一个 QThread 专门读摄像头from PyQt5.QtCore import QThread, pyqtSignal import cv2, numpy as np class CameraThread(QThread): # 每帧画面通过信号发回主线程 frame_signal pyqtSignal(np.ndarray) def __init__(self, device_id0): super().__init__() self.device_id device_id def run(self): cap cv2.VideoCapture(self.device_id) while not self.isInterruptionRequested(): ret, frame cap.read() if ret: self.frame_signal.emit(frame) cap.release()信号槽是 PyQt5 的核心机制CameraThread 把每一帧图像通过 frame_signal 发出去主线程里的槽函数收到帧后一边用 face.py 的 recognize 做识别一边把画面显示到 QLabel 上。不要尝试在 run 里直接改界面控件跨线程操作控件是 PyQt 的大忌轻则界面闪烁重则直接崩溃。所有界面更新都放到主线程槽函数里做这是 PyQt5 项目里不能违反的规矩。槽函数里还有一个容易被忽视的性能细节不要每一帧都去做完整识别我一般会加一个帧率控制比如每 3 帧识别一次其余帧只显示画面。这样 CPU 占用会明显下降摄像头画面也更流畅。4. 本地运行指南从解压到界面弹出的完整步骤4.1 环境准备Python 版本、依赖安装与 dlib 这个老冤家先把环境说清楚。这个项目需要 Python 3.7 以上的版本依赖核心是 face_recognition、opencv-python、PyQt5、numpy、pillow。安装命令集中在 requirements.txt 里但实际执行时最常翻车的是 face_recognition。pip install -r requirements.txt如果你在 Windows 上执行这条命令大概率会在编译 dlib 时报错。dlib 是 face_recognition 的底层依赖在 Windows 上需要 CMake 和 C 编译工具链没有这些环境它就现场编译速度慢还容易失败。两个解决思路一是去社区下载编译好的 dlib wheel 文件先装 dlib 再装 face_recognition二是用项目里自带的 face-master 源码目录pip install ./face-master用源码安装前记得先确认本地有 CMake。如果连 CMake 都不想装还有一个省事方案用 Anaconda 创建环境先 conda install cmake 再去 pip踩坑概率会低很多。这一步是绝大多数新手第一次跑这个项目时卡住的地方别慌按顺序重试就行。提示如果在安装依赖时看到大片红色报错先判断是不是 dlib 编译问题再决定是装 wheel 还是走源码安装不要盲目重装 Python。4.2 配置文件与数据库初始化环境就绪后检查 config 文件里的数据库路径和摄像头 ID。默认路径是 attendance.db这个文件会在首次运行或执行初始化脚本时自动创建。有些同学拿到项目直接跑结果看到报错找不到表就是因为跳过了初始化。我的习惯是写一个小脚本建表CREATE TABLE IF NOT EXISTS users ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, student_no TEXT UNIQUE, face_dir TEXT ); CREATE TABLE IF NOT EXISTS attendance ( id INTEGER PRIMARY KEY AUTOINCREMENT, user_id INTEGER NOT NULL, date TEXT NOT NULL, sign_in_time TEXT, sign_out_time TEXT, FOREIGN KEY(user_id) REFERENCES users(id) );users 表存学生信息attendance 表存考勤记录。face_dir 字段指向这个人照片所在的目录或者也可以按「人名目录」约定自动识别两种方案在代码里都能跑通。初始化脚本通常放在项目的根目录执行一次即可后面再启动程序就不会再报缺表。4.3 启动系统与功能验证配置完成启动命令就一句话python Ui_test_01.py界面弹出后别急着拿脸去试。我的建议是按这个顺序验证第一步点击「用户管理」创建一个测试用户并上传 2 到 3 张本人正面照片第二步回到主界面点击「开始识别」摄像头画面应该出现在预览区域第三步正对摄像头看右上角是否出现自己的名字和距离值第四步观察状态栏提示「签到成功」再关掉识别重新打开第二次识别应显示「签退成功」。如果第四步没有出现预期结果优先检查数据库文件是否生成、attendance 表里是否有记录。用 SQLite 工具打开看一眼比在界面上反复试要高效得多。整个验证流程走通说明系统运行正常这时候再加真实学生数据也不迟。5. 避坑与常见问题排查新手最容易翻车的几个点5.1 dlib 编译失败face_recognition 装不上现象pip install face_recognition 时出现长长的编译报错结尾是 error: command cl.exe failed。原因dlib 要从源码编译而系统里没有 C 编译环境。解决Windows 下先下载社区预编译的 dlib wheel用 pip install 本地 wheel 文件安装再装 face_recognition或者先用 conda install cmake libcxx再 pip install face_recognition。如果项目里有 face-master 目录直接 pip install ./face-master 是最后一根救命稻草。5.2 摄像头打不开界面黑屏现象程序能启动但预览区域全黑控制台提示 cant open camera by index。原因设备号不对或摄像头被其他程序占用。解决把 config 里的 device_id 从 0 改成 1 或 2 逐个试关闭聊天软件、视频会议软件等占用摄像头的应用。我见过最经典的翻车现场是某位同学用远程桌面连主机调试摄像头被远程会话占用本地程序怎么都打不开断开远程就好了。5.3 中文乱码按钮文字变成方框现象界面所有中文显示为方块或乱码。原因PyQt5 默认字体不含中文字形系统字体环境缺中文字库。解决项目里自带 msyh.ttf 就是为了这个。把字体文件放到系统字体目录Windows 下是 C:/Windows/Fonts或者在代码启动时用 QFontDatabase.addApplicationFont 加载它之后设置全局 QFont。如果是在 Linux 机器上跑还需要安装中文字体包但毕设场景基本都在 Windows这条比较容易解决。5.4 识别不准或者把甲认成乙现象同一个人的识别结果不稳定有时显示名字有时显示 Unknown更糟的是把两个人搞混。原因tolerance 阈值设得太大或者录入照片质量太差比如背光、侧脸、模糊。解决先把 tolerance 从 0.45 往 0.4 方向调小看是否改善然后把录入照片换成光线均匀的正面照。每录入一个人至少放 2 张照片不同角度更好。另外现场识别时离摄像头太近或太远都会影响结果建议实际测一下有效距离在 UI 上做个提示这招在答辩演示时很加分。5.5 考勤记录重复同一个人一天产生多行现象考勤表里同一个人同一天有多条记录。原因handle_attendance 里的状态判断没有生效可能是识别线程和写库线程并发访问导致读到了旧数据。解决给 handle_attendance 加一个针对 user_id 和日期的唯一索引或者在识别回调处做简单的互斥。我一般会在表上直接加约束CREATE UNIQUE INDEX idx_attendance_user_date ON attendance(user_id, date);这样即使代码有并发问题数据库也会拦住重复插入属于兜底方案。6. 二次开发与改造让考勤数据活起来把识别引擎换成自己的6.1 改造思路从 SQLite 迁移到 MySQL打通 Web 端最常见的改造是把本地 SQLite 换成 MySQL让考勤数据能通过 Web 后台查看。改造重点在 config 和 back 目录config 里增加 MySQL 连接信息back 目录里的 sqlite3.connect 换成 pymysql 或 SQLAlchemy。SQLite 和 MySQL 的 SQL 语法差异不大主要改占位符SQLite 用 ?MySQL 的 pymysql 用 %s。换个数据库驱动整个系统的使用场景就从「单机演示」变成「可部署的小型考勤服务」这在答辩里是个不错的亮点。另外一个性价比更高的改造方向是把考勤记录同步到企业 IM 机器人的 Webhook 接口每天定时推送未签到名单。这个功能改动量很小加一个脚本定时查询当天缺勤的 user_id再调用 Webhook 发送消息。很多同学把精力花在换模型上其实对评委来说能解决实际问题的业务闭环比单点技术的炫技更有说服力。6.2 替换识别引擎从 face_recognition 到 OpenCV DNN 或 MTCNN如果导师要求你必须体现更多深度学习内容可以考虑把 face_recognition 换掉改用 OpenCV 的 DNN 人脸检测器或 MTCNN 做检测再用预训练模型提特征。face_recognition 的优点是调用简单缺点是它是个黑匣子答辩时一句「底层原理是什么」就容易被问住。我建议至少读一遍 face_recognition 的源码目录把里面 dlib 调用逻辑看明白能讲清「128 维特征向量 欧氏距离」的原理比单纯换库更能应对提问。换引擎时接口要保持不变load_known_faces 返回特征列表recognize 返回名字和置信度。只要守住这两个函数签名业务层完全不用动。这是当初把识别逻辑单独放 face.py 而不是写在 UI 里的好处——模块边界清晰替换成本低。6.3 验证方法与回归测试改完代码后不要只在界面上点两下就算完。我一般会写一个简单的回归脚本把录好的测试视频循环播放几遍断言每次识别结果里都出现正确的人名和考勤状态确保状态机没有被改坏。人脸识别这个领域数据稍微变化就可能引入意想不到的问题比如光照变了识别率下降这时候要对比修改前后的 tolerance 和距离分布。记得有一次我为了提升速度把缩放系数从 0.5 改成 0.25当时界面确实流畅了很多但距离值整体变小导致很多非本人也通过了阈值那天的考勤表多了好几条错误记录。从那以后我每次改完识别参数都会强制走一遍回归测试用同一段视频对比识别结果和距离分布确认不是「看起来流畅」就完事。配合下载包里的手册.docx把数据库设计和接口定义过一遍改起来会更有底气。这个习惯帮我避了不少坑希望帮到你。本文还有配套的精品资源点击获取
📝

华诺云谱内容团队

资深建站顾问 · 行业研究员

10年+企业数字化服务经验,专注智能建站、SEO优化与品牌营销,持续输出建站技巧、行业洞察与营销干货,已帮助5000+企业实现数字化增长。

你可能需要的服务

订阅华诺云谱资讯周报

每周一封,精选建站技巧、SEO与营销干货,直达邮箱。已有 8,000+ 企业主订阅,助你少走弯路。

↑