简介基于人脸识别的学生考勤签到管理系统是一份适合计算机相关专业学生课程设计、毕业设计及入门进阶的完整Python项目。项目采用客户端/服务端架构涵盖人脸录入、训练、识别签到、签退及哈希加密等核心功能配套运行视频和课设报告可直接运行或基于此二次开发。压缩包共160个文件以Python源码py/pyc、操作演示mp4、课程设计报告docx及项目说明md为主另含配置、数据库与测试数据整体仅10.16MB便于快速下载与部署。目前已吸引269人学习下载。除可运行的源码与录屏外报告中还给出了系统设计、关键功能模块实现、实验分析与总结展望等内容对理解网络通信、人脸识别调用、数据库交互等关键点很有帮助。1. 为什么“基于人脸识别的学生考勤签到管理系统”是计算机网络课设而不是 AI 课设拿到标题《基于人脸识别的学生考勤签到管理系统 python 源码运行视频课设报告》时最忌讳的是把时间花在训练深度学习模型上。这门课是计算机网络不是模式识别验收时老师看的是你能否把一次签到操作解释成“采集、编码、传输、解析、存储”的网络通信过程。我的做法是识别部分直接用现成人脸库拿结果把考勤记录通过网络上报到服务端再在报告里写清楚 TCP 连接怎么建立、数据怎么分包、服务端怎么并发处理。适合谁计算机网络课设需要交源码、视频和报告的本科同学以及想把项目扩展成局域网考勤工具的工程师。2. 拆解人脸识别考勤签到管理系统的三条技术线模型、存储、网络项目标题里同时出现“人脸识别”和“计算机网络课程设计”意味着你要交付的不是一个模型而是一个能解释“识别完成之后数据去哪里”的系统。我一般先把系统拆成三个边界人脸特征库、考勤事件、网络通道。人脸特征库存的是学号到 128 维向量的映射考勤事件是 JSON 文本网络通道只负责把 JSON 稳定送到服务端。三者解耦后python 源码只需要三个文件就能跑通报告里还能画一张“识别端-服务端-数据库”的时序图。2.1 人脸识别模型选型LBPH、face_recognition、自训 CNN 该选哪个做考勤签到管理系统人脸识别算法不需要自己发明。常见做法是选一个离线可跑的库把精力留给网络部分。下面三套方案是我在实际课设里见过最多的。方案实现成本特征形式离线运行报告可写深度课程设计推荐度OpenCV LBPH / EigenFace低OpenCV 自带局部纹理直方图 / 特征脸是传统机器学习可解释性强较高face_recognition中依赖 dlib128 维人脸嵌入向量是向量距离、阈值判定、特征提取高自训练 CNN高需要 GPU 和数据集自定义高维特征是模型结构、训练 loss一般时间不够我一般选face_recognition因为它的识别效果在教室这类固定光照场景下足够好而且代码量小。你只需要调用face_encodings拿到 128 维向量再用face_distance算欧氏距离不需要管网络结构。选 LBPH 也可以但遇到侧脸和光线变化很容易误判答辩时容易被追问。环境安装是第一个坑。推荐用 Python 3.10 左右的虚拟环境命令如下python -m venv venv source venv/bin/activate # Windows 使用 venv\Scripts\activate pip install opencv-python face_recognitionface_recognition依赖 dlibWindows 上pip install dlib经常因为缺少 CMake 和 C 编译环境失败。遇到这种情况降低到 Python 3.9/3.10 并安装cmake再重试如果还不行就把识别方案换成 OpenCV 的LBPHFaceRecognizer它不需要 dlib代码也能在报告里写出“传统机器学习与深度学习对比”的讨论。2.2 系统边界识别端、考勤服务端、数据存储和网络报文的职责把这个考勤签到管理系统按网络课设的口吻拆开目录结构应该是下面这样重点在“每个文件只干一件事”。attendance_system/ ├─ server.py ├─ register.py ├─ checkin.py ├─ features.pkl ├─ attendance.db └─ README.mdregister.py负责录入读人脸照片提取特征写入features.pklcheckin.py负责识别打开摄像头实时比对比对成功后生成一条 JSON 考勤事件server.py负责网络接收和落库把 JSON 解析后写进 SQLite。features.pkl是特征库attendance.db是考勤记录。识别端和服务端可以跑在同一台机器也可以分别跑在两个终端甚至两台电脑。只要checkin.py里指定服务端 IP 就能演示跨主机签到这才是计算机网络课设该有的样子。数据库不需要上 MySQLSQLite 对课设完全够用。报告里可以写一句“考勤库使用嵌入式关系数据库 SQLite单文件部署避免引入额外服务依赖。”这句话在答辩时很实用能解释清楚为什么不做单独的数据库服务器。2.3 为什么“先在本机跑通闭环”比“直接搭 Web 端”更适合计算机网络课设有些同学会把系统做成 Flask Web 服务浏览器打开页面再调摄像头代码量大答辩时还容易卡在端口占用、跨域和前端兼容性上。我更推荐先做命令行闭环服务端server.py启动后监听端口客户端checkin.py识别成功就发一条记录服务端落库后回OK。本机跑通后再把客户端里的127.0.0.1改成另一台机器的 IP整个系统自然就变成了分布式考勤系统。这也是计算机网络课程设计最看重的部分连接管理、数据传输、并发处理。3. 用 Python 源码实现人脸录入和签到识别的可运行链路这一章给出最小可运行的人脸识别部分。不追求界面只求代码能跑通后面的网络上报再替换掉打印语句。3.1 注册脚本把人脸照片转成 128 维特征并写入 features.pkl注册是所有流程的前提。下面这段代码用argparse接收学号和照片路径方便后面录制演示视频时批量操作。import argparse import os import pickle import face_recognition FEATURE_FILE features.pkl def register(student_id, image_path): 把一张人脸照片的 128 维特征存入 features.pkl image face_recognition.load_image_file(image_path) encodings face_recognition.face_encodings(image) # 照片里必须且只能有一个人脸 if len(encodings) ! 1: print(f照片里必须恰好有一个人脸当前检测到 {len(encodings)} 个) return data {} if os.path.exists(FEATURE_FILE): with open(FEATURE_FILE, rb) as f: data pickle.load(f) data[student_id] encodings[0] with open(FEATURE_FILE, wb) as f: pickle.dump(data, f) print(f{student_id} 注册完成特征维度 {encodings[0].shape[0]}) if __name__ __main__: parser argparse.ArgumentParser(description人脸考勤注册) parser.add_argument(student_id, help学号) parser.add_argument(image_path, help人脸照片路径) args parser.parse_args() register(args.student_id, args.image_path)逻辑说明load_image_file读入的是 RGB 图face_encodings会返回一个列表列表长度就是画面里的人脸数量。课程设计建议强制要求“单人照片”避免库里有多个特征时不知道绑定给谁。数据用pickle序列化保存特征是 numpy 数组直接用文本文件存会丢失精度。3.2 签到识别脚本摄像头帧里比对特征并生成考勤事件签到脚本从摄像头取帧对人脸做定位和编码然后和特征库里的向量算距离。这里的send_attendance先只打印一条考勤事件第 4 章会把这段替换成 Socket 上报。import time import pickle import cv2 import face_recognition def send_attendance(student_id): 暂时只打印后面替换为网络上报 now time.strftime(%Y-%m-%d %H:%M:%S) print(fCHECKIN {student_id} {now}) with open(features.pkl, rb) as f: known pickle.load(f) known_ids list(known.keys()) known_encodings list(known.values()) cap cv2.VideoCapture(0) while cap.isOpened(): ok, frame cap.read() if not ok: continue # OpenCV 默认 BGRface_recognition 需要 RGB rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) boxes face_recognition.face_locations(rgb, modelhog) encodings face_recognition.face_encodings(rgb, boxes) for encoding in encodings: distances face_recognition.face_distance(known_encodings, encoding) idx int(distances.argmin()) if distances[idx] 0.5: student_id known_ids[idx] send_attendance(student_id) cv2.putText(frame, f{student_id} {distances[idx]:.2f}, (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 200, 0), 2) else: cv2.putText(frame, unknown, (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2) cv2.imshow(attendance, frame) if cv2.waitKey(1) ord(q): break cap.release() cv2.destroyAllWindows()逻辑说明face_distance返回的是当前人脸与特征库每一个特征的欧氏距离距离越小越相似。用argmin取最小距离的下标再和阈值 0.5 比较小于阈值才认为是已知学生。注意OpenCV 的摄像头帧是 BGR必须cvtColor转成 RGB否则识别率会明显下降。3.3 参数和边界tolerance、hog/cnn、BGR/RGB、重复签到判断直接抄代码能跑但几个参数需要理解否则答辩时会被问住。下面是我常用的参数经验表。参数建议值影响face_locations(modelhog)hogCPU 上更快cnn更准但慢适合离线照片处理face_distance阈值0.5越小越严格0.4 容易漏识别0.6 容易误识别VideoCapture(0)00 是内置摄像头外接摄像头可尝试 1 或 2注册照片人脸区域居中且大于 100x100太小会丢失人脸特征细节cvtColor必须做漏掉则颜色通道错位识别率暴跌还有一个很容易忽略的重复签到问题。上面的代码每识别到一帧就触发一次send_attendance同一个学生在摄像头前一秒会被记录 25 次。常见的处理方案是在服务端给考勤表加唯一约束UNIQUE(student_id, date)同一个学号同一天只能插入一条第二次插入时捕获异常并返回ALREADY。这个逻辑放在网络服务端做比放在识别端做更合适因为识别端可能崩溃而服务端手里的数据才是最终考勤结果。4. 把考勤签到数据从客户端搬到服务端Socket、粘包处理与线程模型人脸识别部分完成后重点切换到计算机网络课程设计客户端把识别出的学号和当前时间发到服务端服务端存储并响应。这是整个课设最值钱的部分。4.1 为什么用 TCP Socket 而不是直接在本地写文件有人会觉得识别端已经拿到了学生信息直接sqlite3写本地数据库不就行了。这样做不是不可以但那就变成了“单机软件”计算机网络课设无法成立。常见的做法是让识别端成为 TCP 客户端服务端单独进程负责接收考勤记录。对比一下三种传输方式。方案可靠性代码量可讲的知识点课设推荐度TCP Socket JSON可靠字节流有序中等三次握手、粘包、backlog、线程模型推荐UDP Socket JSON不可靠少丢包、校验和、无连接不推荐考勤记录不能丢HTTP REST Flask可靠较少HTTP 状态码、URL 设计可以但网络底层写不了太深考勤记录不允许丢失所以选 TCP。但 TCP 是字节流协议没有消息边界多行 JSON 可能粘在一次recv里也可能被拆成两次recv。把“粘包处理”写进代码和报告课程设计的深度立刻就不一样了。4.2 客户端上报函数一行 JSON 加换行作为消息边界给客户端定义一个send_attendance函数替换第 3 章里的打印版本。消息格式是“一行 JSON 加一个换行符”这里换行符就是自定义的消息边界。import json import socket import time def send_attendance(student_id): 通过 TCP 把考勤事件发给服务端 payload { student_id: student_id, time: time.strftime(%Y-%m-%d %H:%M:%S) } data json.dumps(payload).encode(utf-8) b\n try: sock socket.create_connection((127.0.0.1, 8000), timeout5) sock.sendall(data) resp sock.recv(1024).decode(utf-8).strip() sock.close() return resp OK except ConnectionRefusedError: print(服务端未启动考勤记录未上传) return False逻辑说明create_connection会自己完成 TCP 三次握手timeout5防止摄像头线程卡死sendall确保全部字节发出服务端回OK后关闭连接体现一次完整的“连接-传输-关闭”过程。换行符\n是客户端和服务端之间的协议约定服务端也按这个规则拆包。4.3 服务端多线程接收recv 拼接、split 按行解析、SQLite 落库服务端要同时处理多个签到端所以用threading为每个连接开一个线程。这里给出完整的server.py包含建表、接收、解析和去重。import json import socket import sqlite3 import threading DB_FILE attendance.db def init_db(): conn sqlite3.connect(DB_FILE) conn.execute( CREATE TABLE IF NOT EXISTS checkin ( id INTEGER PRIMARY KEY AUTOINCREMENT, student_id TEXT NOT NULL, time TEXT NOT NULL, UNIQUE(student_id, substr(time, 1, 10)) ) ) conn.commit() conn.close() def save_record(payload): conn sqlite3.connect(DB_FILE) try: conn.execute( INSERT INTO checkin(student_id, time) VALUES (?, ?), (payload[student_id], payload[time]) ) conn.commit() return True except sqlite3.IntegrityError: return False finally: conn.close() def handle_client(conn, addr): print(f新连接: {addr}) buffer b try: while True: chunk conn.recv(1024) if not chunk: break buffer chunk # 按换行符拆出一条完整消息 while b\n in buffer: line, buffer buffer.split(b\n, 1) payload json.loads(line.decode(utf-8)) if save_record(payload): conn.sendall(bOK\n) else: conn.sendall(bALREADY\n) except (ConnectionResetError, json.JSONDecodeError): pass finally: conn.close() def main(): init_db() server socket.socket(socket.AF_INET, socket.SOCK_STREAM) server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) server.bind((0.0.0.0, 8000)) server.listen(10) print(考勤服务端已启动端口 8000) while True: conn, addr server.accept() threading.Thread(targethandle_client, args(conn, addr), daemonTrue).start() if __name__ __main__: main()逻辑说明recv(1024)是本次读取的最大长度不保证一次拿到完整消息所以要把buffer不断拼接直到出现\n。split(b\n, 1)确保只拆出一条消息剩余数据继续留在buffer里这就是完整的粘包处理。SQLite 表里的UNIQUE(student_id, substr(time,1,10))把“学号 当天日期”作为唯一键第二条记录会被save_record捕获并返回失败客户端收到ALREADY后就不会重复上报。这里把SO_REUSEADDR设置成 1 也很重要开发时重启服务端不会报Address already in use。0.0.0.0表示监听本机所有网卡之后客户端把 IP 改成宿舍局域网地址就能演示跨机器签到。要做更高级的验证可以打开 Wireshark 过滤tcp.port 8000直接看到 TCP 建立连接和每一帧数据的长度这部分内容放进课设报告是很强的加分项。5. 交付前把运行视频和课设报告做到可验收日志、抓包和启动命令最后一个环节是让源码、运行视频、课设报告三者互相引用。很多同学视频里跑得很顺报告里却写不出工作量原因就是没有把网络知识点和代码对应起来。5.1 课设报告里最容易拿分的三个计算机网络知识点第一TCP 连接建立与关闭。客户端调用create_connection触发三次握手程序退出或close()触发四次挥手。报告里画一条客户端、服务端的时序箭头把SYN、SYN-ACK、ACK、FIN标出来。第二TCP 粘包问题。recv(1024)不按消息边界返回数据所以服务端用split(b\n, 1)拆包。报告里贴一页打印出的原始buffer内容说明一次recv可能收到两行 JSON。第三多线程并发模型。每个客户端连接分配一个线程用daemonTrue避免主线程退出后子线程阻塞。如果能提到selectors事件驱动作为改进方向说明你确实理解网络并发模型。5.2 运行视频怎么录把“失败到成功”和 Wireshark 抓包同时放进来视频建议 3 到 5 分钟按下面顺序录启动服务端python server.py注册一个测试同学运行checkin.py签到成功再切换一张未注册照片服务端不落库。视频中间切入一次 Wireshark过滤器设置tcp.port 8000能看到客户端到服务端的数据包长度和确认号变化。这一条能证明“识别结果真的通过网络传输了”而不是本地脚本自己骗自己。5.3 一份可直接照抄的启动命令和复现清单整包交付前我一般会在项目根目录放一个RUNLOG.md内容就是下面这三条命令和预期输出。python server.py python register.py 2024001 ./faces/2024001.jpg python checkin.py复现时先起服务端再注册一张正面人脸照片最后启动摄像头识别。如果checkin.py没打印出CHECKIN 2024001就打开 Wireshark 看 8000 端口有没有 SYN 包没有 SYN 包说明客户端没到网络层问题在摄像头或识别流程有 SYN 但服务端没回问题在服务端端口或防火墙。把RUNLOG.md和features.pkl一起放进 zip别人拿到后能按步骤重跑你这套基于人脸识别的学生考勤签到管理系统才算真正交付完毕。本文还有配套的精品资源点击获取