基于YOLOv8与PySide6的火灾火焰检测识别系统实现
2026/9/19 8:48:51 网站建设 项目流程

在实际消防预警项目中,火焰检测往往需要把目标检测模型和桌面客户端放到一起工作。基于 YOLOv8 和 YOLOv5+PySide6 的火灾火焰检测识别系统,正是解决“视频流进来、火焰框出来、告警能看到”这一类问题的常见方案。YOLO 负责定位画面中的火焰区域,PySide6 负责生成可操作的桌面界面,两者结合以后,既可以处理图片和视频,也可以接入摄像头做实时识别。下面从技术选型讲起,逐步介绍数据集准备、模型训练、界面集成、运行验证和常见问题排查,最终落成一套可复现的桌面检测工具。

1. 火焰检测系统的技术选型:YOLO 负责“看见”,PySide6 负责“操作”

1.1 火焰检测和普通目标检测的差异

火焰检测在安防消防场景里并不等于普通的分类任务。火焰没有固定轮廓,颜色会随燃烧物质和环境光照变化,形状也会不断抖动,这导致传统的颜色阈值分割很容易把夕阳、车灯、红色反光误判成火焰。目标检测模型的做法是从大量标注样本中学习火焰的颜色、纹理、边缘和上下文特征,因此比纯图像处理更稳健。

YOLO 系列属于单阶段目标检测算法。它把目标检测当成回归问题,在整张图上直接预测边框位置、类别和置信度。对火焰检测场景来说,单阶段模型最大的价值是实时性好,能够以较低延迟处理摄像头视频流。相比两阶段检测器,YOLO 在同样硬件条件下的推理速度通常更快,落地到桌面客户端更容易满足实时预览需求。

1.2 YOLOv5 和 YOLOv8 各自适合什么场景

YOLOv5 是社区使用非常广泛的目标检测框架,资料多、插件多,早期有很多基于它的消防项目。YOLOv8 是后续迭代版本,训练入口更统一,模型结构也做了调整,使用 C2f 模块和 Anchor-Free 解耦头,自定义数据集时可以通过一个 YOLO API 完成训练、验证、导出和推理。

从项目维护角度看,两者不一定是替代关系。老项目如果已经用 YOLOv5 训练了一批火焰数据,可以继续沿用;新项目如果从零开始,建议优先考虑 YOLOv8,因为它对自定义数据集的流程更友好,导出 ONNX、TensorRT 也比较方便。如果团队希望同时支持两个模型,则需要在业务层抽象一个检测接口,避免界面代码绑定到具体版本。

下面用表格整理两者的常见差异,实际选型还要结合硬件、历史代码和团队熟悉程度判断。

对比项YOLOv5YOLOv8
常用仓库独立 YOLOv5 仓库,detect.py、train.pyultralytics 统一包,YOLO API
网络结构CSPDarknet 骨干,Anchor-Based 预测C2f 模块,Anchor-Free 解耦头
自定义训练有成熟脚本,需要按仓库约定整理data.yaml + YOLO API,流程统一
推理接入torch.hub、detect.py、ONNXultralytics YOLO 类,predict/export
部署方式ONNX、TensorRT、TorchScriptONNX、TensorRT、OpenVINO 等更统一
维护成本资料多,社区成熟新项目更省心,升级路径明确

1.3 PySide6 在系统里的定位

PySide6 是 Qt 6 的 Python 绑定,用来做桌面界面。它的作用是把 YOLO 的检测能力包装成用户可以操作的窗口:选择图片、打开视频、启动摄像头、调整置信度、查看检测结果。

为什么不直接用命令行处理视频?因为火焰检测系统最终可能交给安保人员或值班员使用,这些人不会去修改训练参数,也不应该直接接触模型权重。一个简单的界面,至少需要包含文件选择按钮、检测结果预览区和日志区。PySide6 的优势是控件齐全,能直接配合 OpenCV 显示图片,也能通过 QThread 把耗时推理放到后台线程,避免窗口卡死。

2. 环境准备:先让模型推理和桌面界面都跑起来

2.1 需要的基础软件环境

开发这套系统最常见的技术栈是 Python + PyTorch + OpenCV + PySide6。Python 版本建议使用 3.9 或 3.10,这两个版本对 PySide6、ultralytics 和 PyTorch 的兼容性都很好。硬件方面,训练阶段推荐有 NVIDIA GPU,显存 6GB 以上跑 YOLOv8s 比较合适;如果只做推理,CPU 也可以运行,只是实时视频检测的帧率会低一些。

下面是一个环境检查清单,开始安装前先确认:

  • Python 版本是否在 3.8 到 3.10 之间。
  • 是否有 NVIDIA 显卡,并确认显卡驱动版本。
  • 是否已有 conda 或 venv 虚拟环境管理工具。
  • 操作系统是 Windows 还是 Linux,PySide6 的显示依赖不同。
  • 是否预留了至少 10GB 磁盘空间用于安装依赖和保存训练结果。

2.2 安装 ultralytics、PySide6 和 OpenCV

安装分为两步:先装 PyTorch,再装其他库。PyTorch 的安装方式决定了 GPU 是否可用,建议不要直接用默认命令,而是根据显卡驱动安装对应 CUDA 版本。下面是使用 conda 创建环境的示例。

conda create -n fire_detection python=3.9 -y conda activate fire_detection # 安装 PyTorch,这里以 CUDA 11.8 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # 安装训练和推理相关依赖 pip install ultralytics opencv-python pyside6

如果只是 CPU 环境,可以去掉--index-url参数,直接安装默认 PyTorch 包。安装完成后,建议运行下面命令验证依赖是否可用。

python -c "import ultralytics, cv2, PySide6; print(ultralytics.__version__, cv2.__version__, PySide6.__version__)"

这里要注意:PySide6 版本更新较快,如果后面发现QVBoxLayoutQImage相关 API 报错,多半是版本接口变化,需要根据自己的 PySide6 版本调整代码。

2.3 项目目录和模型文件规划

检测系统不建议把所有代码写在一个文件里。训练代码、推理代码、界面代码和模型权重分开存放,后续维护会方便很多。下面是一个适合个人项目的目录结构。

fire_detection/ ├── main.py # PySide6 主程序入口 ├── detector.py # 检测逻辑封装 ├── ui_main.py # 主窗口界面代码 ├── datasets/ │ ├── images/ │ │ ├── train/ │ │ └── val/ │ └── labels/ │ ├── train/ │ └── val/ ├── runs/ │ └── detect/ │ └── fire_v1/ │ └── weights/ │ ├── best.pt │ └── last.pt └── models/ └── fire_data.yaml

detector.py负责加载 YOLO 模型并输出标注后的图像,ui_main.py负责窗口控件和信号槽连接,main.py只负责启动界面。这样写的好处是,后续更换模型的时候不需要改动整个窗口逻辑。

3. 准备火灾火焰数据集,完成 YOLOv8 训练与增量训练

3.1 火焰数据集的标注格式

YOLO 系列训练时使用的是 txt 标注文件,每张图片对应一个同名的 txt 文件。文件每一行表示一个目标,格式如下。

类别编号 中心点x 中心点y 归一化宽度 归一化高度

如果只检测火焰一个类别,类别编号就是 0。中心点和宽高都要除以图片宽高,归一化到 0 到 1 之间。例如下面这行表示一个火焰目标,中心在图片横向 0.5、纵向 0.4 的位置,宽度占全图 0.2,高度占全图 0.3。

0 0.500 0.400 0.200 0.300

使用 LabelImg 或 Label Studio 标注时,要特别注意输出格式选 YOLO,而不是 VOC 或 COCO。VOC 的 XML 转 YOLO 需要额外脚本,容易在目录名和类别 id 上出错。

3.2 编写 data.yaml 并拆分数据集

训练前需要准备一个 data.yaml,告诉 YOLO 训练数据和验证数据在哪里,以及有哪些类别。下面是一个火焰数据集的示例。

path: D:/datasets/fire_smoke train: images/train val: images/val nc: 1 names: 0: fire

path是数据集根目录的绝对路径,trainval是相对于根目录的训练和验证图片目录。类别数量nc必须和names一一对应,否则训练过程会出现索引错位。

数据拆分要保证训练集和验证集不重叠。常见做法是每个场景的连续帧只放进一个集合,避免同一段视频既出现在训练集又出现在验证集,否则评估的 mAP 会虚高。

3.3 YOLOv8 训练命令和增量训练

使用 ultralytics 训练 YOLOv8 非常直接。在命令行执行,或者在 Python 脚本里调用YOLO.train()都可以。下面是最小训练命令。

yolo detect train data=D:/datasets/fire_smoke/fire_data.yaml model=yolov8s.pt epochs=100 imgsz=640 batch=16 device=0

也可以写成 Python 脚本,方便把训练参数保存到文件。

from ultralytics import YOLO model = YOLO("yolov8s.pt") model.train( data="D:/datasets/fire_smoke/fire_data.yaml", epochs=100, imgsz=640, batch=16, device=0, workers=4, )

训练过程中如果中断,不需要从头开始。YOLOv8 会自动保存last.pt,可以用resume=True继续训练。

model = YOLO("runs/detect/fire_v1/weights/last.pt") model.train( data="D:/datasets/fire_smoke/fire_data.yaml", epochs=50, resume=True, )

增量训练在火焰检测里很实用。第一次训练可能只有几千张图片,模型对夜间火焰、远处小火苗的检测效果不好。后续补充了新的负样本和火焰样本后,按住上次的best.ptlast.pt继续训练,会比重新训练节省大量时间。需要注意的是,增量训练的数据集类别定义、图片尺寸要保持一致,否则模型结构会对不上。

3.4 训练完成后的验证与导出

训练结束后,在runs/detect/fire_v1/下会生成weights/best.ptweights/last.ptconfusion_matrix.pngresults.png等文件。best.pt是验证集上指标最好的模型,部署时优先选择它。先用下面的命令验证单张图片效果。

yolo predict model=runs/detect/fire_v1/weights/best.pt source=test_fire.jpg conf=0.25

如果要把模型接入 PySide6 做实时推理,不一定要用 PyTorch 原格式。对于桌面端,尤其是 CPU 环境,建议导出为 ONNX,再交给 ONNX Runtime 或 OpenVINO 加载。

yolo export model=runs/detect/fire_v1/weights/best.pt format=onnx opset=12

导出后可以看到生成的best.onnx。ONNX 文件体积通常比 PyTorch 权重小,推理时依赖也更轻。如果界面直接使用 ultralytics 的YOLO("best.pt")加载,也可以,但首次加载 PyTorch 模型需要导入 torch,启动时间会更长。

3.5 训练结果文件怎么看

results.png中包含训练损失曲线、验证损失曲线、mAP 等结果。火焰检测场景里,mAP 50 是最先看的指标,其次是 mAP 50-95。mAP 50 高说明模型能框出基本火焰区域,mAP 50-95 高说明边界框定位更准。

损失曲线如果出现训练损失下降但验证损失上升,通常说明过拟合,可以增加数据增强、增加数据量或缩小模型规模。火焰数据里如果模型对灯光误报很多,检查方向不是单纯增加训练轮数,而是补充大量“像火但不是火”的负样本。

4. 用 PySide6 搭建检测界面,把 YOLO 模型接入图片、视频和摄像头

4.1 界面功能拆分

桌面端火焰检测系统至少要包含三个功能:图片检测、视频检测、摄像头实时检测。界面可以通过三个按钮拆开,再配一个结果显示区和一个置信度输入框。

界面代码不用追求复杂,核心是把长耗时操作放到后台线程。下面是一个最简主窗口的代码结构,只保留了关键部分。

from PySide6.QtWidgets import QMainWindow, QLabel, QPushButton, QFileDialog, QLineEdit, QVBoxLayout, QWidget class MainWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle("火灾火焰检测识别系统") self.label = QLabel("检测结果") self.conf_input = QLineEdit("0.25") self.image_btn = QPushButton("选择图片检测") self.video_btn = QPushButton("选择视频检测") self.camera_btn = QPushButton("启动摄像头检测") layout = QVBoxLayout() layout.addWidget(self.conf_input) layout.addWidget(self.image_btn) layout.addWidget(self.video_btn) layout.addWidget(self.camera_btn) layout.addWidget(self.label) container = QWidget() container.setLayout(layout) self.setCentralWidget(container) self.detector = None

QLineEdit用来接收置信度阈值。这里要注意,不能只在初始化时读取输入框内容。用户可能在窗口打开后才改数值,所以应该在点击检测按钮的槽函数中重新调用self.conf_input.text(),并且判断输入是否为空、能否转成浮点数。

4.2 后台推理线程

在 PySide6 中,不能把耗时的视频循环直接放在按钮点击回调里,否则界面会卡住,窗口无法拖动或关闭。正确做法是把视频读取和模型推理放到 QThread 中,通过信号把检测后的图像发送给主线程。

from PySide6.QtCore import QThread, Signal import cv2 class VideoWorker(QThread): frame_ready = Signal(object) error = Signal(str) def __init__(self, detector, video_source=0, parent=None): super().__init__(parent) self.detector = detector self.video_source = video_source self._running = False def run(self): cap = cv2.VideoCapture(self.video_source) if not cap.isOpened(): self.error.emit("无法打开视频源") return self._running = True while self._running: ok, frame = cap.read() if not ok: break annotated = self.detector.detect_frame(frame) self.frame_ready.emit(annotated) cap.release()

video_source如果是摄像头索引,就传 0 或 1;如果是视频文件,就传文件路径。这个设计可以同时支持视频文件和摄像头。线程退出时通过_running标志控制,避免强制终止线程导致摄像头没有释放。

4.3 检测逻辑封装

detector.py是模型和界面之间的边界。为了同时兼容 YOLOv5 和 YOLOv8,可以封装一个统一接口。下面示例使用 ultralytics 加载 YOLOv8,用 torch.hub 加载 YOLOv5。

import cv2 class YOLOv8Detector: def __init__(self, model_path, conf=0.25, iou=0.45): from ultralytics import YOLO self.model = YOLO(model_path) self.conf = conf self.iou = iou def detect_frame(self, bgr_frame): results = self.model.predict( source=bgr_frame, conf=self.conf, iou=self.iou, verbose=False, ) return results[0].plot()
import torch class YOLOv5Detector: def __init__(self, model_path, conf=0.25): self.model = torch.hub.load( "ultralytics/yolov5", "custom", path=model_path, force_reload=False, ) self.model.conf = conf def detect_frame(self, bgr_frame): results = self.model(bgr_frame) return results.render()[0]

results[0].plot()返回的是画好检测框和标签的 BGR 图像数组,可以直接在窗口中显示。两个类的detect_frame输入输出保持一致,主窗口不需要关心当前用的是 YOLOv5 还是 YOLOv8。

4.4 在主线程中更新界面

QThread 中不能直接修改 QLabel,需要把检测结果通过信号传回来。主线程收到frame_ready信号后,将 numpy 数组转换为QImage,再设置到 QLabel。

from PySide6.QtGui import QImage, QPixmap import numpy as np class MainWindow(QMainWindow): # 已有代码省略 def on_frame_ready(self, frame): rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, c = rgb.shape image = QImage(rgb.data, w, h, c * w, QImage.Format_RGB888).copy() self.label.setPixmap(QPixmap.fromImage(image))

这里特别要注意QImage后面加.copy()。因为rgb.data指向的是 numpy 数组内部内存,如果不复制,QMage 在数组被覆盖或释放后可能显示花屏或崩溃。

5. 运行验证:输入、阈值、输出和日志都要检查

5.1 用测试图片和视频验证

训练好的模型不能只在训练集上验证。至少准备三类测试数据:白天火焰、夜间火焰、类似火焰的干扰物。把这三类图片分别放入测试目录,逐一运行检测,记录漏检和误报情况。

命令行可以快速验证单张图和视频:

yolo predict model=runs/detect/fire_v1/weights/best.pt source=test.jpg save=True yolo predict model=runs/detect/fire_v1/weights/best.pt source=test_video.mp4 save=True

在 PySide6 界面里,选择图片检测后,需要检查三件事:窗口是否卡住、结果是否显示、日志区是否输出模型加载和检测信息。视频检测要额外验证关闭窗口时线程能正常退出,摄像头要及时释放。

5.2 置信度和 IoU 阈值对结果的影响

界面中的conf阈值是最常调整的参数。阈值调高,误报减少,但漏检增加;阈值调低,检测框变多,容易把灯光和暖色物体标成火焰。IoU 阈值影响同一火焰区域的重叠框数量,不同模型对 IoU 的敏感度不同。

下面是一个参数速查表,实际项目可以按这个思路调。

参数默认值调高影响调低影响
conf0.25检测框更少,误报降低,漏检增加检测框更多,容易误报
iou0.45重叠框合并更少,同一目标可能出现多框重叠框合并更多,小目标可能被合并掉
imgsz640小目标识别更好,推理变慢速度更快,小目标可能漏检

火焰检测场景建议先固定imgsz=640,然后根据测试集反复调整conf。不一定要追求所有检测框都准确,关键是值班人员看到的误报次数要在可接受范围。

5.3 验证清单

每次修改模型或界面后,建议按下面清单走一遍:

  • 单张近景火焰图能否正确框出火焰。
  • 单张远景小火苗能否检测到,漏检是否在可接受范围。
  • 日落、路灯、红色车灯等干扰图是否误报。
  • 视频检测时帧率是否满足实时预览需求。
  • 点击停止按钮后线程是否退出,摄像头指示灯是否熄灭。
  • 关闭窗口时是否出现 Python 报错或内存持续增长。
  • 模型权重路径是否存在中文,中文路径是否能正常加载。

6. 常见问题排查与生产环境部署建议

6.1 常见错误现象与处理方案

模型训练和桌面集成过程中,错误类型比较集中。下面表格整理了火焰检测系统开发时最常见的几类问题。

问题现象常见原因检查方式处理建议
训练时提示无法加载数据集data.yaml 路径写错或类别数量不一致检查 yaml 中的 path、train、val使用绝对路径,确认 labels 和 images 目录同名
模型加载后检测不到火焰置信度阈值过高,模型误学到其他特征降低 conf,先输出调试图片检查训练集标注和模型在验证集上的 mAP
PySide6 窗口点击按钮后卡死推理放在主线程执行看 CPU 是否占满,窗口是否无法拖动把视频循环放到 QThread
摄像头无法打开索引错误或摄像头被其他程序占用单独测试cv2.VideoCapture(0)依次尝试 0、1、2 索引
显示图像花屏或颜色异常BGR 和 RGB 混用,QImage 内存未复制检查通道转换代码先用 cvtColor 转 RGB,再加.copy()
QLineEdit 输入不生效只在窗口初始化时读取 text检查按钮点击回调在点击检测按钮时重新读取输入框内容
YOLOv5 和 YOLOv8 权重混用加载方式不匹配看报错栈是 torch.hub 还是 ultralytics按模型版本切换加载逻辑

6.2 排查顺序

遇到检测或界面异常,不要直接改随机参数,可以按下面顺序排查。

  1. 先确认输入是否正确:图片路径、视频路径、摄像头索引。
  2. 再确认模型是否加载成功:打印模型结构或测试一张已知图片。
  3. 然后确认预处理是否一致:图像尺寸、通道顺序、归一化方式。
  4. 再确认阈值参数:当前 conf 是否过高或过低。
  5. 最后看界面线程:是否阻塞了主事件循环。

例如“界面能打开但视频不显示”的问题,排查重点是摄像头是否释放、QThread 信号是否连接、detector 是否在子线程中被正确初始化。很多情况下,把崩溃日志的完整堆栈打出来,就已经能定位到具体位置。

6.3 生产环境部署建议

学习环境用 PyTorch 权重直接推理没有问题,但生产环境建议做以下调整。

第一,模型导出为 ONNX 或 TensorRT。PyTorch 推理依赖 torch,启动慢且占用内存多。ONNX 模型体积更小,CPU 上可用 OpenVINO 加速,NVIDIA 显卡上可用 TensorRT 加速,火焰检测的实时性会更好。

第二,增加配置外置化。模型路径、置信度阈值、摄像头地址不应该硬编码在界面代码中,可以放到 config.yaml 或 json 文件里。

model: path: ./models/best.onnx conf: 0.25 iou: 0.45 camera: source: 0 width: 1280 height: 720

第三,增加告警和日志。火焰检测系统不只是显示检测框,还应该在连续多帧出现高置信度火焰时触发提示音、弹窗或记录日志。日志至少记录时间、图片来源、置信度和检测框坐标,方便事后回溯误报。

第四,摄像头断线重连。现场环境摄像头可能掉线,程序要在读取失败后自动重连,不能直接退出。重连次数和重连时间间隔可以做成可配置项。

6.4 可复用的最佳实践清单

这里整理一份适合火焰检测系统开发和维护的清单,可以直接复制到项目文档中。

  • 数据集文件夹使用英文命名,不要带空格和中文。
  • 标注时统一类别 id,训练前用脚本检查 labels 中是否有没有对应图片的文件。
  • 训练集和验证集按场景划分,不按单帧随机划分。
  • 首次训练用 YOLOv8s,快速验证流程,再根据效果决定是否换更大模型。
  • 界面加载模型放在主窗口初始化之后的单独方法中,避免启动即卡住。
  • 视频检测和摄像头检测统一走 QThread,停止时关闭_running标志并 release 摄像头。
  • 所有用户输入在点击按钮后再读取,不缓存 QLineEdit 的 text。
  • 检测结果图像先转 RGB 再放入 QImage,并且复制内存。
  • 生产环境导出 ONNX 模型,模型和阈值配置放在外部文件。
  • 每次更新数据集后保留训练命令和数据集版本号,方便复现。

这套系统从数据准备到桌面界面,覆盖了火焰检测项目的大多数关键环节。实际项目中,最值得优先做的事是把数据集质量做干净,然后固定好模型版本和界面交互,最后再考虑接入 TensorRT 或 ONNX Runtime。如果只是复现 Demo,用 YOLOv8s 加一段 50 到 100 轮训练就能看到完整效果;如果要交给现场人员使用,还要补上日志、异常提醒、模型更新机制和摄像头断线重连。把 YOLO 的检测能力和 PySide6 的交互能力分开维护,后续替换模型或调整界面都会容易很多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询