CS课程项目设计19:基于DeepFace人脸识别库的课堂签到系统

本专栏上一篇文章实现了基于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人脸识别库的课堂签到系统

相关推荐
不惑_2 小时前
AI大模型是怎么工作的?从石头分类说起
人工智能·分类·数据挖掘
IT古董2 小时前
【第五章:计算机视觉-项目实战之生成对抗网络实战】2.基于SRGAN的图像超分辨率实战-(2)实战1:DCGAN模型搭建
人工智能·生成对抗网络·计算机视觉
悠哉悠哉愿意2 小时前
【数据结构与算法学习笔记】双指针
数据结构·笔记·python·学习·算法
MoRanzhi12032 小时前
5. Pandas 缺失值与异常值处理
数据结构·python·数据挖掘·数据分析·pandas·缺失值处理·异常值处理
yourkin6662 小时前
李宏毅-Generative AI-第一课
人工智能
程序员的奶茶馆3 小时前
Python 字典速查:键值对操作与高频函数
python·面试
tryCbest3 小时前
Python 使用 Redis 详细教程
redis·python·bootstrap
大模型真好玩3 小时前
大模型Agent开发框架哪家强?12项Agent开发框架入门与选型
人工智能·agent·mcp
常州晟凯电子科技3 小时前
君正T32开发笔记之IVSP版本环境搭建和编译
人工智能·笔记·物联网