简介一套基于人脸识别的学生考勤签到管理系统采用Python实现面向计算机网络课程设计、毕业设计或课设作业场景适合计算机、人工智能、数据科学等专业学生及教师参考使用。资源包共160个文件约10.16MB包含Python源码py/pyc、运行演示视频mp4、课程设计报告docx、项目说明md及数据库db等核心代码已通过功能验证可直接运行并支持二次开发。系统实现人脸录入、训练、识别签到、签退和哈希加密等功能并配有服务端与客户端架构涵盖考勤数据上传、存储与基础分析。随附运行视频与课设报告便于快速复现和答辩讲解当前已有270人浏览学习。适合用于学习人脸识别、Socket通信、数据库管理以及完整项目结构梳理也是初期立项演示和期末大作业的实用素材。1. 人脸识别考勤系统这套 Python 源码跑通它需要先弄清四层结构期末做计算机网络课程设计的人都有体会题目不能太水又不能大到做不完。基于人脸识别的学生考勤签到管理系统就是这类题目里的常见选择——技术面上它横跨 OpenCV 人脸识别、Python socket 通信、SQLite 数据落库三块课设报告里能写的东西也多。这份资源的完整度在于它是跑通之后才打包的源码、运行视频、课设报告三件套齐全server 端主程序是 main.pyclient 端主程序是 cilent.py源码里就是这个拼写默认走本机 127.0.0.1:12345。适合想拿现成源码改改交课设、或者第一次接触人脸识别想做二次开发的学生。网上课设源码最怕买回来跑不起来我拆了一遍之后把环境配置、启动顺序和主要坑位记在下面。2. 客户端-服务端架构与数据链路12345 端口背后发生了什么这套系统不是一个单机脚本而是严格分成 client 端和 server 端两级结构的网络程序。要把它跑通先得理解两端各自管什么、数据从摄像头到数据库中间走了几步不然遇到报错根本不知道去查哪一边。2.1 两级架构cilent 端与 server 端各自负责什么cilent 端主程序是 cilent.py负责所有与人脸相关的操作调用摄像头采集人脸、用 haar 级联文件定位人脸区域、提取特征并与训练好的 yml 模型比对以及把签到结果打包发送给 server。简单说一切需要看和算的活都在客户端完成。server 端主程序是 main.py负责接收客户端传来的数据并写入 testDB.db 数据库相当于整个考勤数据的中转站和仓库。两端之间通过 TCP socket 通信默认绑定 127.0.0.1、端口 12345。这种架构的价值在于考勤数据不在本地留存量——客户端识别完成后只把结果发给服务端数据库统一由服务端维护。即使某台客户端机器坏了只要服务端数据库还在历史考勤记录就不会丢。课设报告里写实现了考勤数据的安全和可信指的就是这层设计。如果在答辩时被问到为什么不用单机版这个理由可以直接用。2.2 通信链路与数据落库从签到动作到 testDB.db一次完整签到的数据流是这样的客户端摄像头捕获画面 → haar 级联定位人脸 → LBPH 模型预测出学生 ID 和置信度 → 程序根据置信度判断识别是否成功 → 成功后把学生 ID、时间戳、签到类型签到/签退封装成消息 → 通过 socket send 发给 server → server 端监听线程收到消息后解析写入 testDB.db。testDB.db 是 SQLite 数据库文件整个项目的数据表都在里面。课程设计报告里说过数据库模块是服务端的一部分签到记录、签退记录、学生信息都存在这里。用 SQLite 而不是 MySQL 的好处是零配置不用额外起数据库服务对课程设计和毕设演示来说足够轻量。如果你后续想扩展可以直接用 sqlite3 命令行或 DB Browser 打开这个文件查看表结构这一点后面讲二次开发时会再提。下面是这套工程的文件构成解压后对照着检查缺哪一个都跑不起来文件/目录作用缺失后果cilent.py客户端主程序无法启动人脸识别端main.py服务端主程序无法接收签到数据haarcascade_frontalface_default.xml人脸定位模型文件摄像头检测不到人脸testDB.dbSQLite 数据库签到记录无法落库课程设计报告.docx课设文档交作业缺材料运行视频演示基线无法对照验证注意一个细节haarcascade_frontalface_default.xml 必须放到 client 端的项目根目录中才能定位人脸。OpenCV 的 detectMultiScale 方法加载这个 xml 用的是相对路径一旦文件位置不对程序不会报错但会一直检测不到人脸。这个坑在排错章节还会展开。3. 从解压到首次签到环境配置与启动顺序很多人拿到源码第一件事就是双击运行这是课设源码最容易翻车的开场。正确顺序是先配环境再启动服务端最后启动客户端。每一步都要确认到位别跳过。3.1 环境依赖与 pip.ini先把基础库装对这套系统基于 Python OpenCV核心依赖包括 opencv-python负责摄像头调用和人脸识别、numpy图像数据处理、pyzbar 或类似库要看实际版本是否需要。包里带了 pip.ini 文件说明作者在打包时已经在处理 pip 源的问题——国内网络环境下直接 pip install 经常超时配置镜像源能省大量时间。我一般会先建议建立一个干净的环境# 建议用 Python 3.8 或 3.9太高的版本有时会遇到 opencv 轮子兼容问题 python -m venv venv venv\Scripts\activate # 安装核心依赖版本号按你本机情况可适当放宽 pip install opencv-python pip install numpy pip install Pillow # 如果程序里用了界面库还需要安装 PyQt5 或 tkintertkinter 一般自带依赖装完后打开 pip.ini 看看它的配置。这个文件本质上是 pip 的配置文件它存在的意义是让 pip 从国内镜像站拉包而不是访问默认源。如果你自己装依赖时报超时可以参考它的写法把 global.index-url 指向清华或阿里云镜像。这里要注意pip.ini 本身的格式是标准的 INI 格式不要随意改缩进否则 pip 会直接忽略这个文件。3.2 启动顺序先 server 后 client 的固定流程两端程序对启动顺序是有要求的。必须先启动 server 端让它进入监听状态再启动 client 端去连接。反过来操作的话client 端连接会被拒绝直接抛 ConnectionRefusedError。# 终端一启动服务端 python main.py # 终端二等服务端显示监听成功后再执行启动客户端 python cilent.py如果程序带图形界面启动后应该能看到对应的窗口如果是控制台程序服务端会打印类似监听中的日志。源码打包好的两个 exe 默认也走 127.0.0.1:12345所以如果只是本机演示不需要改任何 IP 配置。想换端口的话注意客户端和服务端要一起改两端的端口号必须一致这是 socket 通信的基本约束。3.3 运行视频对照判断系统是否正常工作的基线包里附带的运行视频就是官方演示基线。我第一次跑通后是拿运行视频逐帧对照的视频里摄像头启动要几秒、录入界面长什么样、训练完成打印什么提示、签到识别时控制台输出什么信息。这些细节全对齐了才说明你本机的环境跟作者一致。如果视频里能正常识别而你本机识别不了优先排查两个方向一是摄像头权限有没有开——Windows 下有些笔记本的摄像头隐私设置默认关闭OpenCV 打开设备时会返回空帧二是 haarcascade 文件路径。这两个问题占了这类项目编译过了但跑不出结果的八成原因。4. 人脸识别三阶段拆解录入、训练、签到的代码路径人脸识别不是单一算法而是检测-特征提取-比对三段式流程。这套系统做得比较规矩录入、训练、签到是三个独立环节每个环节对应独立的代码路径。搞清楚这三段你才有能力改代码、换模型、修 bug。4.1 人脸录入通过 haar 级联定位并保存样本录入阶段的目的是给每个学生采集一批人脸样本图片。代码逻辑上用 VideoCapture 打开摄像头逐帧检测人脸把检测到的人脸区域裁剪后保存为灰度图。下面是常见实现的骨架import cv2 # 加载人脸检测器xml 文件必须放在项目根目录 face_cascade cv2.CascadeClassifier(haarcascade_frontalface_default.xml) cap cv2.VideoCapture(0) # 0 表示默认摄像头 face_id input(请输入学生ID: ) count 0 while True: ret, frame cap.read() if not ret: print(摄像头读取失败请检查设备权限) break gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # detectMultiScale 参数缩放比例 1.1最小邻居 5最小人脸尺寸 100x100 faces face_cascade.detectMultiScale(gray, scaleFactor1.1, minNeighbors5, minSize(100, 100)) for (x, y, w, h) in faces: cv2.rectangle(frame, (x, y), (xw, yh), (255, 0, 0), 2) count 1 # 保存时统一转为灰度图减小数据量也便于后续 LBPH 训练 cv2.imwrite(fdataset/User.{face_id}.{count}.jpg, gray[y:yh, x:xw]) cv2.imshow(face register, frame) if cv2.waitKey(1) 13 or count 50: # 回车或采满50张结束 break cap.release() cv2.destroyAllWindows()detectMultiScale 的四个关键参数决定了人脸检测的效果scaleFactor 是每次缩放的比例越大检测越快但容易漏检minNeighbors 是每个区域最少被检测到的次数越大误检越少但可能漏掉侧脸minSize 控制最小人脸尺寸太小人脸会被忽略。课程设计场景下1.1 / 5 / (100, 100) 这组参数是经过较多验证的起点如果检测不到人脸先把 minSize 调小到 (80, 80) 试试。录入样本统一存灰度图是因为 LBPH 特征本身基于灰度纹理彩色信息在训练时用不上存灰度图还能省一半磁盘空间。4.2 模型训练LBPH 特征提取与 yml 文件生成训练阶段读取采集到的样本用 LBPH局部二值模式直方图算法提取特征最后生成一个 yml 文件作为识别模型。这部分代码的核心是 OpenCV 的 face 模块import cv2 import os import numpy as np recognizer cv2.face.LBPHFaceRecognizer_create() face_cascade cv2.CascadeClassifier(haarcascade_frontalface_default.xml) faces, ids [], [] # 遍历数据集目录文件名格式 User.ID.序号.jpg for root, dirs, files in os.walk(dataset): for file in files: path os.path.join(root, file) img cv2.imread(path, cv2.IMREAD_GRAYSCALE) # 从文件名解析学生ID这是录入时约定的命名规范 id int(file.split(.)[1]) faces.append(img) ids.append(id) # train 方法接收两个 list图像列表和对应的标签列表 recognizer.train(faces, np.array(ids)) recognizer.write(trainer.yml) print(f训练完成共处理 {len(faces)} 张样本)LBPH 的原理是把图像划分成小块在每个块内计算 LBP 纹理特征再统计成直方图最后拼接成整个图像的特征向量。它不依赖深度学习框架纯 OpenCV 就能跑对课程设计来说部署成本最低。识别器训练完通过 write 方法持久化到 yml 文件之后签到阶段直接读取这个文件不用重新训练。LBPH 内部有几个可调参数radius 决定 LBP 算子的采样半径默认 1改大到 2 会捕捉更大范围纹理但可能损失细节neighbors 是采样点数量默认 8grid_x 和 grid_y 决定直方图分块数默认 8×8。分块越多特征越细但计算量也越大。课设场景默认参数足够不需要动。4.3 刷脸签到预测结果与考勤记录写入签到阶段是训练模型的直接应用。摄像头捕捉实时画面检测到人脸后送入 recognizer.predict 进行比对返回 label 和 confidence 两个值然后根据 confidence 判断是否通过import cv2 import hashlib import socket import time recognizer cv2.face.LBPHFaceRecognizer_create() recognizer.read(trainer.yml) face_cascade cv2.CascadeClassifier(haarcascade_frontalface_default.xml) # 连接服务端IP 和端口要与 main.py 保持一致 client socket.socket(socket.AF_INET, socket.SOCK_STREAM) client.connect((127.0.0.1, 12345)) cap cv2.VideoCapture(0) while True: ret, frame cap.read() gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) faces face_cascade.detectMultiScale(gray, 1.1, 5, minSize(100, 100)) for (x, y, w, h) in faces: pred_id, confidence recognizer.predict(gray[y:yh, x:xw]) # LBPH 的 confidence 是距离值越小越匹配80 以下通常可视为同一个人 if confidence 80: now time.strftime(%Y-%m-%d %H:%M:%S, time.localtime()) # 对签到时间做哈希防止明文传输被篡改 digest hashlib.sha256(f{pred_id}-{now}.encode()).hexdigest() msg f{pred_id}|{now}|sign_in|{digest} client.send(msg.encode()) cv2.putText(frame, fID:{pred_id} OK, (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) 27: # ESC 退出 break cap.release() cv2.destroyAllWindows()这段代码里最关键的是 confidence 阈值的理解。LBPH 的 predict 返回的置信度本质上是一个距离值数值越小表示待识别图片与训练样本越接近与深度学习里置信度越高越好的直觉相反。作者在课设报告里强调防止人脸识别的错误或失败实操层面主要就体现在这个阈值怎么调。80 是常见起点调大到 100 会减少误拒但增加误认调小到 60 则更严格但容易导致识别不出。最好的做法是采集 10 张自己的脸做一轮测试看正常情况下 confidence 落在什么区间再定阈值。msg 里携带的哈希值是用 hashlib 计算的消息摘要服务端收到后可以校验数据有没有被中间人篡改这也是哈希加密功能在系统里的实际落点。4.4 哈希加密密码与签到数据的散列落库哈希加密是这个项目里比较容易被忽略但答辩常问的功能点。它有两个应用位置一是用户密码存储不存明文而是存 SHA-256 或 MD5 散列值这样即使数据库泄露也无法直接拿到原始密码二是签到记录传输对学生ID时间戳做哈希作为消息完整性校验字段。常见做法是使用 hashlib 库import hashlib # 注册时对密码做单向散列 password 123456 salt fixed_salt # 正规做法是每个用户随机盐值 hashed hashlib.sha256(f{salt}{password}.encode()).hexdigest() # 验证时重新计算散列与库中存储值比对 def verify_password(input_pwd, stored_hash): return hashlib.sha256(f{fixed_salt}{input_pwd}.encode()).hexdigest() stored_hash要理解的一点是哈希是摘要算法不是加密算法。哈希过程不可逆加密通常意味着可以解密回原文。答辩时如果被问到哈希和加密的区别这个回答比单纯说我用了 sha256要加分。另外我这里写的是固定盐实际安全要求高的场景应该用 os.urandom 为每个用户生成随机盐存库时把盐和散列值一起存。5. 避坑记录打包失败的三个功能与运行期的五类报错这套资源最诚实的地方在于作者在说明里直接列了打包失败的功能。很多人下载课设源码不看这段结果在演示时点了一个不存在或不可用的按钮当场翻车。下面把我在拆解过程中遇到的和从源码说明里确认的坑位统一归类每条按现象 → 原因 → 解决给到可操作的方案。5.1 打包失败说明别忽略这三个功能在演示版里是被阉割的项目说明里明确写了三个打包失败的功能教师端刷新查看、多用户签到、用户画像展示。现象是打包后的 exe 里这些功能要么没有入口要么一点就崩原因是三个功能分别依赖并行库multiprocessing、消息队列和 socket 长文本传输PyInstaller 打包时对这些场景的支持不稳定。解决思路是演示时用源码模式跑不要用打包好的 exe 去展示这三个功能。如果你需要用到多用户并发签到不要依赖打包文件直接源码运行并在服务端做并发测试——说明文件里写得很清楚消息队列有的电脑能运行有的不行这种环境相关的问题短期内无解别在上面耗时间。5.2 摄像头画面正常但检测不到人脸现象摄像头能打开画面也在实时刷新但画面里始终没有矩形框控制台也不输出任何识别信息。原因第一是 haarcascade_frontalface_default.xml 没有放在客户端根目录下detectMultiScale 找不到级联分类器但 OpenCV 对这种情况未必会报错有时候只是内部引用异常第二是摄像头分辨率太高导致人脸尺寸小于 minSize 设置。解决先把 xml 文件路径改为绝对路径测试确认有效后再改回相对路径并保持文件在根目录如果人脸确实离摄像头远把 minSize 从 (100, 100) 降到 (80, 80) 或 (60, 60)同时观察 scaleFactor 是否需要同步调整。5.3 客户端连接服务端被拒绝阿里云盘也会抢 12345现象启动 main.py 正常但 cilent.py 启动后抛 ConnectionRefusedError 或 socket.timeout。原因12345 是常用端口很多软件会抢占它。项目说明里特别提到如果出现报错请关闭阿里云盘——阿里云盘的本地代理服务会占用部分动态端口导致监听失效。解决第一选择是关闭阿里云盘及其后台进程更稳妥的办法是换端口。两端代码里的端口号同时改成一个不常见的高位端口比如 28765改完重启两端程序即可。排查时可以先用 netstat 看端口占用情况netstat -ano | findstr 12345如果输出里存在 LISTENING 状态的记录说明端口已经被其他进程占用记下 PID 后用任务管理器确认是哪个程序。5.4 项目路径含中文导致运行报错现象源码明明完整运行时却不断报文件找不到、模块导入失败之类的奇怪错误。原因OpenCV 的老版本对中文和特殊字符路径支持不好Python 在 Windows 上处理中文路径时也可能出现编码错位导致 imread 或 CascadeClassifier 读取文件失败。解决项目说明里强调过——解压后重命名为英文路径再运行。这是所有带 OpenCV 的课设源码的通病不只是这一套。我习惯把课程设计统一放在 D:\course_projects\face_attendance 这种纯英文路径下检查路径无中文后再开始配环境能省掉一半的玄学报错。5.5 打包后的 exe 运行明显变慢现象源码运行流畅但双击 exe 后启动要几十秒摄像头预览卡顿识别速度明显下降。原因PyInstaller 打包时会把 Python 解释器和所有依赖库全部打包进 exe运行时需要先解压到临时目录再加载启动和 IO 都会变慢另外多用户连接的实验数据在打包环境中往往无法复现。解决正式答辩和功能演示用源码运行exe 只作为交付物存在在课设报告里如实说明打包限制并附上源码运行的性能数据。说明文件里明确写了打包也导致代码启动和运行速度明显降低与项目多用户连接的实验数据可能存在出入这就是官方给出的定论不用再折腾打包参数了。6. 进阶打磨换检测模型与二次开发切入点这套资源的上限不在跑通而在于你能不能在它的骨架上做二次开发。两个方向最值得投入换掉弱检测模型、把考勤数据接出来做统计。说明文件里写得很坦白——更换了更加轻量的预训练模型导致在定位人脸的能力降低。人脸识别链路里有两个独立环节检测人脸在哪和识别这是谁。LBPH 只负责识别不管检测检测靠的是 haarcascade_frontalface_default.xml。如果检测能力弱最直接的替换方案是换回 OpenCV 自带的官方级联分类器。opencv-python 包安装后自带的分类器路径通常在 cv2.data.haarcascades 里可以这样用import cv2 # 不依赖外部 xml 文件的官方路径写法 cascade_path cv2.data.haarcascades haarcascade_frontalface_default.xml face_cascade cv2.CascadeClassifier(cascade_path)cv2.data.haarcascades 指向的是 OpenCV 安装包里的 data 目录这里的 xml 文件是 OpenCV 官方完整版检测能力通常比作者替换的轻量版要好。如果官方 haar 仍然不能满足需求可以考虑用 OpenCV 的 DNN 模块加载深度学习人脸检测模型Caffe 格式的 SSD 模型或 OpenCV Zoo 里的 YuNet 都可以代价是需要额外下载模型文件依赖增加。对课程设计来说先换回官方 haar 是最稳妥的一步。二次开发方面我建议优先做考勤数据可视化。当前系统的输出是 testDB.db 里的签到记录你可以自己写一段查询脚本统计每个学生的签到率和准时率import sqlite3 conn sqlite3.connect(testDB.db) cursor conn.cursor() # 统计每个学生的签到次数按签到时间升序排列 cursor.execute( SELECT student_id, COUNT(*) as cnt FROM attendance GROUP BY student_id ORDER BY cnt DESC ) rows cursor.fetchall() for row in rows: print(f学生 {row[0]}: 签到 {row[1]} 次) conn.close()接入图表库做成柱状图或趋势曲线之后可以往课设报告里多添一页实验结果展示也顺便补上了实验分析章节的可视化素材。这一步不需要动原系统的任何代码只读数据库就行风险极低、收益明确。从那以后我每次拿到课设源码都先看打包失败说明再决定哪些功能能用演示版跑、哪些功能必须回源码环境复现——这比网上任何排错教程都省时间。希望帮到你。本文还有配套的精品资源点击获取
