本专栏上一篇文章实现了基于Insightface人脸识别库的课堂签到系统,具体内容如下所示:
CS课程项目设计18:基于Insightface人脸识别库的课堂签到系统-CSDN博客https://blog.csdn.net/weixin_36431280/article/details/151068505?spm=1001.2014.3001.5501这篇文章继续按照人脸识别库的发展脉络,实现基于DeepFace人脸识别库的课堂签到系统。

1. 研究背景
随着教育信息化的快速发展,传统课堂签到方式(如点名、签到表签字等)存在效率低下、易代签、统计繁琐等问题。在高校课堂中,这些问题尤为突出 ------ 教师需花费课堂时间完成签到,影响教学进度;人工统计考勤数据耗时且易出错;纸质签到记录不易保存和查询。
人脸识别技术的成熟为解决这些问题提供了新方案。相比传统 IC 卡、二维码等签到方式,人脸识别具有非接触性、高准确性、难以伪造等优势,特别适合课堂环境下的批量快速签到场景。DeepFace 作为一款开源的人脸识别库,集成了多种预训练模型和检测算法,降低了开发门槛,为构建高效课堂签到系统提供了技术基础。
2. 研究目的
本系统旨在利用 DeepFace 人脸识别库构建一套高效、准确、易用的课堂人脸签到系统,具体实现目标包括:
2.1 自动化签到流程
替代传统人工点名,通过摄像头实时捕捉学生面部信息,自动完成身份核验与签到记录,将单次课堂签到时间从 5-10 分钟缩短至 1 分钟内。
2.2 高准确性身份识别
在课堂复杂环境(如光线变化、部分遮挡、表情差异)下,保持 95% 以上的人脸识别准确率,降低误识率和拒识率。
2.3 完整的学生管理功能
支持添加、更新、删除学生信息(包括姓名、学号、人脸图像),满足课程学生变动需求。例如:
- 新学生加入班级时,可通过 "添加学生" 功能录入信息并采集人脸;
- 学生信息变更(如姓名修改)或人脸特征变化(如发型改变)时,可通过 "更新学生" 功能重新采集人脸数据;
- 学生退课时,通过 "删除学生" 功能移除其信息,避免无效识别。
2.4 实时考勤统计与记录
签到过程中实时显示实到 / 未到人数,自动记录签到时间并存储至数据库,支持后续查询统计。例如:教师可随时查看当前签到进度,下课后可导出完整签到表。
2.5 友好的用户界面
提供直观的操作界面,包括视频实时预览、参数调节、状态显示等,使非技术背景的教师也能轻松使用。
3. 技术方案
3.1 核心技术栈
(1) DeepFace人脸识别核心库
- 功能:集成人脸检测、特征提取、特征比对等完整流程,支持 VGG-Face、FaceNet、Dlib
等多种预训练模型。 - 优势:简化人脸识别开发流程,无需从零训练模型,支持多种距离度量方式(如余弦距离、欧氏距离)。
选取预训练模型的核心代码如下所示:
# 初始化DeepFace所需参数 - 新增模型列表
self.available_models = ["Facenet", "OpenFace", "VGG-Face", "DeepFace", "Dlib"]
self.model_name = "Facenet" # 默认模型
self.distance_metric = "cosine" # 距离度量方式
(2) OpenCV 与 PIL图像处理
- OpenCV:负责视频捕获、人脸区域提取、图像预处理(如尺寸调整、通道转换)。
- PIL(Pillow):用于图像格式转换,将 OpenCV 处理的图像转换为 Tkinter 可显示的格式。
(3) SQLite3数据存储
- 功能:轻量级关系型数据库,存储学生信息(姓名、学号、人脸图像路径)和签到记录(学号、日期、时间、状态)。
- 优势:无需独立服务器,数据文件本地存储,适合小规模应用场景。
3.2DeepFace核心运行机制
DeepFace 的工作流程可分为三个关键阶段:
(1) 人脸检测
- 功能:从输入图像中定位人脸区域,返回边界框坐标和检测置信度。
- 实现:系统使用
DeepFace.extract_faces()
方法,采用 OpenCV 检测器(detector_backend="opencv"
),支持在复杂背景中快速定位人脸。
核心代码如下所示:
# 使用DeepFace的人脸检测功能
detected_faces = DeepFace.extract_faces(
img_path=image_path,
detector_backend="opencv", # 使用OpenCV检测器
enforce_detection=False
)
if len(detected_faces) > 0:
# 获取人脸区域
face_data = detected_faces[0]
facial_area = face_data["facial_area"]
x1, y1, w, h = facial_area["x"], facial_area["y"], facial_area["w"], facial_area["h"]
x2, y2 = x1 + w, y1 + h
# 提取人脸区域
face_img = img[y1:y2, x1:x2]
(2) 特征提取
- 功能:将人脸图像转换为固定长度的数值向量(特征编码),捕捉面部独特特征(如眼睛距离、鼻梁形状等)。
- 实现:通过
DeepFace.represent()
方法调用 VGG-Face 模型(默认配置),将预处理后的人脸图像(224×224 像素、RGB 格式)输入模型,输出 4096 维特征向量,并进行归一化处理。
核心代码如下所示:
# 提取人脸区域
face_img = img[y1:y2, x1:x2]
# 提取特征
result = DeepFace.represent(
img_path=image_path,
model_name=self.model_name,
enforce_detection=False,
detector_backend="opencv"
)
# 提取特征向量并确保是一维数组
encoding = result[0]["embedding"] if isinstance(result, list) else result["embedding"]
(3) 特征比对
- 功能:计算待识别人脸与已知人脸的特征向量距离,判断是否为同一人。
- 实现:采用余弦距离(
distance_metric="cosine"
)作为度量标准,距离值越小表示相似度越高。当距离小于阈值(默认 0.6)时,判定为匹配成功。
核心代码如下所示:
# 与已知人脸比较
name = "未知人员"
student_id = ""
min_distance = float('inf')
threshold = 0.6 # DeepFace推荐的阈值
if self.known_face_encodings:
# 计算与所有已知人脸的距离
for i, known_encoding in enumerate(self.known_face_encodings):
# 计算余弦距离
distance = 1 - np.dot(encoding, known_encoding)
if distance < min_distance and distance < threshold:
min_distance = distance
name = self.known_face_names[i]
student_id = self.known_face_ids[i]
以上代码对应开始签到的功能,可视化页面如下所示:

左图是签到成功的页面,右图是签到失败的页面。
签到完成后,点击结束签到,回到系统主页面,会发现出勤统计情况也会更新了,可视化页面如下所示:

4. 实现流程
4.1 系统初始化
- 数据库初始化:创建
students
表(存储学生信息)和attendance
表(存储签到记录)。 - 人脸特征加载:从数据库读取学生人脸图像,通过 DeepFace 提取特征并保存至本地文件(
deepface_encodings.pkl
),加速后续加载。 - UI 界面创建:初始化窗口组件,包括视频显示区、控制按钮、统计面板等。
4.2 签到流程
- 启动签到:点击 "开始签到" 按钮后,系统打开摄像头,实时捕获视频流。
- 人脸处理:
- 每帧图像通过多线程调用 DeepFace 检测人脸区域;
- 提取人脸特征并与已知特征库比对;
- 对匹配成功的学生,在视频中绘制边界框和姓名标签。
- 签到记录:首次识别到学生时,自动记录当前时间并写入数据库,同时更新实到列表和统计数据。
- 结束签到:点击 "结束签到" 按钮,关闭摄像头,显示最终考勤统计结果。
4.3 学生管理流程
- 添加学生:输入姓名和学号后,通过摄像头采集人脸图像,检测合格后保存至数据库和本地文件夹,并更新特征库。
- 更新学生:查询学号后,可修改姓名或重新采集人脸图像,同步更新数据库和特征库。
- 删除学生:查询学号并确认后,删除数据库记录和本地图像文件,更新特征库。
添加学生的核心代码如下所示:
def add_student(self):
"""添加新学生"""
# 拍照按钮
def capture_face():
name = name_entry.get().strip()
student_id = id_entry.get().strip()
if not name or not student_id:
messagebox.showerror("错误", "请输入姓名和学号")
return
# 创建新的数据库连接
conn = self.create_db_connection()
c = conn.cursor()
# 检查学号是否已存在
c.execute("SELECT * FROM students WHERE student_id=?", (student_id,))
if c.fetchone():
messagebox.showerror("错误", "该学号已存在")
conn.close()
return
# 捕获人脸
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
cap.release()
if not ret:
messagebox.showerror("错误", "无法访问摄像头")
conn.close()
return
# 检测人脸
results = self.detector.detect_faces(frame)
if not results or results[0]['confidence'] < 0.8:
messagebox.showerror("错误", "未检测到清晰人脸,请重试")
conn.close()
return
# 保存人脸图像
if not os.path.exists("face_images"):
os.makedirs("face_images")
image_path = f"face_images/{student_id}.jpg"
cv2.imwrite(image_path, frame)
# 保存到数据库
c.execute("INSERT INTO students (name, student_id, face_image_path) VALUES (?, ?, ?)",
(name, student_id, image_path))
conn.commit()
conn.close() # 关闭连接
添加学生的可视化图片如下图所示:

更新学生的核心代码如下所示:
def update_student(self):
"""更新学生信息 - 添加了查询时显示学生图片功能"""
# 更新按钮
def update_student_info():
# 检查是否已查询到有效学生
if not current_student["student_id"]:
messagebox.showerror("错误", "请先查询并确认学生信息")
return
student_id = current_student["student_id"]
new_name = name_entry.get().strip()
if not new_name:
messagebox.showerror("错误", "请输入新姓名")
return
conn = self.create_db_connection()
c = conn.cursor()
# 捕获新的人脸(可选)
update_face = messagebox.askyesno("更新人脸", "是否需要更新人脸照片?")
image_path = current_student["image_path"] # 默认使用原图片路径
if update_face:
# 捕获人脸
cap = cv2.VideoCapture(0)
ret, frame = cap.read()
cap.release()
if not ret:
messagebox.showerror("错误", "无法访问摄像头")
conn.close()
return
# 检测人脸
results = self.detector.detect_faces(frame)
if not results or results[0]['confidence'] < 0.8:
messagebox.showerror("错误", "未检测到清晰人脸,请重试")
conn.close()
return
# 保存人脸图像
if not os.path.exists("face_images"):
os.makedirs("face_images")
image_path = f"face_images/{student_id}.jpg"
cv2.imwrite(image_path, frame)
# 更新数据库
c.execute("UPDATE students SET name=?, face_image_path=? WHERE student_id=?",
(new_name, image_path, student_id))
conn.commit()
conn.close()
更新学生的可视化图片如下图所示:

左图是输入错误学号,提醒未找到该学生;右图则是输入正确学号,查询到学生姓名、学号、注册图片。
删除学生的核心代码如下所示:
def delete_student(self):
"""删除学生信息 - 添加了查询和图片显示功能"""
# 删除按钮
def confirm_delete():
# 检查是否已查询到有效学生
if not current_student["student_id"]:
messagebox.showerror("错误", "请先查询并确认学生信息")
return
# 确认删除
confirm = messagebox.askyesno(
"确认删除",
f"确定要删除学生 {current_student['name']} ({current_student['student_id']}) 吗?\n此操作不可恢复!"
)
if not confirm:
return
conn = self.create_db_connection()
c = conn.cursor()
# 删除学生记录
c.execute("DELETE FROM students WHERE student_id=?", (current_student["student_id"],))
# 删除相关的人脸图片
if current_student["image_path"] and os.path.exists(current_student["image_path"]):
try:
os.remove(current_student["image_path"])
except Exception as e:
print(f"删除人脸图片失败: {e}")
messagebox.showwarning("警告", "学生记录已删除,但人脸图片删除失败")
conn.commit()
conn.close()
删除学生的可视化图片如下图所示:

和更新学生功能一样,左图是输入错误学号,提醒未找到该学生;右图则是输入正确学号,查询到学生姓名、学号、注册图片。
4.4 数据查询
系统支持查看历史签到记录(通过 "查看记录" 功能),基于 SQLite 数据库实现数据的持久化存储与检索。
所有人签到完之后,还可以点击查看记录,进一步查看每个人的签到情况,可视化界面如下图所示:

5. 总结
本系统基于 DeepFace 人脸识别库构建,实现了课堂签到的自动化与智能化。通过整合计算机视觉、数据库和 GUI 技术,有效解决了传统签到方式的效率问题,同时保证了识别准确性和操作便捷性。
系统的核心优势在于:利用 DeepFace 简化了人脸识别开发难度,通过多线程处理确保实时性,借助 SQLite 实现数据高效管理。未来可进一步优化方向包括:支持多摄像头同时签到、增加活体检测防止照片欺骗、引入更轻量的模型提升运行速度等,以适应更大规模的课堂场景需求。
最后,还上传个该项目的简要演示视频,供大家了解。
基于DeepFace人脸识别库的课堂签到系统