基于 Django + dlib 的人脸识别校园考勤系统:从零到上线实践指南
本文完整分享一个基于 Django、dlib、face-recognition、OpenCV 的人脸识别校园考勤系统的设计与实现。文章涵盖目录结构、技术栈、关键代码、数据模型、业务流程、部署上线与可视化展示占位,开箱即用并便于二次开发。
— 联系方式:码界筑梦坊各大平台同名
目录
- 项目概览与特性
- 目录结构
- 技术栈与环境
- 业务与数据建模
- 核心流程设计
- 关键代码剖析
- 路由与页面
- 可视化展示
- 本地开发与部署
- 常见问题与排查
- 演进与优化方向
- 致谢
项目概览与特性
- 学生/教师/管理员三类用户,基于会话的登录注册与信息完善。
- 课程与节次管理,教师发布考勤时间窗,学生在窗口内完成“人脸签到”。
- 人脸注册与识别:支持上传图片或摄像头拍照,提取面部编码并进行相似度比对。
- 结果落库:识别日志与考勤记录入库,可扩展统计分析与可视化。
目录结构(精简)
djangoProject/
djangoProject/
settings.py # 配置(MySQL、静态/媒体、上下文处理器)
urls.py # 全局路由,挂载 myApp
myApp/
models.py # 用户、学院、专业、课程、节次、选课、请假、考勤、人脸相关模型
views.py # 登录注册、信息完善、课程/选课、人脸录入/签到、教师端发布考勤
urls.py # 业务路由
face.py # 人脸编码与识别流程(dlib + 欧氏距离阈值)
templates/ # 前端模板(登录、录入、签到、课程等)
utils/
ways.py # 基础工具(base64 转二进制等)
getPublicData.py # 公共数据查询封装
getChartData.py # 可视化数据准备(示例)
*.dat # dlib 人脸关键点/特征模型文件
static/ # 前端静态资源(可替换为 CDN)
media/faces/ # 用户人脸图片持久化目录
requirements.txt # 依赖(Django、dlib、face-recognition、opencv 等)
manage.py
技术栈与环境
- 后端框架:Django 3.1.14(会话登录、模板渲染、ORM、消息系统)
- 数据库:MySQL(
PyMySQL
驱动) - 人脸相关:
- dlib(68 关键点 + ResNet 人脸特征)
- face-recognition(封装的人脸编码/比对 API,可用于注册时提编码)
- OpenCV(图像转灰度等基础处理)
- 科学计算:NumPy、Pillow
- 可视化:ECharts/Matplotlib/WordCloud(项目内已含
getChartData.py
与wordCloud.py
示例) - UI:SimpleUI(管理端优化)、本地静态资源模板
环境要求(Windows 示例):
- Python 3.8+(建议)
- MySQL 5.7+/8.0+
- CMake 与 VS Build Tools(用于编译 dlib,或使用预构建 wheel)
业务与数据建模
- 用户与角色:
User(user_type=student|teacher|admin)
;学生/教师与用户一对一,包含扩展信息。 - 课程体系:
Course
—CourseSession
(节次/上课时间与签到时间窗)。 - 选课记录:
Enrollment
(避免超额与重复选课)。 - 人脸相关:
FaceEnrollmentRecord
保存用户的人脸图片路径与编码(二进制)FaceRecognition
保存一次识别的结果(成功/失败、时间、关联节次)Attendance
考勤记录,关联学生与节次
核心流程设计
- 人脸注册
- 上传图片或前端拍照 base64 → 后端解析并保存到
media/faces/
→ 通过face-recognition
/dlib 提取 128D 面部编码 → 写入FaceEnrollmentRecord
。
- 上传图片或前端拍照 base64 → 后端解析并保存到
- 发布考勤
- 教师对课程发布
CourseSession
,含上课时间与签到起止时间。
- 教师对课程发布
- 人脸签到
- 学生上传签到图片 → dlib/face-recognition 提取编码 → 与库中自身编码做相似度比对(欧氏距离阈值 0.6)→ 成功则写入
FaceRecognition
并生成Attendance
。
- 学生上传签到图片 → dlib/face-recognition 提取编码 → 与库中自身编码做相似度比对(欧氏距离阈值 0.6)→ 成功则写入
关键代码剖析(节选)
数据库配置与模板上下文处理器(djangoProject/settings.py
):
INSTALLED_APPS = [
'simpleui', 'django.contrib.admin', 'django.contrib.auth',
'django.contrib.contenttypes', 'django.contrib.sessions',
'django.contrib.messages', 'django.contrib.staticfiles',
'myApp'
]
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'design_160_face',
'USER': 'root',
'PASSWORD': '123456',
'HOST': 'localhost',
'PORT': '3306'
}
}
TEMPLATES[0]['OPTIONS']['context_processors'] += [
'myApp.context_processors.user_data',
]
核心模型(myApp/models.py
)节选:
class CourseSession(models.Model):
course = models.ForeignKey(Course, on_delete=models.CASCADE)
session_time = models.DateTimeField()
sign_in_start_time = models.DateTimeField()
sign_in_end_time = models.DateTimeField()
def is_sign_in_in_time(self, current_time):
return self.sign_in_start_time <= current_time <= self.sign_in_end_time
class FaceEnrollmentRecord(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE)
enrollment_time = models.DateTimeField(auto_now_add=True)
image_path = models.CharField(max_length=255)
face_encoding = models.BinaryField()
class Attendance(models.Model):
student = models.ForeignKey(Student, on_delete=models.CASCADE)
course_session = models.ForeignKey(CourseSession, on_delete=models.CASCADE)
date = models.DateTimeField(auto_now_add=True)
status = models.CharField(max_length=20, choices=(
('present', '出勤'), ('absent', '缺席'), ('late', '迟到'), ('excused', '请假'),
))
人脸识别流程(myApp/face.py
):
import dlib, cv2, numpy as np
from io import BytesIO
from PIL import Image
from .models import Student, FaceRecognition, Attendance, CourseSession, FaceEnrollmentRecord
detector = dlib.get_frontal_face_detector()
sp = dlib.shape_predictor('utils/shape_predictor_68_face_landmarks.dat')
facerec = dlib.face_recognition_model_v1('utils/dlib_face_recognition_resnet_model_v1.dat')
def get_face_encoding(image_data):
img = Image.open(BytesIO(image_data))
img = np.array(img)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
faces = detector(gray)
if len(faces) == 0:
return None
shape = sp(gray, faces[0])
face_descriptor = facerec.compute_face_descriptor(img, shape)
return np.array(face_descriptor)
def recognize_face(face_image, course_session):
face_encoding = get_face_encoding(face_image)
if face_encoding is None:
return {"status": "failed", "message": "未检测到人脸"}
for student in Student.objects.all():
rec = FaceEnrollmentRecord.objects.filter(user=student.user).first()
if not rec: continue
stored = np.frombuffer(rec.face_encoding, dtype=np.float64)
if np.linalg.norm(face_encoding - stored) < 0.6:
fr = FaceRecognition(user=student.user, status='success', course_session=course_session)
fr.save()
attendance = fr.create_attendance()
return {"status": "success", "message": "签到成功", "attendance_status": getattr(attendance, 'status', None)}
return {"status": "failed", "message": "未匹配到已注册人脸"}
人脸注册与签到视图(myApp/views.py
)节选:
def enroll_face(request):
username = request.session.get('username')
user = User.objects.get(username=username)
if request.method == 'POST':
form = FaceEnrollmentForm(request.POST, request.FILES)
if form.is_valid():
# 保存图片到 media/faces 并提取 face_encoding,写入 FaceEnrollmentRecord
# ...(略,详见仓库源码)
messages.success(request, "人脸录入成功")
return redirect('/myApp/enroll_face/')
else:
form = FaceEnrollmentForm()
return render(request, 'enroll_face.html', {'form': form})
def check_in(request, course_session_id):
course_session = CourseSession.objects.get(id=course_session_id)
if request.method == "POST":
face_image = request.FILES.get("face_image")
result = recognize_face(face_image.read(), course_session)
messages.success(request, result.get('message')) if result['status']=='success' \
else messages.error(request, result.get('message'))
return redirect('check_in', course_session_id=course_session.id)
return render(request, 'check_in.html', {'course_session': course_session})
路由与页面
全局入口(djangoProject/urls.py
):
urlpatterns = [
path('admin/', admin.site.urls),
path('', views.login, name='login'),
path('myApp/', include('myApp.urls')),
]
业务路由(myApp/urls.py
)包含:
- 登录/注册/登出
- 信息完善(学生/教师)
- 课程列表/详情/选课/退课
- 人脸录入与签到、查看考勤、教师端发布考勤时间
前端模板位于 myApp/templates/
,可替换为任意 UI 组件库(Bootstrap、Tailwind、AntD)或前后端分离改造。
可视化展示
🐼 项目源码获取,码界筑梦坊各平台同名,博客底部含联系方式卡片,欢迎咨询!
基于Flask的人脸识别校园考勤系统
本地开发与部署
- 安装依赖
pip install -r requirements.txt
# Windows 若 dlib 安装失败:
# 方式A:预编译 wheel(匹配 Python/平台版本);
# 方式B:安装 CMake 与 VS Build Tools 后再 pip 安装
- 数据库配置
- 在
djangoProject/settings.py
修改DATABASES
为你的 MySQL 连接参数。 - 创建数据库
design_160_face
(或自行更名)。
- 初始化与运行
python manage.py makemigrations
python manage.py migrate
python manage.py createsuperuser
python manage.py runserver 0.0.0.0:8000
- 静态与媒体
STATICFILES_DIRS
指向static/
;媒体文件(人脸图片)保存在media/
,确保有写权限。
- 生产部署要点
- 关闭 DEBUG,设置
ALLOWED_HOSTS
- 使用 uWSGI/gunicorn + Nginx;媒体/静态走 Nginx
- 分离人脸模型与图片存储,考虑对象存储(OSS/七牛/又拍等)
- 加入 HTTPS,敏感接口限流与鉴权
常见问题与排查
- dlib 安装失败:优先尝试预编译 wheel;否则安装 CMake/VS Build Tools 后重试。
- 无法检测到人脸:保证图像清晰、正脸、光照均匀;建议仅一张人脸入镜。
- MySQL 连接失败:检查端口/用户权限/
pymysql
安装。 - 迁移冲突:清理
migrations
异常文件,或用--fake
/--fake-initial
处理历史。 - URL 细节:注意路由参数格式,如
path('course/<int:course_id>/enroll/', ...)
。 - 性能:大量比对时预加载编码到内存,并做索引或缓存;必要时改 ANN(近似最近邻)。
演进与优化方向
- 鉴权升级:Django Auth 与权限系统完善;或切换 JWT 并前后端分离。
- 活体检测与防攻击:加入眨眼检测、光流/深度/纹理反欺诈模块。
- 相似度策略:欧氏距离阈值自适应/课程内 Top-K;或训练度量学习模型。
- 特征管理:编码归一化、版本化、批量重提取与滚动更新。
- 任务异步化:识别日志与统计写入 Celery,前端轮询或 WebSocket 推送。
致谢
- dlib、face-recognition、OpenCV、Django 及其生态。
— 联系方式:码界筑梦坊各大平台同名