用 Python 打造实时专注度分析系统:人脸识别 + GUI 可视化完整实现
·
在课堂、会议、远程办公等场景中,实时监测人员专注度与自动签到是提升效率的重要手段。本文基于OpenCV、face_recognition与Tkinter,从零实现一套实时人脸识别签到 + 专注度分析的桌面应用,兼顾实用性与可扩展性,适合 Python 计算机视觉入门与课程设计实践。
一、项目功能与技术栈
核心功能
- 自动加载本地人脸库,完成精准人脸识别
- 实时摄像头画面展示,人脸框标注与姓名显示
- 自动签到统计,支持签到记录重置
- 基于人脸数量的专注度智能计算
- 可视化 GUI 界面,操作简洁友好
技术选型
- OpenCV:视频采集、图像预处理、画面绘制
- face_recognition:人脸特征编码、相似度匹配(底层基于 dlib)
- Tkinter:桌面 GUI 界面搭建
- Pillow:图像格式转换,适配 Tkinter 显示
- NumPy:数值计算与距离匹配
二、环境准备
安装项目依赖库,执行以下命令:
pip install opencv-python pillow face-recognition numpy
说明:face_recognition依赖 dlib,Windows 环境若安装失败,可先下载预编译 whl 包安装。
三、项目结构设计
专注度分析系统/
├── known_faces/ # 人脸库文件夹(存放注册人员照片,文件名=姓名)
└── main.py # 主程序代码
使用时将人员正面照片放入known_faces文件夹,程序自动加载并生成人脸特征编码。
四、核心代码实现
1. 人脸库加载与特征编码
核心逻辑:读取人脸图片,提取 128 维人脸特征向量,用于后续实时比对。
known_face_encodings = []
known_face_names = []
path = "known_faces"
if not os.path.exists(path):
os.makedirs(path)
messagebox.showwarning("提示", "请将人脸照片放入 known_faces 文件夹,重启程序")
exit()
# 遍历加载人脸特征
for filename in os.listdir(path):
if filename.lower().endswith(('.jpg', '.jpeg', '.png')):
img_path = os.path.join(path, filename)
image = face_recognition.load_image_file(img_path)
face_enc = face_recognition.face_encodings(image)
if face_enc:
known_face_encodings.append(face_enc[0])
name = os.path.splitext(filename)[0]
known_face_names.append(name)
2. GUI 界面搭建
基于 Tkinter 构建可视化界面,包含视频显示区、信息统计区、控制按钮区,采用深色主题提升视觉体验。
class AttentionApp:
def __init__(self, root):
self.root = root
self.root.title("专注度分析系统")
self.root.geometry("850x650")
self.root.configure(bg="#2c3e50")
# 标题
title = Label(root, text="专注度分析系统", font=("微软雅黑",24,"bold"), fg="white", bg="#2c3e50")
title.pack(pady=10)
# 视频画面标签
self.video_label = Label(root, bg="#34495e")
self.video_label.pack(pady=10)
# 信息面板
info_frame = tk.Frame(root, bg="#2c3e50")
info_frame.pack(pady=10)
self.sign_label = Label(info_frame, text="已签到: 0 人", font=("微软雅黑",16), fg="#2ecc71", bg="#2c3e50")
self.attention_label = Label(info_frame, text="平均专注度: 80", font=("微软雅黑",16), fg="#f1c40f", bg="#2c3e50")
3. 摄像头与实时视频处理
七、项目优化方向
八、总结
本项目以Python + 计算机视觉为核心,实现了一套轻量、实用的专注度分析与自动签到系统,完整覆盖人脸检测、特征匹配、GUI 开发、实时视频处理等关键技能。代码结构清晰、注释完善,既可作为计算机视觉入门案例,也能快速迭代为课程设计、毕业设计作品,欢迎大家二次开发拓展功能!
- 调用摄像头获取实时帧
- 缩放图像提升识别速度
- 人脸定位 + 特征提取 + 相似度匹配
- 绘制人脸框与姓名,更新签到与专注度
def update_video(self): if not self.running: return ret, frame = self.cap.read() if not ret: self.root.after(30, self.update_video) return # 缩小图像加速处理 small_frame = cv2.resize(frame, (0,0), fx=0.25, fy=0.25) rgb_small = cv2.cvtColor(small_frame, cv2.COLOR_BGR2RGB) # 人脸检测与编码 face_locations = face_recognition.face_locations(rgb_small) face_encodings = face_recognition.face_encodings(rgb_small, face_locations) detected_names = [] for face_enc in face_encodings: matches = face_recognition.compare_faces(known_face_encodings, face_enc) name = "未知人员" face_distances = face_recognition.face_distance(known_face_encodings, face_enc) if face_distances.size>0: best_idx = np.argmin(face_distances) if matches[best_idx]: name = known_face_names[best_idx] detected_names.append(name)4. 专注度计算逻辑
基础专注度 80 分,检测到的人脸数量越多,专注度越低(模拟多人分散注意力),同时限制最低分为 0。
attention = max(0, self.base_attention - len(detected_names) * 5) self.attention_label.config(text=f"平均专注度: {attention}")五、完整优化代码
原代码存在人脸匹配错误、无真实人脸识别、无签到重置等问题,已完成全面优化,完整代码如下:
import cv2 import os import tkinter as tk from tkinter import Label, Button, messagebox from PIL import Image, ImageTk import face_recognition import numpy as np print("正在启动专注度分析系统...") known_face_encodings = [] known_face_names = [] path = "known_faces" if not os.path.exists(path): os.makedirs(path) messagebox.showwarning("提示", "请将人脸照片放入 known_faces 文件夹,重启程序") exit() for filename in os.listdir(path): suffix = filename.lower() if suffix.endswith(('.jpg', '.jpeg', '.png')): img_path = os.path.join(path, filename) image = face_recognition.load_image_file(img_path) face_enc = face_recognition.face_encodings(image) if len(face_enc) > 0: known_face_encodings.append(face_enc[0]) name = os.path.splitext(filename)[0] known_face_names.append(name) print(f"已注册人脸: {name}") else: print(f"警告:{filename} 未检测到人脸,跳过") if len(known_face_names) == 0: messagebox.showerror("错误", "known_faces 文件夹无有效人脸照片") exit() print(f"成功加载 {len(known_face_names)} 位注册人员人脸") class AttentionApp: def __init__(self, root): self.root = root self.root.title("专注度分析系统") self.root.geometry("850x650") self.root.configure(bg="#2c3e50") title = Label(root, text="专注度分析系统", font=("微软雅黑", 24, "bold"), fg="white", bg="#2c3e50") title.pack(pady=10) self.video_label = Label(root, bg="#34495e") self.video_label.pack(pady=10) info_frame = tk.Frame(root, bg="#2c3e50") info_frame.pack(pady=10) self.sign_label = Label(info_frame, text="已签到: 0 人", font=("微软雅黑", 16), fg="#2ecc71", bg="#2c3e50") self.sign_label.grid(row=0, column=0, padx=30) self.attention_label = Label(info_frame, text="平均专注度: 80", font=("微软雅黑", 16), fg="#f1c40f", bg="#2c3e50") self.attention_label.grid(row=0, column=1, padx=30) self.name_label = Label(info_frame, text="签到名单: 无", font=("微软雅黑", 12), fg="white", bg="#2c3e50", wraplength=700) self.name_label.grid(row=1, column=0, columnspan=2, pady=10) btn_frame = tk.Frame(root, bg="#2c3e50") btn_frame.pack(pady=10) self.start_btn = Button(btn_frame, text="启动摄像头", font=("微软雅黑", 14), bg="#3498db", fg="white", padx=20, pady=5, command=self.start_camera) self.start_btn.grid(row=0, column=0, padx=10) self.stop_btn = Button(btn_frame, text="停止摄像头", font=("微软雅黑", 14), bg="#e74c3c", fg="white", padx=20, pady=5, command=self.stop_camera) self.stop_btn.grid(row=0, column=1, padx=10) self.reset_btn = Button(btn_frame, text="重置签到", font=("微软雅黑", 14), bg="#d35400", fg="white", padx=20, pady=5, command=self.reset_sign) self.reset_btn.grid(row=0, column=2, padx=10) self.quit_btn = Button(btn_frame, text="退出系统", font=("微软雅黑", 14), bg="#95a5a6", fg="white", padx=20, pady=5, command=self.quit_app) self.quit_btn.grid(row=0, column=3, padx=10) self.cap = None self.running = False self.signed_in = set() self.base_attention = 80 def reset_sign(self): self.signed_in.clear() self.update_info_ui() def start_camera(self): if self.running: return self.cap = cv2.VideoCapture(0) if not self.cap.isOpened(): messagebox.showerror("摄像头错误", "无法调用设备摄像头,请检查权限/设备") return self.running = True self.start_btn.config(state="disabled") self.update_video() def stop_camera(self): self.running = False if self.cap: self.cap.release() self.cap = None self.start_btn.config(state="normal") self.video_label.config(image="") self.video_label.image = None def quit_app(self): self.stop_camera() self.root.destroy() def update_info_ui(self): self.sign_label.config(text=f"已签到: {len(self.signed_in)} 人") name_text = ', '.join(self.signed_in) if self.signed_in else "无" self.name_label.config(text=f"签到名单: {name_text}") def update_video(self): if not self.running: return ret, frame = self.cap.read() if not ret: self.root.after(30, self.update_video) return small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25) rgb_small = cv2.cvtColor(small_frame, cv2.COLOR_BGR2RGB) face_locations = face_recognition.face_locations(rgb_small) face_encodings = face_recognition.face_encodings(rgb_small, face_locations) detected_names = [] for face_enc in face_encodings: matches = face_recognition.compare_faces(known_face_encodings, face_enc) name = "未知人员" face_distances = face_recognition.face_distance(known_face_encodings, face_enc) if len(face_distances) > 0: best_idx = np.argmin(face_distances) if matches[best_idx]: name = known_face_names[best_idx] detected_names.append(name) if name != "未知人员" and name not in self.signed_in: self.signed_in.add(name) print(f"✅ {name} 签到成功") for (top, right, bottom, left), name in zip(face_locations, detected_names): top *= 4 right *= 4 bottom *= 4 left *= 4 color = (0, 255, 0) if name != "未知人员" else (0, 0, 255) cv2.rectangle(frame, (left, top), (right, bottom), color, 2) cv2.rectangle(frame, (left, bottom - 25), (right, bottom), color, -1) cv2.putText(frame, name, (left + 6, bottom - 6), cv2.FONT_HERSHEY_DUPLEX, 0.6, (255,255,255), 1) attention = max(0, self.base_attention - len(detected_names) * 5) self.attention_label.config(text=f"平均专注度: {attention}") self.update_info_ui() frame = cv2.resize(frame, (640, 360)) frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) img = Image.fromarray(frame_rgb) imgtk = ImageTk.PhotoImage(image=img) self.video_label.config(image=imgtk) self.video_label.image = imgtk self.root.after(30, self.update_video) if __name__ == "__main__": root = tk.Tk() app = AttentionApp(root) root.mainloop() print(f"最终签到人数:{len(app.signed_in)}") print(f"签到名单:{list(app.signed_in)}")六、运行与使用说明
- 在项目目录下创建
known_faces文件夹,放入人员正面照片(文件名设为姓名,如张三.jpg) - 运行
main.py,程序自动加载人脸库 - 点击启动摄像头,系统开始实时检测
- 注册人员入镜后自动签到,界面实时更新签到人数、名单与专注度
- 支持停止摄像头、重置签到、退出系统操作
- 精准专注度判断:接入 MediaPipe 人脸关键点,计算眨眼频率、头部姿态、视线方向,提升专注度判断准确性
- 数据持久化:将签到记录保存至 Excel / 数据库,支持历史查询
- 多人同时管理:添加人员注册、删除功能,动态管理人脸库
- 异常告警:专注度低于阈值时弹窗 / 声音提醒
- 性能优化:多线程分离视频采集与识别,提升流畅度
更多推荐
所有评论(0)