【YOLO26系列】基于YOLO26的面部表情检测系统【python源码+Pyqt5界面/WEB+数据集+训练代码】

基于YOLO26的面部表情检测系统

导读

本文基于YOLO26模型,开发了一套面向人类面部表情的目标检测系统。项目采用标注完善的面部表情数据集,涵盖9种常见表情类别,包含15000张标注图像;同时提供PyQt5桌面可视化界面与Flask网页界面,集成单张图片检测、文件夹批量检测、视频检测、摄像头实时检测四大核心功能,并支持检测结果本地保存。系统结合YOLO26模型的高精度与实时性优势,可广泛应用于人机交互、情绪识别、用户体验研究等场景。


一、软件功能演示

本项目提供两种可视化交互界面:PyQt5桌面GUI界面和Flask网页界面,两者均支持以下5种核心功能:

【YOLO26系列】基于YOLO26的面部表情检测系统

1. 单张图片检测

操作流程:打开GUI/网页界面后,点击「打开图片」按钮选择待检测的面部表情图片,点击「开始检测」即可获取检测结果。

检测完成后,系统将自动标注人脸位置、对应表情类别及置信度,并在结果面板中结构化展示检测信息,示例如下:

序号 图片名称 检测类型 表情类别 置信度 坐标位置
1 test_001.jpg 单张图片检测 happy 0.92 (32, 45)-(218, 260)
2 test_002.jpg 单张图片检测 angry 0.87 (45, 62)-(230, 275)
3 test_003.jpg 单张图片检测 surprised 0.89 (28, 38)-(222, 256)

2. 文件夹批量检测

操作流程 :点击「打开文件夹」按钮选择包含多张待检测图片的目录,系统将自动遍历所有图片并完成批量检测,最终输出结构化结果。检测结果将自动保存至results目录,同时在界面展示检测概况统计:

统计项 数值
总检测图片数 15
检测出人脸总数量 18
占比最高表情 happy (6次)

3. 视频检测

操作流程:点击「打开视频」按钮选择目标视频文件,点击「开始检测」后,系统将逐帧对视频进行面部表情检测,实时绘制检测框与类别标签,并支持将检测结果保存为新的视频文件。

检测过程中,界面将实时展示当前帧的检测结果,示例如下:

序号 帧画面 检测类型 表情类别 置信度 坐标位置
1 实时帧 0012 视频检测 natural 0.85 (120, 80)-(250, 240)
2 实时帧 0012 视频检测 sad 0.78 (400, 120)-(520, 280)

4. 摄像头实时检测

操作流程:点击「开启相机」按钮,系统将调用本地默认摄像头,对实时捕获的画面进行面部表情检测,实现实时情绪识别,并支持实时展示各类表情的统计数据。

5. 结果保存

检测完成后,点击「保存结果」按钮,即可将检测结果图片与结构化信息保存至本地results目录:

  • 图片结果:保留检测框与类别标注,便于后续查看;
  • 文本结果:保存为CSV格式表格,包含所有检测目标的序号、类别、置信度、坐标信息,便于后续分析处理。

二、环境搭建

本项目基于PyTorch框架开发,提供两种环境配置方式,可根据自身需求选择:

1. Conda环境安装(推荐)

首先创建并激活新的Conda环境,执行以下命令:

bash 复制代码
# 创建新环境,推荐Python 3.10版本
conda create -n yolo26-expression python=3.10
conda activate yolo26-expression

根据CUDA版本安装对应PyTorch(无NVIDIA GPU可选择CPU版本):

bash 复制代码
# CUDA 11.8版本
conda install pytorch torchvision pytorch-cuda=11.8 -c pytorch -c nvidia

# CPU版本
conda install pytorch torchvision cpuonly -c pytorch

2. pip安装

确保已安装PyTorch后,执行以下命令安装项目依赖:

bash 复制代码
# 进入项目根目录
cd yolo26-facial-expression

# 安装所有依赖包
pip install -r requirements.txt

项目依赖清单如下:

依赖包 版本
Flask 3.1.3
moviepy 2.2.1
numpy 2.5.1
opencv-python 5.0.0.93
PyQt5 5.15.11
PyYAML 6.0.3
tqdm 4.68.4
ultralytics 8.4.92
Werkzeug 3.1.8

三、模型训练、评估、预测

3.1 数据集上传说明

1. 数据集格式要求

本项目采用YOLO标准数据集格式,目录结构如下:

复制代码
dataset/
├── train/
│   ├── images/   # 训练集图片
│   │   ├── img1.jpg
│   │   ├── img2.jpg
│   │   └── ...
│   └── labels/   # 训练集标签(与图片同名的txt文件)
│       ├── img1.txt
│       ├── img2.txt
│       └── ...
├── val/
│   ├── images/   # 验证集图片
│   └── labels/   # 验证集标签
└── test/
    ├── images/   # 测试集图片
    └── labels/   # 测试集标签
2. YOLO格式标签说明

YOLO格式要求每张图片对应一个同名.txt标签文件,内容格式如下:

复制代码
class_index x_center y_center width height

所有坐标均为归一化格式(取值范围0~1),示例如下:

复制代码
4 0.421 0.312 0.182 0.256

对应说明:

  • 4:类别索引(对应happy,从0开始计数);
  • 0.421:人脸框中心点x坐标除以图片宽度的归一化值;
  • 0.312:人脸框中心点y坐标除以图片高度的归一化值;
  • 0.182:人脸框宽度除以图片宽度的归一化值;
  • 0.256:人脸框高度除以图片高度的归一化值。
3. 从VOC格式转换(XML转TXT)

若使用LabelImg等工具标注得到VOC格式的XML标签,可通过以下脚本转换为YOLO格式的TXT标签:

python 复制代码
import os
import xml.etree.ElementTree as ET

# 定义项目类别顺序,需与数据集配置一致
categories = ['angry', 'contempt', 'disgust', 'fear', 'happy', 'natural', 'sad', 'sleepy', 'surprised']
category_to_index = {category: index for index, category in enumerate(categories)}

# 定义输入输出路径,请替换为本地实际路径
input_folder = r'./VOCData/Annotations'  # VOC XML文件存放目录
output_folder = r'./VOCData/labels'      # YOLO TXT文件输出目录

# 确保输出文件夹存在
os.makedirs(output_folder, exist_ok=True)

# 遍历所有XML文件
for filename in os.listdir(input_folder):
    if not filename.endswith('.xml'):
        continue
    xml_path = os.path.join(input_folder, filename)
    
    # 解析XML文件
    tree = ET.parse(xml_path)
    root = tree.getroot()
    
    # 获取图片尺寸信息
    size = root.find('size')
    width = int(size.find('width').text)
    height = int(size.find('height').text)
    
    objects = []
    # 遍历每个标注目标
    for obj in root.findall('object'):
        name = obj.find('name').text
        if name not in category_to_index:
            continue  # 跳过不在类别列表中的目标
        category_index = category_to_index[name]
        
        # 获取标注框坐标
        bndbox = obj.find('bndbox')
        xmin = int(bndbox.find('xmin').text)
        ymin = int(bndbox.find('ymin').text)
        xmax = int(bndbox.find('xmax').text)
        ymax = int(bndbox.find('ymax').text)
        
        # 转换为YOLO格式(中心点坐标+宽高,均做归一化处理)
        x_center = (xmin + xmax) / 2.0
        y_center = (ymin + ymax) / 2.0
        w = xmax - xmin
        h = ymax - ymin
        
        x = x_center / width
        y = y_center / height
        w_norm = w / width
        h_norm = h / height
        
        objects.append(f"{category_index} {x:.6f} {y:.6f} {w_norm:.6f} {h_norm:.6f}")
    
    # 输出TXT标签文件
    txt_filename = os.path.splitext(filename)[0] + '.txt'
    txt_path = os.path.join(output_folder, txt_filename)
    with open(txt_path, 'w') as f:
        for obj in objects:
            f.write(obj + '\n')

print("VOC XML转换为YOLO TXT格式完成!")

执行命令:

bash 复制代码
python VOCData/xml2txt.py
4. 数据集划分脚本

格式转换完成后,使用以下脚本按照8:1:1的比例划分训练集、验证集与测试集:

python 复制代码
import os
import shutil
import random

# 设置固定随机种子,保证划分结果可复现
# random.seed(0)

def split_data(file_path, label_path, new_file_path, train_rate, val_rate, test_rate):
    images = os.listdir(file_path)
    labels = os.listdir(label_path)
    
    # 通过文件名匹配图片与标签文件
    images_no_ext = {os.path.splitext(image)[0]: image for image in images}
    labels_no_ext = {os.path.splitext(label)[0]: label for label in labels}
    matched_data = [(img, images_no_ext[img], labels_no_ext[img]) 
                   for img in images_no_ext if img in labels_no_ext]
    
    # 输出未匹配的文件提示
    unmatched_images = [images_no_ext[img] for img in images_no_ext if img not in labels_no_ext]
    unmatched_labels = [labels_no_ext[label] for label in labels_no_ext if label not in images_no_ext]
    if unmatched_images:
        print("未匹配的图片文件:")
        for img in unmatched_images:
            print(img)
    if unmatched_labels:
        print("未匹配的标签文件:")
        for label in unmatched_labels:
            print(label)
    
    # 打乱数据并按比例划分
    random.shuffle(matched_data)
    total = len(matched_data)
    train_data = matched_data[:int(train_rate * total)]
    val_data = matched_data[int(train_rate * total):int((train_rate + val_rate) * total)]
    test_data = matched_data[int((train_rate + val_rate) * total):]
    
    # 复制训练集数据
    for img_name, img_file, label_file in train_data:
        old_img_path = os.path.join(file_path, img_file)
        old_label_path = os.path.join(label_path, label_file)
        new_img_dir = os.path.join(new_file_path, 'train', 'images')
        new_label_dir = os.path.join(new_file_path, 'train', 'labels')
        os.makedirs(new_img_dir, exist_ok=True)
        os.makedirs(new_label_dir, exist_ok=True)
        shutil.copy(old_img_path, os.path.join(new_img_dir, img_file))
        shutil.copy(old_label_path, os.path.join(new_label_dir, label_file))
    
    # 复制验证集数据
    for img_name, img_file, label_file in val_data:
        old_img_path = os.path.join(file_path, img_file)
        old_label_path = os.path.join(label_path, label_file)
        new_img_dir = os.path.join(new_file_path, 'val', 'images')
        new_label_dir = os.path.join(new_file_path, 'val', 'labels')
        os.makedirs(new_img_dir, exist_ok=True)
        os.makedirs(new_label_dir, exist_ok=True)
        shutil.copy(old_img_path, os.path.join(new_img_dir, img_file))
        shutil.copy(old_label_path, os.path.join(new_label_dir, label_file))
    
    # 复制测试集数据
    for img_name, img_file, label_file in test_data:
        old_img_path = os.path.join(file_path, img_file)
        old_label_path = os.path.join(label_path, label_file)
        new_img_dir = os.path.join(new_file_path, 'test', 'images')
        new_label_dir = os.path.join(new_file_path, 'test', 'labels')
        os.makedirs(new_img_dir, exist_ok=True)
        os.makedirs(new_label_dir, exist_ok=True)
        shutil.copy(old_img_path, os.path.join(new_img_dir, img_file))
        shutil.copy(old_label_path, os.path.join(new_label_dir, label_file))
    
    print("数据集划分完成!")

if __name__ == '__main__':
    # 修改为本地实际路径
    file_path = r"./VOCData/JPEGImages"    # 所有图片存放路径
    label_path = r"./VOCData/labels"       # 所有标签存放路径
    new_file_path = r"./VOCData/VOdevkit"  # 划分后数据集存放路径
    # 划分比例:80%训练,10%验证,10%测试
    split_data(file_path, label_path, new_file_path, train_rate=0.8, val_rate=0.1, test_rate=0.1)

执行命令:

bash 复制代码
python VOCData/SplitDataset.py
5. 配置数据集YAML文件

数据集划分完成后,创建dataset.yaml配置文件,内容如下(请根据本地实际路径修改):

yaml 复制代码
train: ./VOCData/VOdevkit/train/images
val: ./VOCData/VOdevkit/val/images
test: ./VOCData/VOdevkit/test/images

# 类别数量
nc: 9
# 类别名称,需与格式转换时的类别顺序一致
names: ['angry', 'contempt', 'disgust', 'fear', 'happy', 'natural', 'sad', 'sleepy', 'surprised']

3.2 模型训练

完成数据集配置后,执行train.py启动模型训练,核心训练代码如下:

python 复制代码
import warnings
warnings.filterwarnings('ignore')

from ultralytics import YOLO

def main():
    # 加载YOLO26n预训练模型
    model = YOLO('yolo26n.pt')

    # 启动训练
    results = model.train(
        # 数据配置
        data=r'./VOCData/VOdevkit/dataset.yaml',
        imgsz=640,
        batch=16,
        workers=8,
        cache=False,

        # 训练配置
        epochs=300,
        patience=50,
        device=0,
        seed=0,
        project='runs/detect',
        name='train'
    )

if __name__ == '__main__':
    main()

核心训练参数说明:

参数 说明 推荐值
data 数据集YAML配置文件路径 本地实际路径
imgsz 训练输入图像尺寸 640
batch 批量大小,需根据GPU显存调整 8/16/32
workers 数据加载线程数 建议为2的幂次(如8)
cache 是否将数据集缓存到内存,可加快训练速度 服务器环境建议开启(True)
epochs 训练总轮次 300~500
patience 早停耐心值,若验证集指标连续指定轮次无提升则自动停止训练 50
device 训练设备,0代表第一张GPU,无GPU时改为'cpu' 0/'cpu'

启动训练命令:

bash 复制代码
python train.py

3.3 训练结果评估

训练完成后,所有结果将保存至runs/detect/train/目录,核心输出文件如下:

文件/目录 说明
args.yaml 训练参数配置记录
results.csv 每轮训练的损失与指标记录
results.png 训练损失、精确率、召回率等指标的变化曲线图
confusion_matrix.png 混淆矩阵可视化,展示类别预测的混淆情况
confusion_matrix_normalized.png 归一化混淆矩阵可视化,消除类别样本数量差异的影响
BoxPR_curve.png PR曲线(精确率-召回率曲线),反映模型在不同置信度下的性能表现
BoxF1_curve.png F1分数曲线,展示不同置信度下的F1值变化
BoxP_curve.png 精确率曲线,展示不同置信度下的精确率变化
BoxR_curve.png 召回率曲线,展示不同置信度下的召回率变化
labels.jpg 数据集类别分布可视化
train_batch*.jpg 训练批次样本的标注可视化,便于查看数据增强效果
val_batch*_labels.jpg 验证集样本的原始标注可视化
val_batch*_pred.jpg 验证集样本的预测结果可视化,对比真实标注与模型预测
weights/best.pt 验证集表现最优的模型权重文件
weights/last.pt 最后一轮训练的模型权重文件

运行验证脚本,输出模型整体评估指标:

bash 复制代码
python val.py

验证脚本核心代码:

python 复制代码
from ultralytics import YOLO
import numpy as np
from datetime import datetime

# 加载验证集表现最优的模型权重
model = YOLO(r"./runs/detect/train/weights/best.pt")

# 执行验证
metrics = model.val(data=r"./VOCData/VOdevkit/dataset.yaml")

# 计算平均精确率和召回率
mean_p = np.mean(metrics.box.p)
mean_r = np.mean(metrics.box.r)

# 整理输出内容
content = []
content.append("="*60)
content.append(f"验证时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
content.append("="*60)
content.append(f"整体 mAP50:        {metrics.box.map50:.4f}")
content.append(f"整体 mAP50-95:     {metrics.box.map:.4f}")
content.append(f"平均 Precision:    {mean_p:.4f}")
content.append(f"平均 Recall:       {mean_r:.4f}")
content.append("-"*60)
content.append(f"{'类别':<12}{'Precision':<12}{'Recall':<12}{'AP50':<12}")
content.append("-"*60)

# 逐类别输出评估指标
for i, name in enumerate(metrics.names):
    ap50 = metrics.box.ap50[i]
    p = metrics.box.p[i]
    r = metrics.box.r[i]
    content.append(f"{name:<12}{p:.4f}{' ':<6}{r:.4f}{' ':<6}{ap50:.4f}")

# 保存验证结果到文件
with open("validation_result.txt", "w", encoding="utf-8") as f:
    f.write("\n".join(content))

# 控制台打印验证结果
for line in content:
    print(line)

3.4 模型预测

训练完成后,可使用训练好的模型进行多源输入预测,支持单张图片、文件夹、视频、摄像头四种输入类型,预测代码如下:

python 复制代码
from ultralytics import YOLO
import os

# 获取项目根目录
root = os.getcwd()
# 加载训练得到的最优模型权重
model = YOLO(rf'{root}/runs/detect/train/weights/best.pt')

# 设置输入源,可根据需求修改:
# 单张图片: 'img_video/test_imgs/test.jpg'
# 文件夹: 'img_video/test_imgs/'
# 视频: 'img_video/test_MP4.mp4'
# 摄像头: 0 (本地默认摄像头)
source = r'img_video/test_imgs/000001.jpg'

# 执行推理,save=True表示自动保存结果到runs/detect/predict目录
results = model.predict(source, save=True, conf=0.5)

# 弹窗展示检测结果(按任意键关闭弹窗)
results[0].show()

# 将结果保存到自定义路径
results[0].save(filename=r"results/result_test.jpg")

启动预测命令:

bash 复制代码
python predict.py

四、项目目录结构

复制代码
yolo26-facial-expression/
│
├── 📄 README.md                    # 项目说明文档
├── 📄 requirements.txt             # Python依赖包列表
├── 📄 yolo26n.pt                   # YOLO26n预训练模型权重
│
├── 🐍 train.py                     # 模型训练入口脚本
├── 🐍 predict.py                   # 模型预测/推理入口脚本
├── 🐍 val.py                       # 模型验证/评估脚本
│
├── 📂 UI/                          # 界面相关代码目录
│   ├── 🐍 web.py                   # Flask网页后端主程序
│   ├── 🐍 GUI.py                   # PyQt5桌面GUI界面逻辑
│   ├── 📄 config.yaml              # 界面配置文件
│   ├── 📄 user.txt                 # 网页端用户信息文件
│   ├── 📂 templates/               # 网页端HTML模板目录
│   │   ├── 📄 index.html           # 网页主页面
│   │   └── 📄 login.html           # 网页登录页面
│   └── 📂 models/
│       └── 📦 best.pt              # 界面使用的最优模型权重
│
├── 📂 img_video/                   # 测试素材目录
│   ├── 📂 test_imgs/               # 测试图片集
│   │   └── ...
│   └── 🎬 test_MP4.mp4             # 测试视频文件
│
├── 📂 results/                     # 推理结果输出目录
│
├── 📂 runs/                        # 训练运行记录目录
│   └── 📂 detect/train/
│       ├── 📄 args.yaml            # 训练参数配置记录
│       ├── 📄 results.csv          # 训练指标记录文件
│       ├── 📊 results.png          # 训练指标变化曲线图
│       ├── ...                     # 各类模型评估可视化文件
│       └── 📂 weights/
│           ├── 📦 best.pt          # 验证集最优模型权重
│           └── 📦 last.pt          # 最后一轮训练模型权重
│
├── 📂 VOCData/                     # 数据集处理工具目录
│   ├── 🐍 SplitDataset.py          # 数据集划分脚本
│   ├── 🐍 ViewCategory.py          # VOC数据集类别统计脚本
│   ├── 🐍 xml2txt.py               # VOC XML转YOLO TXT格式脚本
│   ├── 🐍 pic to mp4.py            # 图片转视频脚本
│   └── 📂 VOdevkit/
│       ├── 📄 dataset.yaml         # 数据集配置文件
│       └── 📄 数据集单独下载.txt    # 数据集下载说明文档
│
└── 📂 ultralytics/                 # Ultralytics YOLO框架源码目录
    ├── 📂 cfg/                     # 模型与数据集配置文件目录
    ├── 📂 data/                    # 数据加载与数据增强模块
    ├── 📂 engine/                  # 训练、预测、验证核心引擎
    ├── 📂 models/                  # 模型定义模块
    └── ...

五、项目README摘要

本项目是基于YOLO26模型开发的面部表情检测系统,核心内容如下:

  1. 核心功能:支持单张图片、文件夹批量、视频、摄像头四种输入方式的面部表情检测,支持检测结果本地保存,同时提供PyQt5桌面GUI与Flask网页两种交互界面;
  2. 数据集:包含9种常见面部表情类别(生气、轻蔑、厌恶、恐惧、开心、自然、悲伤、困倦、惊讶),可直接下载使用;
  3. 代码支持:提供完整的训练脚本、验证脚本、预测脚本与数据处理脚本,可直接用于自定义数据集的训练;
  4. 环境配置:提供详细的项目依赖清单与PyTorch环境安装指引。

项目启动方式:

  • 启动桌面GUI界面:python UI/GUI.py
  • 启动网页端界面:python UI/web.py

文末互动区

如果您觉得本项目有帮助,欢迎点击【分享】【推荐】支持我们!

如需获取完整项目代码与数据集,回复 「基于YOLO26的面部表情」获取。

相关推荐
远铂1 小时前
BuildAdmin AI内容营销一体化解决方案:整合SEO与GEO优化,解锁AI时代全域流量增长
人工智能·geo·buildadmin
黑马水牛1 小时前
PC+RK3588连板在线调试模型推理
人工智能·经验分享·深度学习
tntxia1 小时前
迁移学习
人工智能
Eloudy1 小时前
基于 RDMA-CM(librdmacm)的聊天程序
网络·人工智能
WUYOUGYLU1 小时前
大模型:人工智能时代的关键引擎
人工智能
2601_950760791 小时前
BCMA:急性髓系白血病免疫治疗的新型可行靶点
人工智能·算法·蛋白
vickycheung31 小时前
启扬I.MX8MPlus开发板如何在NPU上适配Movenet 模型
人工智能·arm 嵌入式开发
刘一说2 小时前
AI科技热点日报 | 2026年07月17日
人工智能·科技
海盗12342 小时前
AI新闻日报_2026-07-17
人工智能