ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Python人脸识别考勤系统实现:从MTCNN到FaceNet完整实战

Python人脸识别考勤系统实现:从MTCNN到FaceNet完整实战 简介这是一套面向计算机专业本科生的高完成度人脸识别考勤系统毕业设计源码专为毕业设计、课程设计及期末大作业打造解决传统考勤效率低、易代签等问题融合深度学习模型部署与桌面应用开发实践。资源包共25个文件含3个核心Python脚本实现人脸检测、特征提取与考勤逻辑、15张UI界面与状态图如用户列表、签到状态、背景等以及配置文件、字体、图标、API接口定义和使用手册.docx结构清晰模块职责分明便于二次开发与功能扩展。压缩包大小239.41MB已吸引190人下载学习。使用者可直接运行Ui_test_01.py启动图形界面结合config配置与face.py模型调用逻辑快速掌握基于OpenCVFaceNet或类似轻量模型的人脸识别全流程同时获得导师评审98分的完整项目范式——从需求分析、界面设计、模型集成到考勤数据管理具备强参考性与工程落地价值。 先交代一下背景这个题目我太熟了。人脸识别考勤系统几乎可以说是Python深度学习方向里最经典的毕设选题之一。你搜一下就会发现网上同类项目多到烂大街但真正能跑通、能演示、能答上答辩老师追问的少之又少。大多数所谓的“源码”要么是拿OpenCV的Haar级联糊弄一个只能检测人脸不能识别身份的Demo要么是调了个现成API假装是自己做的。这篇文章我就按照我当年实打实做一个可演示、可答辩、可扩展的Python人脸识别考勤系统的完整思路来拆包括技术选型、环境搭建、核心代码逻辑、数据库设计、UI界面、防作弊处理以及一堆不跑一遍根本发现不了的坑。这个项目适合什么人看如果你正在做人脸识别相关的毕业设计或者想从零构建一个完整的计算机视觉应用或者单纯想了解一套深度学习项目从算法到落地的全流程那这篇文章就是给你准备的。我会把每一步的“为什么”也讲清楚——毕竟答辩老师最爱问的就是你为什么选这个模型、为什么用这个阈值、为什么这么设计数据库。把这些想明白比代码本身更值钱。1. 考勤系统的整体架构别急着写代码先想清楚这几件事很多人拿到这个题目第一反应就是“人脸识别怎么实现”然后一头扎进模型的汪洋大海里。我做这个项目时最大的体会是人脸识别算法只占整个系统的一部分考勤业务逻辑才是真正决定这个系统能不能用的关键。一个完整的人脸识别考勤系统至少需要五个模块人脸检测与人脸对齐、人脸特征提取、人脸特征比对与身份识别、考勤记录管理、可视化交互界面。如果你把这几块拆开来看每一块其实都有很成熟的解决方案但把它们组装成一个稳定运行的系统难度瞬间上升一个量级。为什么要用深度学习而不是传统方法这是答辩时最容易被问到的第一个问题。传统的人脸识别方法比如Eigenfaces特征脸、Fisherfaces、LBPH都是基于手工设计的特征。LBPH的原理是提取图像的局部二值模式纹理特征然后用直方图去描述人脸。这种方案在小规模、光照稳定的场景下能用但一遇到人脸角度变化、光线剧烈变化、遮挡准确率就断崖式下跌。而深度学习模型是端到端学习的——我们喂给它大量标注好的人脸图片它自己学习哪些特征是有区分度的。这就是为什么现在工业界的人脸识别清一色都是深度学习方案。系统整体架构上我推荐从逻辑上分成三个层次底层是算法服务层负责摄像头图像采集、人脸检测、特征提取、比对识别中间层是业务逻辑层负责考勤时间判断、打卡记录写入、重复打卡检测、出勤统计顶层是交互展示层提供录入人脸、手动打卡、查看考勤记录、统计报表的界面这么划分的好处是职责清晰。算法层出问题不会污染业务数据业务逻辑变更不需要改动算法代码界面层更是可以完全独立替换。比如你后续想从PyQt5桌面端改成Web端只需要保留算法层和业务层重写一个前端即可。2. 模型选型解析为什么我用MTCNNFaceNet而不是其他方案模型选型是整个项目的灵魂。我见过很多同学在这里犯难其实选型只需要考虑三个维度识别精度、运行速度、开发成本。人脸检测阶段我推荐MTCNNMulti-Task Cascaded Convolutional Networks。这个名字听起来唬人原理其实很清晰它通过三个级联的卷积网络——P-Net、R-Net、O-Net——逐级精细化地找出人脸位置。P-Net快速生成大量候选框R-Net过滤掉大部分误检O-Net做最终的人脸框回归和关键点定位左眼、右眼、鼻尖、左嘴角、右嘴角。这三步下来既能保证检测速度又能输出对齐人脸所需的五个关键点。这里有一个细节容易被忽视脸部对齐对识别准确率的影响极大。同样的一个人脸歪了5度和正对着镜头提取出来的特征差异可能比两个不同人的差异还大。MTCNN输出的五个关键点正好可以做人脸仿射变换把脸部旋转到标准位置。人脸特征提取阶段市面上的主流选择有三个FaceNet、ArcFace、SphereFace。我选FaceNet是因为它的平衡性最好而且开源生态完善。FaceNet的核心思路是训练一个卷积神经网络把一张人脸图片映射到一个128维的欧几里得空间向量。训练时用三元组损失Triplet Loss——同一个人的两张脸正样本对在向量空间中的距离要近不同人的两张脸负样本对的距离要远。经过充分训练后这个128维向量就成了一个人脸的“数字指纹”。为什么用什么模型就得用什么代码因为不同模型产出的特征向量维度不同、分布不同直接混用会导致比对结果毫无意义。FaceNet有多个预训练版本我建议用基于LFW数据集训练且在VGGFace2上微调的版本它在真实场景下的泛化能力更好。如果追求更极致的精度可以换用ArcFace它的优点是用附加角边距损失让类内更紧凑、类间更分散但相应的模型文件更大、推理速度稍慢。对于考勤这种对实时性有一定要求的场景FaceNet足够。特征比对阶段最直观的方法是计算余弦相似度。人脸向量A和人脸向量B的余弦相似度定义为sim(A, B) (A·B) / (|A| × |B|)取值范围是[-1, 1]越接近1代表两个人脸越相似。实际操作中把相似度阈值设为0.55到0.65之间比较合理。阈值设得越低识别率越高但误识率也越高阈值设得越高系统越严格但容易把人拒之门外。考勤场景建议阈值取0.6既避免学生恶搞换脸打卡蒙混过关又不会因为光线稍变就认不出人。这个阈值不是一个拍脑袋的数字而是可以用一批测试样本去标定的采集20个人的脸每人拍5张不同光线角度的照片统计类内相似度和类间相似度的分布取两者分界处的值作为阈值。3. 环境搭建与依赖管理这步踩坑最多细说这个项目的环境配置是全流程最容易劝退新手的环节。我先给出我验证过完全可行的组合再解释为什么这么搭配。推荐软硬件环境如下操作系统Windows 10/11 或 Ubuntu 20.04/22.04 均支持但强烈建议用Linux做训练和推理环境变量和依赖冲突要少很多Python版本3.8到3.10不要用3.11以上有些深度学习库对高版本Python的预编译包支持不及时深度学习框架PyTorch 1.12或2.x皆可PyTorch的生态和社区支持比TensorFlow更适合快速落地人脸检测与对齐MTCNN开箱即用人脸特征提取FaceNet的PyTorch实现facenet-pytorch库图像处理与摄像头读取OpenCV-PythonGUI界面PyQt5如果你只想快速出效果也可以用Streamlit做Web界面依赖安装命令我建议这样写pip install opencv-python torch torchvision facenet-pytorch pip install PyQt5 pymysql # 或者改sqlite3后面讲为什么这里面最大的坑是facenet-pytorch的依赖。它会自动拉取torch和torchvision如果你之前装过CPU版torch再装facenet-pytorch时可能会把torch覆盖成最新版导致CUDA版本不匹配。最稳妥的做法是先装好torchGPU版或者CPU版都行再装facenet-pytorch时加个--no-deps参数跳过依赖检查pip install facenet-pytorch --no-deps另一个大坑是OpenCV的摄像头索引问题。笔记本自带摄像头通常是索引0外接USB摄像头可能是1某些电脑上0和1都不工作。我写了一个小函数来探测可用摄像头索引后面放在工具类里。提示Ubuntu用户如果pip install后import cv2报错libGL.so.1: cannot open shared object file执行sudo apt-get install libgl1 libglib2.0-0即可解决。这是OpenCV在Linux下最常见的报错之一。4. 数据集准备与人脸注册流程不是训练但要做得像训练一样认真这里必须先纠正一个误区用预训练模型做人脸识别绝大多数情况下不需要自己训练模型。FaceNet预训练模型已经在海量人脸数据上学到了足够强大的特征表达能力我们要做的只是用它来提取特征。所以很多毕设当中“训练自己的模型”这个环节其实是可以省掉的——答辩时你可以明确说“本项目采用迁移学习策略在大型公开人脸数据集预训练的FaceNet模型基础上进行人脸特征的提取与比对”。那么真正要做的“数据工作”是什么是构建人脸库。具体来说每个需要考勤的人录入若干张包含不同姿态、不同光照的人脸照片然后为每个人的照片集合提取特征向量取平均作为该人的标准人脸特征向量存入数据库。录入照片时有一些讲究。我测试下来一个人录入3到5张照片比较合适太少会导致特征向量不稳定太多则会让平均特征偏向某些拍摄条件。拍摄角度建议一张正脸、两张左右各偏移15度左右、一张略微俯仰角度变化的光线尽量模拟实际考勤场景的光线条件。如果实际考勤场景光线偏暗录入照片时也最好在类似暗光条件下拍。人脸注册的核心逻辑代码整理成一个可复用的类class FaceRegister: def __init__(self, model, detector): self.model model self.detector detector def register_face(self, image_path, person_id): img cv2.imread(image_path) img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # MTCNN检测人脸框和关键点返回概率和位置 boxes, probs, landmarks self.detector.detect(img_rgb, landmarksTrue) if len(probs) 0 or probs[0] 0.9: return None # 用关键点做人脸对齐 aligned self.detector.extract(img_rgb, [boxes[0]], [landmarks[0]]) if aligned is None or len(aligned) 0: return None # 提取特征向量先归一化再转numpy embedding self.model(torch.tensor(aligned).permute(0, 3, 1, 2).float()) embedding embedding.detach().numpy().flatten() # L2归一化让特征在超球面上均匀分布 norm np.linalg.norm(embedding) embedding embedding / norm return embedding这里有一个小技巧提取特征后一定要做L2归一化。FaceNet的原始输出向量长度可能各不相同直接计算余弦相似度会受向量模长影响归一化后余弦相似度才完全由向量方向决定更纯净地反映人脸相似程度。所有录入照片的向量都归一化后再平均得到的人脸标准特征也保持单位长度后续比对结果才稳定。人脸库的数据表我推荐这样设计字段名类型说明idINTEGER PRIMARY KEY自增主键person_idVARCHAR(20) UNIQUE工号/学号nameVARCHAR(50)姓名face_vectorBLOB128维特征向量用pickle序列化后存储photo_pathVARCHAR(255)原始照片路径方便回溯register_timeDATETIME注册时间这里我推荐用SQLite而不是MySQL。对毕设而言SQLite足够而且零配置文件、零服务进程拷到答辩机器上就能跑不会出现演示现场连不上数据库的尴尬。但如果你想体现工程能力可以用MySQL的pymysql接口代码差异也就是一个数据库连接对象的区别。5. 实时人脸识别与考勤系统核心逻辑从一帧画面到一条打卡记录识别流程是整个系统的主干。从摄像头读取一帧图像到生成一条考勤记录中间经过人脸检测、对齐、特征提取、特征比对、身份判定、考勤业务判断六个环节。把这个链路的代码写清楚整个项目的核心就完成了。先看识别模块的代码骨架class FaceRecognizer: def __init__(self, threshold0.6): self.device torch.device(cuda if torch.cuda.is_available() else cpu) self.detector MTCNN(keep_allTrue, deviceself.device) self.model InceptionResnetV1(pretrainedvggface2).eval().to(self.device) self.threshold threshold self.face_db self._load_face_db() def recognize(self, frame): img_rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) boxes, probs, landmarks self.detector.detect(img_rgb, landmarksTrue) results [] if boxes is None: return results for i, (box, prob) in enumerate(zip(boxes, probs)): if prob 0.9: continue aligned self.detector.extract(img_rgb, [box], [landmarks[i]]) if aligned is None or len(aligned) 0: continue embedding self.model(torch.tensor(aligned).permute(0, 3, 1, 2).float()) embedding embedding.detach().numpy().flatten() norm np.linalg.norm(embedding) embedding embedding / norm # 与库中所有人脸比较找到最高相似度 best_id, best_sim self._match(embedding) if best_sim self.threshold: results.append((best_id, best_sim, box)) return results为什么每次摄像头画面都要重新检测人脸而不是用跟踪器因为考勤场景下人员来回走动、遮挡等情况频繁跟踪器一旦丢框就很难恢复。直接每帧检测的计算开销其实完全可控。在CPU上MTCNN加FaceNet的完整推理大约400到600毫秒每帧有GPU加速时能跑到100毫秒左右。考勤不必追求视频流的每秒30帧实时刷新3到5帧每秒的处理速度已经足够流畅。接下来是考勤业务逻辑。这里有几个边界条件必须处理同一人在短时间内的重复打卡、上下班时间的判定、缺卡的处理逻辑。我设计的时间判断规则如下上班迟到判定时间09:00之后打卡算迟到下班早退判定时间18:00之前打卡算早退重复打卡窗口5分钟内重复识别同一个人只记录第一条避免人在摄像头前晃来晃去触发多次打卡缺卡判定当天只有上班卡没有下班卡的下班记录置为“未打卡”重复打卡的判定在代码里需要维护一个内存缓存表我用字典模拟了最近打卡人脸的记录class AttendanceService: def __init__(self): self.recent_records {} # person_id - (timestamp, status) def process_check_in(self, person_id, current_time): # 5分钟内重复打卡不记录 if person_id in self.recent_records: last_time, last_status self.recent_records[person_id] if (current_time - last_time).total_seconds() 300: return False, 重复打卡 # 正常记录逻辑... }考勤记录表的结构也要提前设计清楚字段名类型说明idINTEGER PRIMARY KEY主键person_idVARCHAR(20)工号check_dateDATE考勤日期check_in_timeDATETIME上班打卡时间check_out_timeDATETIME下班打卡时间statusVARCHAR(20)正常/迟到/早退/缺卡每天上下班各生成一条记录还是合并成一条记录包含上下班两个字段我建议后者因为考勤统计出勤天数、迟到次数时按天聚合更直观。具体实现时上班打卡时插入一条记录下班打卡时更新对应日期记录的check_out_time字段。6. UI交互界面设计让答辩老师看得懂比炫技更重要很多同学的注意力全在算法上界面做得极其简陋。但实际答辩时评审老师对系统好不好用、界面是否友好的关注度往往高于算法本身。一个干净、清晰的交互界面能在演示环节加不少印象分。我的界面分成三个页签人脸注册、实时考勤、考勤记录查询。人脸注册页签的核心操作流是输入工号和姓名点击“拍照注册”按钮摄像头捕捉当前画面自动检测人脸并提取特征确认相似度足够高后保存到数据库。这里我加了一步人工确认提示框“确定保存该人脸信息吗”——这能防止误操作把模糊的照片存入人脸库导致后续识别率下降。实时考勤页签是系统的主界面。摄像头画面居中显示识别到人脸后在画面中用矩形框标出人脸位置旁边实时显示姓名和相似度。当判定为合法考勤时画面下方滚出一条打卡成功的记录包含工号、姓名、打卡时间、考勤状态四个字段。整个逻辑我建议用PyQt5的QTimer周期性刷新帧画面避免用多线程操作Qt控件引发的崩溃问题。考勤记录查询页签做一个表格支持按日期区间筛选、按工号筛选。还可以做一个简单的统计功能显示选定时间范围内的应出勤天数、实际出勤天数、迟到次数、早退次数。这个功能看起来简单但在答辩演示时效果很好——直接展示一个月的统计报表比口头解释系统功能有说服力得多。界面的线程模型是PyQt5开发最容易踩坑的地方。人脸识别是耗时操作如果在主界面线程里直接跑界面会卡死摄像头画面会像幻灯片一样一顿一顿的。解决办法是把视频帧采集和人脸识别放到QThread工作线程里识别结果通过信号槽机制传回界面线程更新显示。信号槽千万不能直接传numpy数组给界面更新因为Qt的跨线程对象传递有开销我实际测试下来直接传会掉帧正确做法是传图片的字节流或base64编码。不过这个性能问题只在低配机器上明显如果你的演示机器配置不错直接传numpy数组问题也不大。7. 活体检测与防作弊设计考勤系统必须过的一道关人脸识别考勤系统在实际使用中面临的最大挑战是“照片攻击”——拿一张打印出来的照片、手机屏幕上的照片甚至一段录制视频对准摄像头就能冒充他人打卡。如果毕设答辩时被问到“你的系统怎么防止学生用照片代打卡”答不上来会很尴尬。我在这个项目里做了一个简单但有效的防作弊方案利用OpenCV的眨眼检测。原理是人在自然状态下会周期性眨眼而照片和视频里不存在这种自然规律。检测到的连续多帧画面中如果检测到眼睛的纵横比EAREye Aspect Ratio出现明显的周期性变化判定为活体如果眼睛长时间处于同一个开合状态判定为照片攻击。EAR的公式是EAR (|p2 - p6| |p3 - p5|) / (2 × |p1 - p4|)其中p1到p6是眼睛轮廓六个关键点。睁眼时EAR大约在0.25到0.35之间闭眼时EAR降到0.1以下。连续检测到EAR从正常值掉到低值再回到正常值且这个周期在1到3秒内出现就认为有眨眼动作。这个方案在工程上很好落地因为MTCNN已经输出了眼睛的位置再用dlib的68点面部关键点检测器可以精确计算出六个眼睛轮廓点。实现代码大致是def eye_aspect_ratio(eye): # 计算垂直距离和水平距离之比 vertical1 np.linalg.norm(eye[1] - eye[5]) vertical2 np.linalg.norm(eye[2] - eye[4]) horizontal np.linalg.norm(eye[0] - eye[3]) return (vertical1 vertical2) / (2.0 * horizontal)活体检测模块要结合到识别流程中只有当人脸识别相似度超过阈值且活体检测判定为真人时才允许打卡成功。这个逻辑的先后顺序有讲究——先做人脸识别因为速度快拒绝掉大量不匹配的帧识别通过后再做活体检测因为活体检测需要连续观察多帧开销更大。先粗筛再细筛整体性能最优。注意仅靠眨眼检测无法防御高级的深度伪造视频和3D面具攻击但对毕设场景来说这个防作弊方案已经足够有说服力。答辩时你可以主动说明这一点然后补充说工业级方案会结合红外摄像头或3D结构光摄像头来做更可靠的活体判断这反而能体现你对方案局限性的清醒认识。8. 踩坑实录这些问题不跑一遍根本发现不了这个项目的坑我当年踩得七七八八挑最值得说的几个记录下来希望你能少走弯路。第一个坑是dlib和OpenCV的版本冲突。dlib在Windows下编译很痛苦需要Visual Studio Build Tools配合CMake。我建议直接用pip install dlib安装预编译版本不要自己编译。装好后立刻验证跑一个68点关键点检测确认导入成功。常见报错是AttributeError: module dlib has no attribute get_frontal_face_detector这种情况多半是dlib版本太老升级到最新版即可。第二个坑是摄像头打开后不释放。PyQt5程序在打开摄像头后如果异常退出摄像头资源没有释放下次再运行会报Unable to capture video (0)。我在程序里写了信号槽来捕获窗口关闭事件确保在退出时执行cap.release()和cv2.destroyAllWindows()。另外如果摄像头被其他程序占用比如你开着Windows相机应用OpenCV也会打不开摄像头。这个排查技巧很实用关闭所有可能占用摄像头的程序再试。第三个坑是人脸特征库的存储方式。把128维numpy数组存进SQLite时不能直接存数组对象需要序列化。我用的方案是pickle.dumps()后再存BLOB字段读取时pickle.loads()还原。还有一种更省空间的思路是把128个浮点数拼接成字符串存TEXT字段但解析性能和空间效率都不如BLOB方案。第四个坑是多人同时出现在画面时的识别逻辑。默认实现是循环检测到的所有人脸逐一与数据库比对。如果画面里有5个人但只有1个人在考勤系统会给其他4个人也做识别流程浪费不少算力还可能因为某个人恰好匹配到库里的人脸而导致误打卡。我的解决方案是加一个人数判断当画面中检测到多张人脸时只处理离摄像头最近的人脸通常面积最大的边界框。这样既避免了算力浪费也大大降低了误打卡概率。如果你想让系统支持多人同时打卡就需要把重复打卡的时间窗口和并发写入逻辑做得更健壮这属于进阶功能毕设阶段做到单人串行打卡已经足够。第五个坑是不同人脸库之间的兼容性。facenet-pytorch用的是InceptionResnetV1输出的128维向量是基于VGGFace2训练的。如果你后面换用了其他FaceNet实现比如基于Keras的版本特征向量的语义空间完全不同两个库的人脸无法互相比对。这解释了为什么最好不要混用多种实现。9. 性能调优与部署注意事项从“能跑”到“跑得稳”项目做完能运行只是第一步你还得让它稳定运行足够长的时间才能应付答辩演示的持续要求。我这里给出几组实测数据供参考。在一台Intel i5-1240P CPU无独立GPU的笔记本上640x480分辨率的视频流完整的人脸识别流程MTCNN检测 FaceNet特征提取 余弦比对大约需要450ms/帧。也就是说每秒能处理2帧多一点的画面。作为考勤场景这个速度完全够用——人站在摄像头前1到2秒就能完成识别体验还算流畅。如果你想让识别速度更快有两条路一是缩小输入图像尺寸把摄像头帧从640x480缩小到320x240MTCNN的检测速度明显提升识别精度下降不明显。二是把MTCNN的置信度阈值从0.9降到0.85减少漏检但这会轻微增加误检率非关键场景下用0.9稳妥。GPU加速方面如果演示机器有NVIDIA显卡装上CUDA版PyTorch后整个流程能提速到100ms以内。但有一个坑CUDA版PyTorch的安装包较大下载时间较长而且要和GPU驱动版本匹配。答辩前一定要提前装好、提前测好不要在演示现场折腾环境。如果没有GPUCPU跑完全够用没必要为了追求性能去装CUDA。系统长时间运行时的资源管理也是坑。我测试时发现程序运行超过一个小时后内存占用会缓慢增长最后稳定在一个较高的水平。原因是每一帧的图像数据和特征向量都会在内存中被保留直到Python的垃圾回收器运行。如果界面线程和识别线程之间通过队列传递数据队列中的未消费数据会累积。我的解决办法是每处理完一帧就显式删除不再需要的变量并且控制帧队列的最大长度超出则丢弃旧帧。代码里加一行frame_queue queue.Queue(maxsize2)就解决了一部分问题。打包成可执行文件的问题也要提前考虑。如果用PyInstaller打包因为项目依赖torch和facenet-pytorch等大型库打包后的exe体积会非常大1GB以上而且经常因为动态链接库缺失导致运行失败。我的建议是不要打包答辩时直接用源码运行。如果老师要求交可执行文件再单独处理PyInstaller的说明文件问题——具体做法是完全可行但比较耗时需要把模型文件、dlib的dll都打包进exe。10. 从毕设源码到真实项目代码结构的优雅度决定你能走多远很多人的毕设代码是“能跑就行”所有逻辑杂糅在几个文件里连函数标注都没有。这种代码应付答辩可能够了但一旦想在此基础上扩展功能或者写进简历作为项目经验就会暴露出很多问题。我建议在完成功能后至少做一次代码结构梳理把识别、考勤、界面、数据库拆成四个独立的模块这样每个模块都方便单独测试和复用。我最终的项目目录结构是这样的attendance_system/ ├── main.py # 程序入口负责初始化和启动GUI ├── config.py # 全局配置阈值、路径、数据库名 ├── models/ │ ├── __init__.py │ ├── face_detector.py # MTCNN封装 │ ├── face_embedder.py # FaceNet封装 │ └── face_recognizer.py # 识别流程编排 ├── services/ │ ├── __init__.py │ ├── attendance_service.py # 考勤业务逻辑 │ └── database_service.py # 数据库操作 ├── ui/ │ ├── __init__.py │ ├── main_window.py # 主窗口框架 │ ├── register_tab.py # 注册页签 │ ├── attendance_tab.py # 考勤页签 │ └── records_tab.py # 记录查询页签 └── utils/ ├── __init__.py ├── camera.py # 摄像头管理 ├── liveness.py # 活体检测 └── helpers.py # 公共工具函数这种分层结构有几个好处。第一config.py集中管理所有参数调阈值、改数据库名不用翻代码。第二models层和services层分离意味着后续换掉人脸识别算法比如从FaceNet换成ArcFace考勤业务代码一行都不用改。第三答辩时老师问“你的系统怎么扩展”你可以直接用这个结构回答算法接口是抽象的换模型只需要实现新的识别类即可。如果你时间充裕还可以在这个基础上加三个亮点功能一是报表导出Excel把考勤统计结果导出成表格文件方便查看二是邮件通知当天缺卡的人自动发提醒邮件三是云端数据同步用阿里云OSS或宝塔面板做数据库和照片的备份。这几个功能都是加分项实现难度不高但能体现项目的工程完整性。11. 写在最后的实操心得说实话做这个项目最费时间的地方不是写代码而是调试各种环境问题。我记得有个下午花了三个小时找Bug到最后发现是OpenCV按BGR读取图片而MTCNN检测时内部转为RGB颜色通道顺序不一致导致人脸检测率异常低。这种低级但隐蔽的错误在你没经验的时候就是死活发现不了。所以我想特别的提醒你一句遇到糟糕的效果先回到“数据流”层面检查每一环节的输入输出是什么格式、什么形状再怀疑算法本身。另外做毕设最重要的一件事就是尽早搭出最小可用版本。不要想着一次性把活体检测、报表统计、多人并发识别全做完而是先跑通“摄像头抓拍、识别出人、保存记录”这条主链路再逐步加功能。主链路通了你心里就有底了后面加功能都是锦上添花。最后再分享一个小技巧做一个演示专用的“快速模式”把人脸识别流程中所有不必要的打印日志关掉关闭实时状态栏的频繁刷新让摄像头画面更流畅。答辩时给别人展示一个“行云流水”的系统和展示一个“每识别一张脸卡顿一下”的系统观感完全不一样。这些都是细节但细节决定分数。希望这个项目对你不仅有“源码”层面的参考价值更能帮你在答辩现场从容应对每一个追问。本文还有配套的精品资源点击获取
返回列表