☰
Python+Flask+dlib人脸识别考勤系统:从环境搭建到二次开发全解析
2026/10/5 7:48:04 网站建设 项目流程

简介:这是一套面向高校计算机相关专业学生的高分毕业设计源码,主题为基于Python、Flask与dlib的人脸识别企业考勤管理系统,同时也可作为课程设计参考。项目已通过导师指导与答辩评审,获得97分成绩,并在Windows 10/11环境下完成严格调试,下载后即可运行,配套部署教程齐全。资源包共416个文件,约103.71MB,其中32个py文件承载Flask后端与dlib人脸识别核心逻辑,26个html与118个js、61个css构成前端页面与交互样式,另有79张jpg、51张png等图片资源用于界面展示与识别素材,dat、xml等文件支撑模型与配置数据。目前已有170人学习关注。读者可获得完整可运行的项目源码、数据库与模型文件、前端静态资源以及使用文档,便于快速理解人脸识别考勤的业务流程、接口设计与部署方式,适合作为毕业设计、课程设计或Flask与计算机视觉入门实践的参考范例。

1. 从一份 97 分毕设拆起:Flask + dlib 考勤系统到底能跑出什么

如果你正在找一份能直接跑起来、答辩能讲清楚技术链路的毕业设计,或者想拿一套现成的 Flask 项目改造成课程设计,这套「基于 Python + Flask + dlib 的人脸识别企业考勤管理系统」值得认真拆一遍。它不是那种只放几张截图、代码跑不通的“论文配套压缩包”,而是在 Windows 10/11 上完整调试过、带部署文档、答辩评审拿到 97 分的可运行项目。核心链路很清晰:浏览器端调摄像头抓人脸,后端用 dlib 做检测和特征提取,Flask 负责路由与业务逻辑,考勤记录落库后在前端页面展示。适合两类人:一是需要快速搭出可演示系统的毕业生,二是想理解人脸识别从算法到 Web 落地全流程的开发者。下面按“资源是什么 → 怎么装怎么跑 → 坑在哪 → 怎么改”的顺序拆开讲。

2. 环境搭建与依赖安装:把 dlib 和 Flask 同时伺候好

2.1 为什么 dlib 是这套系统里最容易翻车的一环

这套项目的技术栈里,Flask 和前端资源(Bootstrap、Summernote 等)都是常规操作,真正决定你能不能跑起来的是 dlib。dlib 的人脸检测和 68 点特征提取依赖 C++ 编译环境,在 Windows 上直接pip install dlib大概率会卡在 CMake 或 Visual Studio Build Tools 缺失上。常见做法是先用 conda 建一个干净环境,再通过 conda-forge 渠道装 dlib,这样能绕过大部分编译问题。如果你坚持用 pip,那就得先装好 Visual Studio 2019/2022 的 C++ 桌面开发组件和 CMake,并且把 cmake 加入 PATH。我一般会推荐 Python 3.8 或 3.9,因为 dlib 和 face_recognition 在这两个版本上的预编译包最全,Python 3.11 以上容易遇到 wheel 缺失。

2.2 从零建环境到依赖落地的完整命令

# 创建 conda 环境,指定 Python 3.8,避免高版本 dlib 无预编译包 conda create -n attendance python=3.8 -y conda activate attendance # 优先用 conda-forge 装 dlib,它会自动处理 C++ 依赖 conda install -c conda-forge dlib -y # 安装 Flask 及项目所需的其他 Python 包 pip install flask flask-sqlalchemy flask-login opencv-python numpy pillow # 如果项目里用了 face_recognition,再补装 pip install face_recognition

这段命令的逻辑是:conda 负责解决 dlib 的二进制依赖,pip 负责装纯 Python 包。参数上,-c conda-forge指定渠道,-y跳过确认。装完后用python -c "import dlib; print(dlib.__version__)"验证,能打印版本号就说明 dlib 通了。如果报ImportError: DLL load failed,多半是 conda 环境没激活或者和系统里的其他 Python 冲突,检查where python的输出顺序。

2.3 数据库与项目配置的初始化

项目一般用 SQLite 做默认数据库,方便毕设演示。在项目根目录找到配置文件(常见是config.py或app/config.py),确认SQLALCHEMY_DATABASE_URI指向sqlite:///attendance.db。然后执行建表脚本:

# init_db.py 或类似入口,手动建表 from app import db, create_app app = create_app() with app.app_context(): db.create_all() print("数据表创建完成")

这里的关键是db.create_all()必须在应用上下文里执行,否则会报RuntimeError: Working outside of application context。如果项目用了 Flask-Migrate,那就走flask db init、flask db migrate、flask db upgrade三步。建完表后,检查数据库文件是否出现在instance/或项目根目录下,有文件就说明落库成功。

3. 人脸识别链路拆解:从摄像头帧到考勤记录

3.1 dlib 检测 + 特征提取的实际调用顺序

这套系统的人脸识别不是黑匣子,拆开看就是三步:检测人脸框、提取 128 维特征向量、和库里的已知人脸比对。dlib 的get_frontal_face_detector()负责第一步,shape_predictor_68_face_landmarks.dat负责定位五官,face_recognition_model_v1负责把五官区域转成特征向量。项目里通常会封装一个face_utils.py或recognizer.py,核心逻辑如下:

import dlib import face_recognition import numpy as np # 加载模型文件,路径根据项目实际位置调整 detector = dlib.get_frontal_face_detector() sp = dlib.shape_predictor("models/shape_predictor_68_face_landmarks.dat") facerec = dlib.face_recognition_model_v1("models/dlib_face_recognition_resnet_model_v1.dat") def get_face_encoding(image_path): # 读取图片并转为 RGB,dlib 对 RGB 更友好 img = face_recognition.load_image_file(image_path) # 检测人脸位置 face_locations = face_recognition.face_locations(img, model="hog") if len(face_locations) == 0: return None # 提取第一张人脸的特征向量 encodings = face_recognition.face_encodings(img, face_locations) return encodings[0] if encodings else None

参数说明:model="hog"是 CPU 版检测器,速度快但小脸容易漏;换成model="cnn"精度更高但需要 GPU 或者耐心等。face_encodings返回的是 128 维 numpy 数组,存库时可以用pickle或直接转成二进制。比对时用欧氏距离,阈值一般设 0.6,小于 0.6 判定为同一人,大于 0.6 判定陌生人。这个阈值不是玄学,是 dlib 官方推荐的经验值,调低会拒真,调高会认错。

3.2 Flask 路由如何串起打卡业务

前端页面通过navigator.mediaDevices.getUserMedia拿到摄像头流,定时截帧传给后端/api/recognize接口。后端收到 base64 图片后解码,调用上面的get_face_encoding,再和数据库里User.face_encoding字段比对。匹配成功后写入Attendance表,记录user_id、timestamp、status(正常/迟到/早退)。核心路由大概长这样:

from flask import Blueprint, request, jsonify import base64 import numpy as np import cv2 from app.models import User, Attendance, db from app.face_utils import get_face_encoding api_bp = Blueprint('api', __name__) @api_bp.route('/api/recognize', methods=['POST']) def recognize(): data = request.get_json() # 前端传过来的是 base64 编码的图片,去掉前缀 img_data = data['image'].split(',')[1] img_bytes = base64.b64decode(img_data) # 转成 numpy 数组供 OpenCV 处理 nparr = np.frombuffer(img_bytes, np.uint8) img = cv2.imdecode(nparr, cv2.IMREAD_COLOR) # 保存临时文件或直接传 numpy 给识别函数 encoding = get_face_encoding_from_array(img) if encoding is None: return jsonify({'code': 1, 'msg': '未检测到人脸'}) # 遍历数据库里的用户特征做比对 users = User.query.filter(User.face_encoding.isnot(None)).all() for user in users: known = np.frombuffer(user.face_encoding, dtype=np.float64) dist = np.linalg.norm(known - encoding) if dist < 0.6: record = Attendance(user_id=user.id, status='正常') db.session.add(record) db.session.commit() return jsonify({'code': 0, 'msg': f'打卡成功:{user.name}'}) return jsonify({'code': 2, 'msg': '未匹配到用户'})

这段代码里,np.linalg.norm算的是欧氏距离,和face_recognition.face_distance等价。User.face_encoding存的是二进制,读出来要np.frombuffer还原。注意每次请求都查全表比对,用户量大了会慢,毕设场景够用,生产环境得换向量数据库或者加缓存。

3.3 前端页面与静态资源组织

项目正文里列了一堆 CSS 文件(bootstrap.min.css、summernote-bs3.css、style.css 等),说明前端用了 Bootstrap 做响应式布局,Summernote 做富文本编辑(可能用于公告或日志模块)。Flask 的静态文件默认放在static/目录,模板放在templates/。启动后访问http://127.0.0.1:5000应该能看到登录页,登录后进入考勤面板。如果页面样式错乱,检查static/css/下的文件是否齐全,以及模板里url_for('static', filename='...')的路径拼写。常见问题是 Bootstrap 版本和 Summernote 版本不匹配,导致弹窗样式异常,换回项目自带的文件即可。

4. 避坑与排查:那些文档里不会写的血泪经验

4.1 摄像头调用失败,页面一直转圈

现象:点击“开始打卡”后浏览器没有弹出摄像头授权,或者授权后画面黑屏。原因通常是浏览器安全策略限制,getUserMedia只在 HTTPS 或 localhost 下生效。如果你用127.0.0.1:5000访问一般没问题,但用局域网 IP 访问就会静默失败。解决:本地开发就用 localhost,或者用 Flask 的ssl_context='adhoc'临时开 HTTPS。另外检查摄像头是否被其他程序占用,Windows 的隐私设置里要允许桌面应用访问摄像头。

4.2 dlib 模型文件路径写错,报错找不到 .dat

现象:启动时报RuntimeError: Unable to open shape_predictor_68_face_landmarks.dat。原因:模型文件没下载,或者代码里的相对路径基于启动目录而不是项目根目录。解决:确认models/目录下有两个 .dat 文件,没有就去 dlib 官方渠道下载。路径建议用os.path.join(os.path.dirname(__file__), 'models', '...')拼绝对路径,别用./models/...这种依赖工作目录的写法。

4.3 人脸比对总是匹配到同一个人

现象:不同人打卡都显示同一个名字。原因:特征向量存库时用了错误的 dtype,比如存成 float32 读出来当 float64 用,距离计算全乱。或者注册时只存了一张脸,而那张脸光照条件特殊,导致特征向量泛化差。解决:统一用np.float64存取,注册时至少采 3 张不同角度的照片取平均特征。阈值 0.6 不要随意调高,超过 0.65 误识率会明显上升。

4.4 Flask 热重载导致摄像头资源重复占用

现象:开发模式下改了代码,Flask 自动重启,但摄像头句柄没释放,再打卡就报设备忙。原因:Flask debug 模式会起两个进程,一个监控一个运行,摄像头资源被监控进程也初始化了一次。解决:把摄像头初始化放在路由函数内部而不是模块顶层,或者关掉 debug 模式的 reloader:app.run(debug=True, use_reloader=False)。

4.5 数据库并发写入导致考勤记录丢失

现象:多人同时打卡时,偶尔有人的记录没写进去。原因:SQLite 默认锁机制在并发写时容易database is locked。解决:毕设演示场景可以给db.session.commit()加 try-except 重试,或者换 MySQL。如果坚持 SQLite,在连接字符串里加?timeout=10让写操作排队等待。

5. 二次开发与验证:把毕设改成能讲出亮点的作品

5.1 换掉 HOG 检测器,用 CNN 提升小脸检出率

默认的 HOG 检测器在光线暗、人脸小的情况下漏检严重。如果你有 NVIDIA 显卡,可以装dlib的 CUDA 版本,然后把face_locations的model参数改成"cnn"。改完后同样一张图,HOG 可能只检出 1 张脸,CNN 能检出 3 张。代价是单帧处理时间从 50ms 涨到 300ms 左右,打卡场景可以接受。验证方法:准备一张多人合影,分别用两种模型跑,打印len(face_locations)对比。

5.2 加一个活体检测的简易方案

毕设答辩时老师常问“拿照片能不能打卡”。最简单的防御是眨眼检测:用 dlib 的 68 点 landmark 算出眼睛纵横比(EAR),连续几帧 EAR 低于阈值再恢复,判定为眨眼。代码片段:

def eye_aspect_ratio(eye_points): # eye_points 是 6 个点的坐标 A = np.linalg.norm(eye_points[1] - eye_points[5]) B = np.linalg.norm(eye_points[2] - eye_points[4]) C = np.linalg.norm(eye_points[0] - eye_points[3]) return (A + B) / (2.0 * C) # 连续帧里 EAR 先小于 0.2 再大于 0.25,判定眨眼

这个方案不能防视频回放,但能挡住静态照片,答辩够用。真要上生产,得用红外双目或者 3D 结构光,那是另一个量级的成本。

5.3 考勤报表导出与数据验证

项目一般自带考勤记录页面,但导出 Excel 的功能不一定有。你可以用pandas加openpyxl补一个导出接口:

import pandas as pd from flask import send_file from io import BytesIO @api_bp.route('/api/export') def export_attendance(): records = Attendance.query.all() df = pd.DataFrame([{ '姓名': r.user.name, '时间': r.timestamp.strftime('%Y-%m-%d %H:%M:%S'), '状态': r.status } for r in records]) output = BytesIO() df.to_excel(output, index=False) output.seek(0) return send_file(output, download_name='考勤记录.xlsx', as_attachment=True)

验证方法:打卡几次后调这个接口,打开 Excel 看时间戳和数据库里的是否一致。注意时区问题,SQLite 存的是 UTC 还是本地时间取决于datetime.now()还是datetime.utcnow(),导出前统一转换。

5.4 从毕设到课程设计的降维用法

如果你只是拿它当课程设计,不需要完整考勤逻辑,可以只保留人脸注册和识别两个页面,把数据库换成 JSON 文件存储,省去建表和迁移的麻烦。具体做法:把User模型换成读写users.json,特征向量用 base64 编码存字符串。这样部署时只需要 Python 和 dlib,连数据库都不用装。我一般会建议先跑通完整版,再按需裁剪,别一上来就改架构,否则出了问题都不知道是原项目的锅还是自己改的锅。

从那以后我每次拿到这种带 dlib 的项目,都强制先跑一遍python -c "import dlib; print(dlib.__version__)"再动其他文件,确认底层依赖通了再往上叠业务。希望帮到你。

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

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

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

立即咨询