UI界面设计-Fer2013面部表情识别/基于pytorch

基于tensorflow代码请参考主页:

http://t.csdnimg.cn/beYP5icon-default.png?t=N7T8http://t.csdnimg.cn/beYP5本文使用torch框架构建模型做出UI界面,将所有调参变量做到UI界面上

一、项目概述

本项目开发了一款集成深度学习的情绪识别软件,采用 PyTorch 框架构建卷积神经网络模型。该软件通过摄像头捕获实时视频流,利用 Haar 级联分类器检测人脸,并应用训练好的模型分析表情,最终识别出七种基本情绪:愤怒、厌恶、恐惧、快乐、中立、悲伤和惊讶。此外,我们特别设计了一个直观的图形用户界面(GUI),使用 Tkinter 库实现,使用户能够轻松调整关键参数,优化识别效果。

(1)核心功能

  • 动态参数调整:用户可通过 GUI 上的滑块调整两个重要参数——缩放因子和最小邻居数。缩放因子控制图像金字塔中的图像尺寸缩放比例,影响检测到人脸的大小范围;而最小邻居数则确保只有经过多次验证的候选区域才被视为真实的人脸,平衡了检测精度和速度。

  • 实时情绪反馈:软件在视频流中实时高亮显示检测到的人脸区域,并在界面上方即时呈现识别到的情绪类别,便于观察者理解情绪状态。

  • 模型加载与保存:用户可以加载预先训练的模型权重文件(.pth格式),确保软件能够立即投入使用,无需重新训练模型。

(2)用户界面设计

  • 简洁直观的操作面板:包含“加载模型”和“开始检测”按钮,以及参数调整滑块,方便用户快速配置。

  • 实时视频预览区:主界面中央显示摄像头捕获的视频流,实时更新检测结果。

  • 状态提示:通过弹窗通知用户模型加载情况和其他重要信息。

(3)应用场景与参数调整建议

在不同的光照条件或拍摄角度下,适当调整缩放因子和最小邻居数可显著提升识别准确率。例如,在低光照环境下,增加最小邻居数有助于减少误报,但在部分遮挡的情况下,降低这一数值则可能避免漏检。

一、代码如下所示:

import tkinter as tk
from tkinter import filedialog, messagebox, ttk
from PIL import Image, ImageTk
import numpy as np
import cv2
import torch
import torch.nn as nn
import torch.nn.functional as F
import os

class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3, stride=1, padding=1)
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3, stride=1, padding=1)
        self.conv3 = nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1)
        self.conv4 = nn.Conv2d(128, 128, kernel_size=3, stride=1, padding=1)
        self.pool = nn.MaxPool2d(kernel_size=2, stride=2)
        self.dropout1 = nn.Dropout(0.25)
        self.dropout2 = nn.Dropout(0.5)
        self.fc1 = nn.Linear(128 * 6 * 6, 1024)
        self.fc2 = nn.Linear(1024, 7)
    
    def forward(self, x):
        x = torch.relu(self.conv1(x))
        x = self.pool(torch.relu(self.conv2(x)))
        x = self.dropout1(x)
        x = self.pool(torch.relu(self.conv3(x)))
        x = self.pool(torch.relu(self.conv4(x)))
        x = self.dropout1(x)
        x = x.view(-1, 128*6*6)  # Flatten the tensor
        x = self.fc1(x)
        x = torch.relu(x)
        x = self.dropout2(x)
        x = self.fc2(x)
        return x

class EmotionRecognitionApp:
    def __init__(self, master):
        self.master = master
        master.title("情绪识别")

        self.model = CNN()
        self.weights_path = ''
        self.load_model()

        #self.emotion_dict = {0: "生气", 1: "厌恶", 2: "恐惧", 3: "高兴", 4: "中性", 5: "悲伤", 6: "惊讶"}
        self.emotion_dict = {0: "Angry", 1: "Disgusted", 2: "Fearful", 3: "Happy", 4: "Neutral", 5: "Sad", 6: "Surprised"}
        self.cap = cv2.VideoCapture(0)
        self.face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

        self.canvas = tk.Canvas(master, width=890, height=650)
        self.canvas.pack()

        self.create_widgets()

    def create_widgets(self):
        # 加载模型按钮
        self.load_button = tk.Button(self.master, text="加载模型", command=self.load_model_dialog)
        self.load_button.pack(side=tk.LEFT)

        # 开始检测按钮
        self.detect_button = tk.Button(self.master, text="开始检测", command=self.start_detection)
        self.detect_button.pack(side=tk.LEFT)

        # 缩放因子滑块
        self.scale_factor_label = tk.Label(self.master, text="缩放因子:")
        self.scale_factor_label.pack(side=tk.LEFT)
        self.scale_factor_scale = tk.Scale(self.master, from_=1.0, to=2.0, resolution=0.1, orient=tk.HORIZONTAL, label="缩放因子")
        self.scale_factor_scale.set(1.3)
        self.scale_factor_scale.bind('<ButtonRelease-1>', self.update_scale_factor)
        self.scale_factor_scale.pack(side=tk.LEFT)

        # 最小邻居数滑块
        self.min_neighbors_label = tk.Label(self.master, text="最小邻居数:")
        self.min_neighbors_label.pack(side=tk.LEFT)
        self.min_neighbors_scale = tk.Scale(self.master, from_=2, to=10, resolution=1, orient=tk.HORIZONTAL, label="最小邻居数")
        self.min_neighbors_scale.set(5)
        self.min_neighbors_scale.bind('<ButtonRelease-1>', self.update_min_neighbors)
        self.min_neighbors_scale.pack(side=tk.LEFT)

    def load_model_dialog(self):
        self.weights_path = filedialog.askopenfilename(title="选择模型权重", filetypes=[("PyTorch Model", "*.pth")])
        if self.weights_path:
            self.model.load_state_dict(torch.load(self.weights_path, map_location=torch.device('cpu')))
            messagebox.showinfo("信息", "模型加载成功!")

    def load_model(self):
        # 默认模型加载(更新为你的默认模型路径)
        default_path = 'model_1000.pth'
        if os.path.exists(default_path):
            self.weights_path = default_path
            self.model.load_state_dict(torch.load(default_path, map_location=torch.device('cpu')))
            messagebox.showinfo("信息", "默认模型加载成功!")

    def update_frame(self):
        ret, frame = self.cap.read()
        if not ret:
            messagebox.showerror("错误", "无法从摄像头读取帧。")
            return

        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        faces = self.face_cascade.detectMultiScale(gray, scaleFactor=self.scale_factor, minNeighbors=self.min_neighbors)

        for (x, y, w, h) in faces:
            cv2.rectangle(frame, (x, y-50), (x+w, y+h+10), (255, 0, 0), 2)
            roi_gray = gray[y:y + h, x:x + w]
            cropped_img = cv2.resize(roi_gray, (48, 48))
            cropped_img = np.expand_dims(cropped_img, axis=0)
            cropped_img = np.expand_dims(cropped_img, axis=0)
            cropped_img = torch.from_numpy(cropped_img).float()
            prediction = self.model(cropped_img)
            prediction = F.softmax(prediction, dim=1)
            maxindex = int(torch.argmax(prediction).item())
            cv2.putText(frame, self.emotion_dict[maxindex], (x+20, y-60), cv2.FONT_HERSHEY_SIMPLEX, 1, (255, 255, 255), 2, cv2.LINE_AA)

        img = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
        self.photo = ImageTk.PhotoImage(image=Image.fromarray(img))
        self.canvas.create_image(0, 0, image=self.photo, anchor=tk.NW)
        self.master.after(10, self.update_frame)

    def start_detection(self):
        if not self.weights_path:
            messagebox.showerror("错误", "请先加载一个模型。")
            return
        self.scale_factor = self.scale_factor_scale.get()
        self.min_neighbors = int(self.min_neighbors_scale.get())
        self.update_frame()

    def update_scale_factor(self, event):
        self.scale_factor = self.scale_factor_scale.get()

    def update_min_neighbors(self, event):
        self.min_neighbors = int(self.min_neighbors_scale.get())

    def on_closing(self):
        self.cap.release()
        self.master.quit()

def main():
    root = tk.Tk()
    app = EmotionRecognitionApp(root)

    root.protocol("WM_DELETE_WINDOW", app.on_closing)
    root.mainloop()

if __name__ == "__main__":
    main()

二、代码流程图

三、UI效果图

UI效果图描述:

在UI界面上,用户首先会看到一个简洁明了的窗口,其中包括了两个主要的操作按钮:“加载模型”和“开始检测”。通过点击“加载模型”按钮,用户可以浏览并选择一个预先训练好的模型权重文件(.pth格式)。成功加载模型后,会弹出提示信息确认模型已加载。

在界面的下方,用户可以通过两个滑块来调整“缩放因子”和“最小邻居数”。这些参数对于优化人脸检测的准确性至关重要。调整完毕后,用户可以点击“开始检测”按钮,此时程序将开始从摄像头捕获视频流,并实时显示情绪识别的结果。

情绪识别的结果会以文本的形式显示在检测到的人脸下方,使用不同的颜色和字体样式以提高可读性。用户可以随时通过关闭窗口或点击退出按钮来结束程序。

首先实现基于pytorch的情绪识别,如下所示

实现将所有调参变量做到UI界面上,将使用 tkinter 库来创建一个图形用户界面,允许用户通过滑块调整参数,并显示实时视频流和情绪识别结果

运行代码,点击加载模型,将之前跑好的pth文件导入,显示模型加载成功后,点击开始检测。

即可进行情绪识别,如下所示

(1)缩放因子

        这个参数决定了在图像金字塔中,每一层图像的缩放比例。具体来说,它是在每次向下采样时,图像尺寸缩小的比例。较高的缩放因子可以使检测器检测到更小的人脸,但同时也会增加误检(false positives)的可能性,因为较小的特征变化可能会被错误地识别为人脸。

(2)与最小邻居数

        决定在检测过程中,一个候选区域需要有多少个邻近的候选区域才能被确认为真正的人脸。较高的最小邻居数可以减少误检,因为它要求候选区域在多个尺度上都被检测到,从而增加了检测的可靠性。但同时,它也可能错过一些真正的人脸,特别是当人脸在图像中不明显或部分被遮挡时。

(3)考虑场景

        在不同的应用场景中,可能需要根据实际情况调整这些参数。例如,在光照条件较差的环境中,可能需要增加最小邻居数以减少误检。

通过在 UI 界面上提供这些参数的调整选项,用户可以根据自己的需求和环境来优化情绪检测的效果。

感谢你的阅读,祝你生活愉快~

  • 16
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值