☰
基于深度学习的人脸识别考勤系统源码解析与二次开发
2026/10/19 6:08:57 网站建设 项目流程

简介:这是一套基于深度学习的人脸识别考勤系统毕业设计源码,面向计算机相关专业学生与需要项目实战练习的开发者,适用于毕业设计、课程设计及期末大作业场景。项目经导师指导并通过评审(98分),功能完整、模块划分清晰。资源共25个文件,包含Python核心代码、配套docx使用手册、字体图标等界面资源、多张UI界面截图,以及打包好的可运行软件程序,整体约239MB,已有166人学习下载。文件中既含人脸识别与考勤管理相关逻辑,也有背景、头像区域、签到状态等界面展示所需的静态素材,可对照源码与手册快速理解系统架构、识别流程与界面交互逻辑。对想复现高分毕设、或参考项目结构完成类似课题的学生来说,是一份模块划分明确、可直接上手的学习和修改底稿。

1. 从 98 分的毕设里拆出一套可复现的人脸考勤系统

人脸识别考勤这个方向,每年毕业设计都有一大批人选,但真正能跑通、能截图、能写进论文的并不多。这个基于深度学习的人脸识别考勤系统源码包,是一份评审分 98 分的高分项目,拿到手不是让你照着交差,而是给你一条完整的工程链路:从摄像头采集人脸、检测对齐、特征提取,到与库里的人脸比对、写入考勤记录,再到 PyQt 界面展示,每一步都有落地的代码和素材。适合正在做毕业设计、课程设计的学生,也适合想用完整案例练手深度学习的开发者。我拆完这个包之后的感觉是:它最大的价值不在算法多惊艳,而在于把识别、数据库、界面三件事拧成了一个能演示、能答辩的完整系统。

2. 源码包结构拆解:先弄清楚每一层在干什么

2.1 目录映射:face-master、static、config 各管哪一段

拿到压缩包先别急着装环境,把目录结构过一遍,能省掉后面大半的排查时间。这个包解压后是一个叫 face-master 的主目录,里面有几个关键角色。back 目录看名字像是历史备份或后端辅助代码,2018-08-16、2018-08-02 这两个子目录是不同迭代版本,打开看下文件时间戳就明白这是开发过程留下的存档,跑主流程不需要动它们。api 目录里有 face.py 这类接口文件,承载了识别逻辑的封装,Ui_test_01.py 是界面程序的任务入口,static 目录存放着界面用到的 png 背景图、登录页素材、logo 等,llz_user_list_bg.png、sign_status.png 这些直接对应考勤页面的背景和签到状态图标。

config 文件放的是路径配置和基础参数。这么说吧,在毕设项目里,config 这种文件往往是整个项目的“任督二脉”,因为人脸识别系统要读摄像头、要访问图片库、要写考勤日志,每一个路径写错了,程序起来都会黑屏或者闪退。我建议第一步就是把 face.py、Ui_test_01.py 里的相对路径和 config 里的配置全部对照一遍,确认当前机器上的目录结构能对齐。

2.2 核心调用链:UI、识别 API、数据存储是如何串起来的

从代码结构上推测,正常跑起来的流程应该是这样的:Ui_test_01.py 启动 PyQt 窗口,界面上提供“录入人脸”“开始签到”“查看记录”几个入口。录入时,程序调用摄像头拍照,把抓到的面部图像经过人脸检测器定位后,提取特征向量,存入本地人脸特征库;签到时,同样先检测人脸,再拿当前帧的特征向量去和库里存好的向量做距离度量,距离小于阈值就判定为同一人,写入考勤表。

这里要注意一个细节:face-master 目录下出现了 msyh.ttf,这是微软雅黑字体文件。之所以特意放在项目里,是因为 PyQt 在某些系统上默认字体渲染中文会变成方框,把字体文件打包到资源目录里,再用 QFontDatabase.addApplicationFont 加载,才能保证界面中文不乱码。很多毕设代码跑起来界面全是乱码,九成是没做这一步。

# 引入公用模块 import sys from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtGui import QFontDatabase # 在 app 创建之前主动加载字体包,避免中文乱码 font_path = "static/msyh.ttf" font_id = QFontDatabase.addApplicationFont(font_path) if font_id == -1: print("字体加载失败,界面中文可能显示为方框") app = QtWidgets.QApplication(sys.argv)

这段代码要放在程序入口最早的位置,早于任何窗口界面实例化。QFontDatabase.addApplicationFont 是 PyQt 提供的全局字体注册接口,返回值是字体编号,如果返回 -1 说明路径不对或文件损坏。这里我用的是项目内相对路径,如果从其他目录启动程序,需要先切换 current working directory,这个会在避坑章细聊。

2.3 人脸识别原理框架在这个项目里的简化实现

深度学习人脸识别的一般流程是:人脸检测(找出画面里哪里有人脸)→ 对齐(把眼睛和嘴巴校准到标准位置)→ 特征提取(卷积网络把人脸映射成多维向量)→ 比对(算向量余弦相似度或欧氏距离)。这个毕设项目没有从零写网络,而是借助 OpenCV 和第三方识别库来做人脸检测与特征提取,上层业务逻辑自己实现。

值得学的是它“识别成功后如何落地”:每次签到成功会向数据库插一条记录,包含姓名学号、签到时间、考勤状态,这个表结构你在后续对接自己的毕设论文时完全可以直接拿过来用。识别阈值、特征存储位置、比对方式这三个点,是答辩时导师最喜欢追问的地方,源码包里都给了实现,建议你逐个函数去看,而不是只盯着界面截图看。

3. 环境搭建与首次启动:把依赖装对,项目就成功了一半

3.1 依赖项说明:Python 版本、OpenCV、PyQt 的匹配关系

这个项目是贴着 Python 3.6 时代的需求写的,用的还是 OpenCV 3.x / 4.x 早期的 API 写法。拿最新 Python 3.12 直接跑大概率会碰到 dlib 编译失败、numpy 接口变动等问题。我的习惯是先给项目建一个独立的虚拟环境,明确锁定版本,比硬追新版本省心得多。建议的版本组合是 Python 3.7 或 3.8,OpenCV 用 4.5.x,PyQt5 用 5.15.x,人脸识别相关的 dlib 用 19.22 或 19.23,这些版本组合我在类似项目里跑过很多次,兼容性最稳。

# 创建虚拟环境并激活(Windows / macOS / Linux 通用思路) python -m venv env source env/bin/activate # Windows 下用 env\Scripts\activate # 先装基础依赖 pip install opencv-python==4.5.5.64 pip install PyQt5==5.15.9 pip install numpy==1.21.6

如果你在安装 dlib 时遇到 cmake 报错、无编译工具链的问题,可以先安装 cmake 和 visual studio build tools 或者 Xcode command line tools,bootstrap 阶段会自动调用它们编译。这里我用的是人工指定版本号的方式,因为跨版本时 OpenCV 的 findContours 等函数返回参数已经调整过,不定死版本后面会遇到很多“明明照着教程写的却报错”的情况。

3.2 替换路径与参数:让项目能适配你自己电脑的目录结构

招式一,先把 config 里的路径全改成绝对路径。很多毕设源码默认按照写代码那台电脑的路径结构来组织文件,你 clone 到本地后层级只要差一层,图片就读不到,界面背景自然白屏。给一个常见做法:把项目根目录作为基准,用 os.path.dirname(file) 动态拼出其它目录的绝对路径。

import os # 以当前文件所在目录为基准,动态计算项目绝对路径 BASE_DIR = os.path.dirname(os.path.abspath(__file__)) CONFIG_PATH = os.path.join(BASE_DIR, "config") STATIC_PATH = os.path.join(BASE_DIR, "static") # 如果原代码里写的是相对路径,全部替换成如下取值方式 img_path = os.path.join(STATIC_PATH, "llz_background.png")

这样改的思路很简单,把你从 IDE 里直接运行和从命令行运行时的工作目录差异抹平。为什么要这样做,因为 PyQt 里加载图片通常用的是 QPixmap(path),如果给的是“static/xx.png”这种相对路径而当前进程不在项目根目录,QPixmap 会返回空对象,界面背景就是一片黑,你不会第一时间想到是路径问题。

3.3 人脸库的初始化与测试图片准备

人脸识别系统在进入考勤之前,得先有“人脸底库”。这个包的设计思路是先把用户照片放在某个目录里,文件名用“姓名学号”这种带标识的格式命名,然后运行录入脚本把特征向量提取好存进特征库。建议你自己准备 3-5 张不同光线条件、不同角度但露脸的正面照片,入库时特征向量越丰富,后面签到识别越稳定。

import face_recognition # 加载一张人脸底库图片,提取 128 维特征向量 image = face_recognition.load_image_file("known_faces/张同学_2021001.jpg") face_encoding = face_recognition.face_encodings(image)[0] # 打印向量维度来验证特征提取是否成功 print("特征向量维度: %d" % len(face_encoding))

face_recognition 库的 face_encodings 返回的是一个列表,列表里每个元素对应图片里的每一张人脸。如果你提供的图片里同时有多张脸,一定要用下标 [0] 锁定第一张,或者先做人脸检测确认数量,否则提取到的特征可能对应到旁边的人,签到成功却掉了别人的库里,这种隐蔽问题很难查。毕设答辩时老师问到“你的特征向量怎么保证是对应这个人的”,这个处理就是很好的回答点。

4. 考勤主流程:从摄像头采集到记录入库的完整闭环

4.1 签到逻辑模块拆解:检测、比对、写库三步走

签到主流程可以拆成三个互相独立又按顺序调用的模块。摄像头每抓取一帧画面,先做人脸检测定位人脸框,然后裁剪出人脸区域提取特征,再和库里的所有特征做距离计算,找出最近的一个。这个最近距离小于设定的阈值,就算签到成功,程序调数据库接口写入考勤数据。如果大于阈值或者压根没检测到人脸,界面会给出“签到失败或未注册”的提示。

def check_attendance(frame): # 1. 用 HOG 检测器定位当前帧中的人脸位置 face_locations = face_recognition.face_locations(frame) if not face_locations: return None, "未检测到人脸" # 2. 对检测到的第一张人脸提取特征 face_encoding = face_recognition.face_encodings(frame, face_locations)[0] # 3. 遍历已知人脸库计算距离 distances = face_recognition.face_distance(known_encodings, face_encoding) # 4. 取最小距离并与阈值比较 min_index = distances.argmin() if distances[min_index] < threshold: user_name = known_names[min_index] save_attendance_to_db(user_name) return user_name, "签到成功" return None, "未匹配到注册用户"

这段逻辑里最关键的两个参数是 threshold 和 known_encodings 的配比。阈值设得太大,随便一个不认识的人都会被误识别成库里的人,考勤记录一片混乱;阈值设得太小,同一个人换了个眼镜、换个灯光就签到失败。face_recognition 官方常见参考值是 0.4-0.6 之间,项目里具体用了多少,你要打开实际代码确认,答辩被问到时能解释清楚“为什么这个值能平衡误识率和拒识率”就是加分项。

4.2 界面操作流程:录入人脸、开始签到、查看报表

界面部分继承的是经典的 PyQt 桌面程序套路。左侧放功能导航,右侧是操作面板。录入人脸时,点按钮打开摄像头,程序自动抓取当前画面里的人脸并保存;签到页面则实时显示摄像头画面,识别结果和签到状态会直接刷新在界面上。从 static 目录里的 llz_userinfo_all.png 和 llz_user_list_bg.png 来看,界面还设计了用户列表区域和签到状态图标,对应考勤历史记录的展示。

这批界面素材文件命名比较规整,可以直接替换成你自己的 logo 和校徽,背景图尺寸如果和原设计不一致,PyQt 的 setStyleSheet 里 background-image 会自动拉伸,但清晰度会打折扣,建议用相同尺寸的图片替换。要改动界面布局的话,从 Ui_test_01.py 里的控件坐标开始看,注意 setGeometry 的四个数字分别对应 x、y、宽、高。

4.3 数据库设计与会话保持:考勤记录从哪里读、往哪里写

考勤数据在这个项目里承担着“证据”角色,所以一般不放在内存里,而是写进本地数据库或 SQLite 文件。最朴素的表结构就两张:用户表存姓名学号,考勤表存用户 ID、签到时间、状态。如果你想把项目升级成多人连续考勤,可以加一张班级表,用外键关联用户,但毕设场景下两张表足够。

这里有个很容易被忽视的细节:程序启动时要检查数据库文件是否存在,不存在就自动建表。如果没有这段初始化逻辑,第一次签到会直接报“no such table”,你以为代码坏了,其实是数据库还没建。我一般会在启动处加一个 init_db 函数,用 CREATE TABLE IF NOT EXISTS 的写法保证幂等创建。

5. 避坑与常见问题排查:我从这个包里踩过的六个坑

5.1 OpenCV 与 PyQt 摄像头占用冲突

现象:PyQt 界面正常打开,一点“开始签到”,程序没有任何报错但画面全黑,或者直接卡死。原因:OpenCV 的 VideoCapture 和 PyQt 的定时器刷新机制都在争抢摄像头句柄,有时代码里上一个 cap 没有 release,导致新开的摄像头拿不到画面。解决:打开摄像头之前先检测全局变量,如果已有 cap 实例先 release;界面关闭时也要主动释放摄像头。

# 摄像头初始化时先释放旧实例,防止句柄冲突 if hasattr(self, 'cap') and self.cap is not None: self.cap.release() self.cap = cv2.VideoCapture(0) if not self.cap.isOpened(): print("摄像头打开失败,检查是否被其他程序占用") return

代码放在摄像头初始化的分支里,作用是防止重复创建 VideoCapture 对象导致句柄耗尽。为什么会出现这种情况,主要原因是一些界面操作(比如切换选项卡)没有按预期触发 closeEvent,cap 就一直留在内存里。

5.2 中文乱码或界面无响应实为字体或编码问题

现象:界面按钮上的中文全部变成方框,而且日志里出现 UnicodeEncodeError。原因:PyQt 默认字体不是中文字体,同时 Python 2 时代遗留的编码写法在 Python 3 里失效。解决:在启动文件里加载 msyh.ttf,并且在所有涉及文件路径的地方都注意不要混用中英文路径。Windows 下如果用户名为中文,某些旧库读取路径会出问题,可以考虑把项目放到纯英文路径下。

5.3 背景图白屏与按钮图片丢失

现象:主界面窗口出现了,但背景是默认灰色,导航图标也不显示。原因:QPixmap 加载图片时传入的相对路径找不到文件,加载失败返回空对象,控件 setPixmap 之后就什么都不显示。解决:同一节里介绍过的绝对路径方案,用 os.path.join(BASE_DIR, STATIC_PATH) 统一拼路径。另外检查图片文件是否存在时,不要只看文件名字,直接在系统里确认扩展名是 .png 还是 .PNG,Linux 下大小写写错会加载失败。

5.4 dlib 安装失败的编译链问题

现象:pip install dlib 时报错 error: subprocess-exited-with-error,后面跟着一堆 GCC 或 MSVC 的编译输出。原因:dlib 需要本地编译,缺少 C++ 编译工具链或 cmake 版本过旧。解决:先安装 cmake,Windows 还要安装 Visual Studio 的 C++ 桌面开发组件,macOS 装 xcode-select --install。装完编译工具再回来装 dlib,基本一次通过。别图省事用 pip 仓库里的老版本轮子,系统架构不匹配带来的问题比编译还烦。

5.5 远程运行报错而本机正常

现象:在本机 IDE 里跑得好好的,把项目拷到另一台电脑或服务器上,一运行就报 ModuleNotFoundError 或者路径找不到。原因:依赖库没装全,或者代码里用了绝对路径写死了开发机的目录结构。解决:建一个 requirements.txt 锁死依赖版本,跑新机器时先执行 pip install -r requirements.txt;同时把项目内所有写死的绝对路径改成基于 BASE_DIR 动态拼接。这一条虽然朴素,但很多同学翻车都翻在这。

5.6 考勤重复录入:同一个人一节课签到了五次

现象:摄像头画面里人没走,定时器每刷新一帧签到一次,数据库里出现同一时间段的多条重复记录。原因:签到成功后没有做状态锁定,只要人脸还在画面里,比对又通过,就会不断写库。解决:在签到成功后设置一个 session 标记,记录当前已签到用户的 ID 和签到时间,在一定间隔内同一 ID 不再重复写入。这个逻辑你放到代码里后在答辩时能讲出一个完整闭环,导师会觉得你考虑到了真实考勤场景里的业务陷阱。

6. 从高分毕设到可演示项目:二次开发的三处打磨技巧

第一处打磨,把硬编码的姓名学号列表改成可视化维护。原始项目的人脸库是通过特定目录图片导入的,每次加人要重新跑脚本。可以加一个“添加用户”面板,界面上直接输入姓名学号,点拍照入库,后台自动把图片保存到指定位置并更新特征库。这改动的代码量不大,但演示效果远超“命令行添加用户”,答辩时能直接现场录入一张脸再现场签到,说服力很强。

第二处打磨,给考勤记录加一个导出功能。PyQt 里可以调用 pandas 把数据库表读出来,再生成 CSV 文件。很多毕设项目的考勤记录只停留在“数据库里能查到”,但实际应用场景里管理员需要导出 Excel 做月度统计,这个功能一旦做了,项目就不再是演示 Demo,而是有实用价值的工具。

import pandas as pd import sqlite3 # 读取数据库中的考勤原始记录 conn = sqlite3.connect("attendance.db") df = pd.read_sql_query("SELECT user_name, sign_time, status FROM attendance", conn) conn.close() # 按用户和日期汇总签到次数 df["sign_date"] = pd.to_datetime(df["sign_time"]).dt.date summary = df.groupby(["user_name", "sign_date"]).size().reset_index(name="count") # 导出成 CSV 文件,Excel 直接打开 summary.to_csv("attendance_report.csv", index=False, encoding="utf-8-sig")

第三处打磨,调整阈值和检测频率做现场演示优化。演示时光线不如实验室稳定,如果把阈值卡得太死,台下观众站起来走近你,人脸角度一偏就可能识别失败。我的经验是正式演示前把 threshold 从 0.45 调到 0.5 左右,留出一点容忍余量;同时把界面刷新帧率从 30 降到 15,减轻摄像头处理压力,CPU 占用低一些,笔记本风扇声音小一点,现场观感会好很多。

这三处改完,项目就从一个“能跑的毕设源码”变成了“能给别人展示完整业务的考勤系统”。从那以后我每次拿到这类历史项目,都会先花半天时间拆路径、理入口、跑通主流程,再考虑改什么功能;强制自己把“代码能运行”和“项目能答辩”分开看,前者是底线,后者才是高分的关键。希望这份拆解能帮你把下载到的源码真正变成自己的作品,少走我走过的弯路,祝你的毕设一样拿高分。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询