ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

YOLOv5+PyQt5火灾检测可视化系统实战指南

2026/9/15 1:36:43 拓冰建站 浏览量
YOLOv5+PyQt5火灾检测可视化系统实战指南 简介这是一套面向毕业设计场景的火灾检测可视化系统项目基于YOLOv5目标检测框架与PyQt5界面库实现面向计算机、电子信息、数学等相关专业学生可用于课程设计、期末大作业或毕业论文的参考。压缩包共156个文件大小约141.44MB内含YOLOv5训练与推理源码py/pyc、模型配置文件yaml/cfg、预训练权重pt、图片样本jpg/jpeg、Dockerfile及环境依赖说明等能够支撑从数据集准备、模型训练、模型评估到可视化界面集成的完整链路。项目还配有说明文档md/txt与jupyter示例便于梳理模块结构、理解检测逻辑并开展二次开发。sh脚本可用于一键训练或推理降低环境配置成本。已有482人学习下载整体目录清晰、类型丰富对希望快速搭建可演示火灾检测系统或撰写毕业设计的同学而言是一份值得参考的完整资料。1. 从模型到界面YOLOV5PyQt5火灾检测可视化系统的真实工作流把YOLOV5训练好的权重文件和PyQt5做成的桌面程序拼在一起这个标题看起来像是两个独立技术栈的简单叠加真正做的时候却能拆出数据准备、模型训练、界面设计、线程通信、报警联动一大串问题。火灾检测可视化系统的核心并不在模型本身而在于把检测结果以稳定、可演示、可解释的形式送进一个GUI窗口里。适合正在做课程设计或毕业设计、打算快速搭出一套能跑通完整流程的工程的人也适合想了解YOLOV5检测服务如何与桌面端集成的开发者。下面从训练到界面按一条可复现的路线展开。2. 先把模型立住YOLOV5火灾数据集的准备与训练参数2.1 火灾检测不直接迁移COCO权重数据分布决定了模型上限很多第一次做的人会直接拿yolov5s.pt官方的COCO预训练权重去检测火焰结果发现画面里的火苗识别不出来或者把橙色的路灯、晚霞误报成火灾。原因不难理解COCO的80个类别里并没有fire和smoke这两个类别模型虽然学到了通用特征但火焰的纹理、边缘和透明度与常见目标差异非常大而且小尺寸火苗在640分辨率下只有几十个像素正负样本极不均衡。因此在这个项目中训练环节的优先级要高于界面。我一般会先收集火焰和烟雾的图片公开的火灾检测数据集在代码托管站点和学术资源站上能搜到不少优先找已经带有YOLO格式标注的版本省去自己转换的麻烦。如果原始数据只有VOC格式的xml标注需要写一个转换脚本把xml里的bounding box坐标转成归一化的txt格式转换时注意归一化用的是矩形中心点坐标和宽高不是左上角右下角。数据量方面火焰加烟雾各2000张左右是入门门槛类别不平衡会直接拉低mAP。图片里要涵盖白天、夜晚、室内、户外、小目标火源、大面积烟雾等场景。如果原始数据里火焰占绝大多数、烟雾样本很少可以在训练时对烟雾类别施加更高的损失权重或者对含烟雾的图片做更多的随机裁剪和亮度抖动让模型见过更多烟雾形态。2.2 YOLOV5训练自己的数据集目录规划、标注格式与yaml配置YOLOV5对数据集目录没有强约束但按官方推荐的布局可以少踩很多坑。目录结构如下datasets/fire_dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── fire.yamlimages和labels下各放图片与对应的txt标注文件每个txt文件名和图片名一致。标注文件每一行是class_id x_center y_center width height四个坐标值都是相对图片宽高的归一化浮点数范围0到1。类别编号从0开始这个项目里只有fire和smoke两类所以class_id只能是0或1。如果类别顺序换成了smoke在前后面推理时显示的名称也要跟着换。接下来写数据集配置fire.yaml# fire.yaml 数据集配置 train: ./datasets/fire_dataset/images/train val: ./datasets/fire_dataset/images/val nc: 2 names: [fire, smoke]train指定训练图片目录val指定验证图片目录nc是类别数names是类别名。写完后可以用下面命令快速检查标注和图片是否能被正确读取python train.py --data fire.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --cachetrain.py是YOLOV5仓库主目录下的训练脚本--data指定数据集配置--weights指定初始权重用预训练权重做迁移学习收敛明显更快。--img 640表示输入分辨率火灾检测里的火焰常以远处的小目标出现分辨率低于640时漏检率会明显上升。--batch 16需要约8GB显存如果显存不够就降到8--cache参数可以把所有训练图片预加载进内存省掉大量磁盘IO时间第一次跑会等图片缓存构建完之后速度提升明显。2.3 训练时值得盯的三个指标与超参数选择训练过程中不要只看loss曲线loss下降不代表检测效果够用。需要同时盯住precision、recall和mAP0.5这三个值会在每轮epoch结束后的验证集上输出。指标含义火灾场景里的容忍度mAP0.5IoU阈值0.5时各类别平均精度0.8以上才能作为演示版本recall真实火灾目标被找回的比例宁可误报也不能漏报recall优先precision检出目标中真实目标的比例过低会频繁误报至少0.7F1-scoreprecision与recall的调和平均演示时看这个值更直观按经验这个任务从yolov5s开始调hyp.scratch-low.yaml里的lr0保持默认0.01就行优先调整的是数据增强参数mosaic设为1.0可以提升小目标表现但训练后期建议关掉否则部分目标被裁剪得过于碎片化会破坏真实火焰的连续性如果发现验证集上的mAP在最后20轮不再上升可以增大mixup系数或减少epochs来抑制过拟合。训练结束后用best.pt做推理测试测试别只挑训练集里的图找一些网上下载的真实火灾照片看误报情况。这一步决定了后面界面开发时模型是否可靠如果到界面阶段再发现模型选错返工成本会成倍增加。3. 用PyQt5把检测结果变成可操作的监控界面3.1 PyQt5界面骨架主窗口、视频画布与控制区拿到训练好的best.pt之后下一步就进入界面开发。PyQt5安装用pip即可在PyCharm的终端里直接执行pip install pyqt5当前PyQt5版本停留在5.15系列不会自动跳到PyQt6可以放心使用。界面骨架我一般用QMainWindow搭左侧是控制面板中间是视频画布画布用一个QLabel控件通过setPixmap把每一帧更新上去而不是用QPainter直接绘制整个窗口。核心代码结构如下from PyQt5.QtWidgets import QMainWindow, QLabel, QPushButton, QVBoxLayout, QWidget class FireDetectWindow(QMainWindow): def __init__(self): super().__init__() self.setWindowTitle(YOLOV5PyQt5 火灾检测可视化系统) # 视频画布用QLabel展示帧图像尺寸随窗口缩放 self.canvas QLabel() self.canvas.setMinimumSize(800, 600) # 控制按钮开始检测、停止检测、选择视频源 self.start_btn QPushButton(开始检测) self.stop_btn QPushButton(停止) self.start_btn.clicked.connect(self.start_detection) self.stop_btn.clicked.connect(self.stop_detection) layout QVBoxLayout() layout.addWidget(self.canvas) layout.addWidget(self.start_btn) layout.addWidget(self.stop_btn) container QWidget() container.setLayout(layout) self.setCentralWidget(container)这个骨架把界面和业务逻辑分开了。canvas负责显示画面start_btn和stop_btn负责控制开关clicked信号连接到对应的槽函数。真正的检测逻辑不会写在这一层QMainWindow只做两件事响应用户操作、刷新显示结果。如果在这里直接写YOLOV5推理循环界面会在每帧推理期间完全卡死鼠标拖不动窗口按钮没有反馈所以第3.3节必须引入独立线程。3.2 在界面上叠加检测框把YOLOV5的坐标换算成Qt坐标YOLOV5的后处理输出x1, y1, x2, y2这四个值是像素坐标可以直接在原始帧上画框再把画好框的帧转成QImage显示。不要在渲染到界面时再做缩放那样坐标会偏移。import cv2 from PyQt5.QtGui import QImage, QPixmap def draw_detections(frame, results, model): # results是YOLOV5后处理后的结果每个元素是[x1, y1, x2, y2, conf, cls] for *xyxy, conf, cls in results: x1, y1, x2, y2 map(int, xyxy) label f{model.names[int(cls)]} {conf:.2f} # 在OpenCV的BGR帧上画框颜色BGR红色对应火焰告警 cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(frame, label, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) return frame def frame_to_pixmap(frame): # BGR转RGB再包装成QImage否则画面颜色会偏蓝偏绿 rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch rgb.shape qimg QImage(rgb.data, w, h, ch * w, QImage.Format_RGB888) return QPixmap.fromImage(qimg)画框直接使用OpenCV而不是Qt的QPainter是因为帧本身就是OpenCV的ndarray用cv2.rectangle成本低也避免在Qt绘画事件里做耗时操作。QImage.Format_RGB888要求数据是RGB顺序所以必须先cvtColor。如果画面在界面上被缩放QPixmap显示时会自动拉伸但检测框已经画在原始帧上所以不会错位。需要留意的是results里的cls值是numpy.float32取类别名时要先强转成int否则model.names的下标会报错。3.3 用QThread跑推理避免界面卡死的三个关键点界面卡死的根因是推理阻塞了Qt主线程。解决办法是把视频读取和模型推理放到QThread里通过信号把处理完的帧传回主线程显示。下面是一个最小可运行的线程封装from PyQt5.QtCore import QThread, pyqtSignal import cv2 class DetectThread(QThread): # 自定义信号发送当前帧供界面刷新 frame_ready pyqtSignal(object) def __init__(self, model, source0): super().__init__() self.model model self.source source self.running True def run(self): cap cv2.VideoCapture(self.source) while self.running: ret, frame cap.read() if not ret: break # 调用YOLOV5的推理输入是原始BGR帧 results self.model(frame) annotated draw_detections(frame, results, self.model) self.frame_ready.emit(annotated) cap.release() def stop(self): self.running False self.wait()这段代码里有两个关键点。第一frame_ready是跨线程信号触发后主线程的槽函数会排队执行中间不会阻塞run里的视频循环。第二stop方法用self.wait()等待线程退出防止界面关闭后子线程还在访问已经释放的模型对象。还需要注意QThread的线程亲和性不要在DetectThread里直接调用任何QWidget方法所有界面刷新都必须通过信号回到主线程。第三个关键点是异常处理视频文件损坏或摄像头被拔出时cap.read()会连续返回Falserun里要加一个最大失败次数连续失败30次就主动退出线程并发信号通知界面否则线程会在空循环里空转。4. 把模型和界面接起来实时视频流、报警联动与性能优化4.1 从视频帧到检测结果的数据管线设计实时视频流和单张图片检测之间最大的差别在于摄像头每秒产生25到30帧而YOLOV5在CPU上推理一帧往往需要200到500毫秒在GPU上也要30到80毫秒。如果每一帧都送进模型实时性必然崩塌。常见的做法是把视频读取和推理拆成两个环节用跳帧策略控制推理频率。# 数据管线核心跳帧推理 保留最近一次检测结果 frame_index 0 infer_interval 2 # 每2帧推理一次 last_boxes [] while cap.isOpened(): ret, frame cap.read() if not ret: break if frame_index % infer_interval 0: results model(frame) last_boxes results # 保存结果供后续帧显示 # 非推理帧也画框把上一帧的检测结果贴到新帧上 annotated draw_detections(frame, last_boxes, model) emit_frame(annotated) frame_index 1这里的逻辑是推理帧和显示帧分离。每隔infer_interval帧做一次检测中间跳过的帧直接复用上一次检测到的框画面保持连续但推理次数减半。infer_interval的取值要看硬件能力GPU运行时设2或3CPU运行时设5或10否则界面流畅度和检测实时性会互相打架。注意保存的检测框坐标要和当前帧尺度一致如果视频分辨率没变直接复用没问题如果中途切换了视频源或分辨率变化必须清空last_boxes否则旧坐标会画在错误位置上。4.2 报警别做成阻塞倒计时、防抖与声音提示火灾检测系统里最核心的联动是报警。简单粗暴的做法是只要检测到fire就立刻弹出QMessageBox弹窗结果视频每几分钟就弹一次用户要点无数次确定反而阻碍了观察现场。更好的设计是引入连续帧命中计数和触发阈值# 报警防抖逻辑连续fire_hit_threshold帧检测到火焰才触发 fire_count 0 fire_hit_threshold 5 # 连续阈值建议5~10 is_alarm_active False while True: frame read_frame() boxes detect(frame) fire_detected any(model.names[int(b[5])] fire for b in boxes) if fire_detected: fire_count 1 else: fire_count 0 is_alarm_active False if fire_count fire_hit_threshold and not is_alarm_active: is_alarm_active True start_alarm() # 只触发一次fire_count连续累加一旦中途有一帧没有检测到火焰就清零。这样做可以过滤掉单帧误检比如镜头快速晃动、光照瞬时变化导致的假阳性。is_alarm_active保证报警只触发一次直到连续未命中才复位。阈值设太大会导致真实小火苗出现后延迟报警设太小又容易闪断建议在答辩演示时用本地视频实测确定一般5帧以内既能防抖又不明显迟钝。报警之后还应该自动截图存档保存带检测框的帧到本地目录并记录时间戳。这个功能在毕业设计答辩时很加分因为说明文档里可以写“系统具备报警证据留存能力”。4.3 推理速度上不去时先查这四个地方界面能跑通之后常见的问题就是帧率太低。下表是我在调试这类系统时优先排查的四个位置。排查点现象调整方式输入分辨率推理耗时集中在640分辨率上测试img 480先看漏检是否明显增加模型尺寸yolov5s仍然太慢换yolov5n精度下降但速度快一倍以上推理框架单帧推理时GPU利用率低用TensorRT或ONNX Runtime提高吞吐OpenCV解码cap.read()本身占CPU降低摄像头采集分辨率或改用FFMPEG后端最后一个容易被忽略的地方是CPU推理时的线程配置。YOLOV5的export.py导出的ONNX模型在CPU上可以考虑用OpenVINO执行器PyQt5界面完全不用改只需把推理session的provider改成OpenVINO帧率往往能提高两三倍。如果项目只要求演示直接在DetectThread里加载优化后的模型即可注意导出后要重新跑一次相同的测试视频确认精度没有明显下降。5. 毕业设计答辩前必做的五项验证与两个容易被追问的边界5.1 用一段固定视频做演示比现场接摄像头更稳毕业设计答辩当天最怕摄像头驱动异常或现场光线不对导致整个演示卡住。我一般会把测试视频提前录制成mp4界面里加一个“本地视频”下拉选项从文件路径读取视频流。这样在操作系统环境多变的多媒体教室不用依赖摄像头驱动也能完整体验检测流程评委提问时还可以重放关键片段展示报警联动过程。5.2 五项验证覆盖演示全流程第一个验证是长时间运行的稳定性。让系统连续运行30分钟以上观察内存占用是否持续增长。如果QThread里的帧队列没有被及时清空内存会慢慢涨上去最后界面失去响应可以把任务管理器截图放进说明文档作为证据。第二个验证是无标签真实视频的误报率。下载几段没有标注过的火灾现场视频用界面完整跑一遍记录误报和漏报。这一步可以提前发现模型对特定场景的过拟合比如傍晚的红色灯光、墙面上的橙色装饰板。第三个验证是视频中断的恢复。在播放视频过程中手动删除视频文件或拔出摄像头系统不能崩溃要能回退到等待状态并弹出错误提示。很多毕业设计演示都挂在这一步上。第四个验证是三种报警触发方式分别测试声音、弹窗、截图存档。注意弹窗不要阻塞推理线程可以用信号槽把弹窗请求发到主线程处理。第五个验证是切换设备。拿一台没有NVIDIA显卡的笔记本跑一遍CPU推理确认帧率不低于5。如果低于5要把输入分辨率降到480或换yolov5n否则答辩现场的笔记本带不动演示效果会非常尴尬。两个容易被追问的边界第一个是模型只对训练数据分布内的火焰和烟雾有效对于镜面反光、橙红色塑料物体和蒸汽模型可能会误判。答辩时要主动说明数据增强策略和误报控制方法不能声称该系统可以覆盖所有火灾场景。第二个是PyQt5只是可视化外壳检测精度完全由YOLOV5权重决定如果评委要求提高mAP回应方向是先扩充数据集而不是调界面代码。把这两个边界写进说明文档答辩时会被认为是真正理解了自己做的东西。本文还有配套的精品资源点击获取