简介:本资源为基于人脸识别的学生考勤签到管理系统完整课程设计包,面向计算机、人工智能、通信、物联网等专业在校学生与教师,可用于课程设计、毕业设计、大作业或项目立项演示。包内共160个文件,以52个py源码与78个pyc编译文件为核心,辅以mp4运行演示视频、docx课设报告、pkl模型文件、xlsx数据表、db数据库及xml人脸定位文件等,压缩包约10.16MB。系统涵盖人脸录入、训练与识别签到、签到签退、哈希加密等模块,服务端与客户端分离,并附有LSTM用户画像与考勤数据分析的完整研究方案。已有270人学习下载。读者可获得可稳定运行的源码、实操录屏、结构清晰的课设报告与排错说明,便于快速理解人脸识别考勤的工程实现,并在此基础上进行二次开发与功能扩展。
1. 从一份课设压缩包说起:人脸识别考勤系统能跑成什么样
课程设计季一到,计算机相关专业的同学最头疼的往往不是写报告,而是找一个「代码完整、功能验证过、还能讲清楚原理」的项目。这份基于人脸识别的学生考勤签到管理系统,就是冲着这个场景来的:Python 源码、运行视频、课设报告三件套打包在一起,客户端负责摄像头采集与人脸识别签到,服务端负责接收数据、落库和统计展示。它适合计科、人工智能、物联网等方向的学生做课设、毕设或大作业,也适合刚入门想拿一个完整 C/S 架构项目练手的开发者。需要先说明的是,项目里人脸识别用的是轻量预训练模型,定位人脸的能力比重量级方案弱一些,但换来的是在普通笔记本上也能跑起来的运行速度,这个取舍后面会细讲。
2. 拆开压缩包:目录结构、技术栈与运行前置条件
2.1 文件清单与各文件职责
解压之后先别急着双击运行,花两分钟把目录看一遍,能省掉后面一半的报错排查时间。从项目正文给出的打包情况看,核心文件分布大致如下:
| 文件/目录 | 作用 | 备注 |
|---|---|---|
client.py | 客户端主程序 | 摄像头采集、人脸识别、签到签退入口 |
main.py | 服务端主程序 | 监听端口、接收数据、写库 |
testDB.db | SQLite 数据库文件 | 存储学生信息与考勤记录 |
haarcascade_frontalface_default.xml | 人脸定位级联分类器 | 必须放到 client 端根目录 |
pip.ini | pip 镜像配置 | 加速依赖安装 |
课程设计报告.docx | 课设报告 | 含目录、实验分析、结论 |
项目说明.md | 运行说明 | 端口、路径等关键提示 |
这里有个血泪经验:haarcascade_frontalface_default.xml放在DATASource目录里,但程序运行时是从 client 端根目录找它的。很多人第一次跑报「无法定位人脸」,不是摄像头坏了,是这个 xml 没挪位置。
2.2 技术栈与依赖环境
项目是典型的 Python C/S 架构,客户端和服务端通过本机地址127.0.0.1、端口12345通信。人脸识别部分走的是 OpenCV 的传统路线:Haar 级联做人脸定位,再提取特征生成 yml 模型文件,识别时调用 yml 特征库做快速比对。数据库用 SQLite,单文件testDB.db,不需要额外装数据库服务,这对课设环境很友好。
依赖安装建议先看pip.ini,里面通常配好了国内镜像源。如果没配,手动指定一下:
pip install opencv-python opencv-contrib-python numpy pillow -i https://pypi.tuna.tsinghua.edu.cn/simpleopencv-contrib-python不能省,人脸识别相关的face模块在 contrib 包里,只装opencv-python会在cv2.face处报AttributeError。参数上,-i后面跟镜像地址,网络正常的话几十秒就能装完。
提示:项目路径和项目名不要用中文,解压后重命名为英文再运行,否则 OpenCV 读文件时可能出现解析不了的错误。
2.3 启动顺序与端口检查
启动顺序不能反:先起服务端,再起客户端。服务端main.py会绑定12345端口,如果这个端口被占用,客户端连不上会直接报连接错误。常见占用源是某些网盘客户端,项目说明里专门提到「如果出现报错请关闭阿里云盘」,就是这个原因。
# 先启动服务端 python main.py # 另开一个终端启动客户端 python client.py服务端启动后不要关那个终端窗口,它需要一直监听。客户端启动后会调摄像头,第一次运行系统会弹权限申请,允许即可。如果摄像头被其他程序占用(比如视频会议软件),客户端会黑屏或报can't open camera,关掉占用程序再试。
3. 人脸录入、训练与签到:三个核心功能的实现链路
3.1 人脸录入:采集多少张、怎么采才有效
人脸录入是整个系统的数据源头,采得好不好直接决定后面识别的准确率。项目里录入功能会调用摄像头,对同一个人采集多张人脸图像,存到指定目录并绑定学号或姓名。常见做法是采集 20 到 30 张,覆盖正脸、轻微左右偏转、戴眼镜和不戴眼镜的情况。
采集时有两个参数值得注意:一是采集间隔,不要连续狂拍,每张之间隔个零点几秒,让脸有轻微移动,增加样本多样性;二是光照,尽量在均匀光线下采,背光或侧光太强会让 Haar 定位失败,采到的图里根本没有脸,训练出来就是废模型。
import cv2 # 加载人脸定位分类器,路径按实际放置位置调整 face_cascade = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') cam = cv2.VideoCapture(0) # 0 表示默认摄像头 count = 0 while count < 30: ret, frame = cam.read() gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # 转灰度,Haar 只吃灰度图 faces = face_cascade.detectMultiScale(gray, 1.3, 5) # 缩放系数1.3,最小邻居数5 for (x, y, w, h) in faces: count += 1 cv2.imwrite(f'data/User.{count}.jpg', gray[y:y+h, x:x+w]) # 只存人脸区域 cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2) cv2.imshow('capture', frame) if cv2.waitKey(100) & 0xFF == 27: # 按 ESC 提前退出 break cam.release() cv2.destroyAllWindows()detectMultiScale的两个关键参数:scaleFactor=1.3表示每次图像尺寸缩小 1.3 倍来搜索人脸,值越小搜得越细但越慢;minNeighbors=5表示一个候选框周围要有 5 个邻居才确认是人脸,调高能减少误检,调低能减少漏检。采完图后建议人工翻一遍,把明显不是脸的图删掉,这一步偷懒后面识别就会翻车。
3.2 人脸训练:yml 模型是怎么生成的
录入的是一张张 jpg,训练要做的是把这些图喂给识别器,生成一个 yml 特征库文件。项目用的是特征提取方法,常见实现是 LBPH(局部二值模式直方图)识别器,它对光照变化有一定鲁棒性,适合课设这种小样本场景。
import cv2 import numpy as np import os recognizer = cv2.face.LBPHFaceRecognizer_create() detector = cv2.CascadeClassifier('haarcascade_frontalface_default.xml') def get_images_and_labels(path): image_paths = [os.path.join(path, f) for f in os.listdir(path)] faces = [] ids = [] for image_path in image_paths: gray = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE) # 文件名格式 User.1.1.jpg,取第二段作为标签 ID id = int(os.path.split(image_path)[-1].split('.')[1]) faces.append(gray) ids.append(id) return faces, np.array(ids) faces, ids = get_images_and_labels('data') recognizer.train(faces, ids) # 训练 recognizer.write('trainer/trainer.yml') # 生成 yml 模型 print(f'训练完成,共 {len(faces)} 张样本')LBPHFaceRecognizer_create()创建识别器,train()接收人脸数组和对应标签数组,write()把模型落盘成 yml。标签 ID 从文件名里解析,所以录入时文件名格式必须统一,否则训练出来的标签是乱的,识别时全对不上号。训练完成后,识别阶段用recognizer.predict()返回标签和置信度,置信度越低表示越像,一般低于 50 可以认为是同一个人,具体阈值要按自己采集的样本调。
3.3 签到与签退:数据怎么从客户端流到数据库
签到签退是业务层逻辑。客户端识别出人脸后,拿到对应的学生 ID,把签到时间、状态打包,通过 socket 发给服务端,服务端写进testDB.db。项目里签到和签退是两个独立功能,通常按时间段区分:上午到课算签到,下课离开算签退。
import socket import json import datetime def send_checkin(student_id, action): payload = { 'student_id': student_id, 'action': action, # 'checkin' 或 'checkout' 'time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') } s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect(('127.0.0.1', 12345)) # 地址和端口与服务端一致 s.send(json.dumps(payload).encode('utf-8')) resp = s.recv(1024).decode('utf-8') s.close() return resp这里用 JSON 做序列化,比直接拼字符串稳,字段清晰也好扩展。action字段区分签到签退,服务端按这个字段决定写哪张表或哪个状态位。哈希加密功能用在学生密码或敏感字段上,常见做法是hashlib.sha256加盐,避免明文存库。socket 通信要注意粘包问题,课设规模下数据量小,一般不会触发,但如果后面扩展成多用户并发,就得加长度头或分隔符来切分消息边界。
4. 避坑与排查:打包失败功能与运行报错怎么处理
4.1 教师端刷新查看功能失效
现象:教师端点刷新没反应,或者直接抛异常退出。原因是这个功能用了并行库,打包成 exe 后并行库的进程创建机制和打包环境冲突,子进程起不来。解决方式是别用打包好的 exe,直接跑源码python main.py,源码环境下并行库正常。如果必须打包,把并行部分改成串行或线程池,牺牲一点速度换稳定。
4.2 多用户签到在部分电脑上跑不起来
现象:同一份代码,有的电脑能多用户同时签到,有的直接卡死或丢消息。原因是消息队列在不同系统上的实现依赖有差异,项目说明里也写了「原因尚未明确」。解决方式是课设演示时用单用户串行签到,或者把消息队列换成基于 socket 的简单请求-响应模式,一个请求处理完再处理下一个,虽然并发能力弱,但至少不会玄学崩溃。
4.3 用户画像功能显示违规字符
现象:历次签到时间通过 socket 传输后,界面上出现乱码或违规字符。原因是编码不一致,发送端和接收端的解码方式没对齐,或者时间字符串里混入了不可见字符。解决方式是在发送前统一encode('utf-8'),接收后统一decode('utf-8'),并在写库前对字符串做一次清洗,过滤掉非打印字符。
4.4 打包后启动和运行明显变慢
现象:源码跑得好好的,打包成 exe 后启动要等十几秒,识别也变卡。原因是打包工具把整个 Python 解释器和依赖都塞进 exe,启动时要解压到临时目录,加上项目本身多用户连接的实验数据是在源码环境测的,打包后环境变了,数据自然对不上。解决方式是演示和实验数据采集都用源码环境,exe 只作为分发备份,不作为性能参考。
4.5 端口被占用导致连接失败
现象:客户端报连接拒绝或超时。原因是12345端口被其他程序占了,网盘客户端是常见嫌疑。解决方式是先查端口占用,Windows 下用netstat -ano | findstr 12345找到 PID,再决定是关程序还是改端口。改端口的话,客户端和服务端两边的端口号要同步改,只改一边照样连不上。
5. 从能跑到好用:阈值调优与二次开发的一点技巧
把系统跑起来只是第一步,真正让它在答辩或演示时不出丑,靠的是几个细节调优。先说识别阈值,LBPH 的predict()返回的置信度不是概率,是距离,值越小越像。默认没有固定阈值,你得自己试:拿同一个人不同角度的图测,记录置信度分布,再拿不同人的图测,找一个能把两者分开的临界值。我一般会写个小脚本批量跑一遍,把置信度打出来看分布,而不是凭感觉设一个 50 就完事。
# 批量测试置信度分布,帮助确定阈值 import cv2 recognizer = cv2.face.LBPHFaceRecognizer_create() recognizer.read('trainer/trainer.yml') test_img = cv2.imread('test/someone.jpg', cv2.IMREAD_GRAYSCALE) label, confidence = recognizer.predict(test_img) print(f'预测标签: {label}, 置信度: {confidence:.2f}') # 置信度低于阈值判为同一人,高于阈值判为陌生人再说二次开发。项目本身留了不少扩展口子:签到数据已经在testDB.db里,想加考勤率统计,直接写 SQL 查就行;想加人脸识别门禁联动,把签到成功后的 socket 消息再转发一路给门禁控制端即可。用户画像那块用了 LSTM 做签到预测,如果你不想碰深度学习,换成简单的统计方法——比如按学生历史签到时间算个均值方差,超过阈值就标异常——效果未必差,还省了训练时间。
最后说一个我自己的习惯:每次改完代码,先不急着接摄像头,用几张本地图片跑一遍识别流程,确认模型加载、标签解析、数据库写入这三步都通,再接硬件。这样出问题时能快速定位是算法层还是硬件层。从那以后我每次交付这类课设项目,都强制走一遍「本地图测试 → 摄像头测试 → 多用户测试」的流程,省得在演示现场手忙脚乱。希望帮到你。
本文还有配套的精品资源,点击获取