YOLOv8+PyQt5抽烟检测系统实战:从训练到部署
2026/9/6 4:03:26 网站建设 项目流程

先理清一个判断:这类“YOLOv8 + PyQt5 抽烟检测”项目,真正的难点通常不在模型本身,而在“怎么把模型训练好、怎么让界面不卡死、怎么在别人电脑上也能跑起来”。模型结构有现成的,训练脚本有公开的,界面框架也有官方示例,但把这三者拼成一个能稳定使用的系统,中间会踩到很多文档里不会写的坑。

这篇文章就按我实际落地时的顺序来写:先讲清楚这个系统解决什么问题,再给训练和界面集成的完整思路,最后补性能和打包经验。内容主要以通用实践为基础,原始材料里没有给出具体版本和参数时,我会用“以你的环境为准”来说明边界。

1. 先确认需求:是做一个课堂演示,还是要真的在工地上用

很多人看到“抽烟检测系统”第一反应是:这不就是目标检测加一个界面吗?思路没错,但需求不同,技术方案差别很大。

如果只是课程设计、毕业设计或者公司内部技术验证,那核心目标是“能跑通、能演示、能截图写报告”。这种情况下,模型精度差一点可以接受,界面只要能上传图片和视频、显示出检测框就算完成。

但如果是打算放到工地、厂区、食堂走廊这类真实场景里长期跑,那就完全是另一回事。你需要考虑摄像头流接入、识别延迟、误报率、日志留存、报警联动,甚至还要处理多人同时吸烟、远处小目标、逆光环境、夜间红外画面等复杂情况。这两个方向对数据集、模型选型和界面架构的要求完全不同。

我给你的建议是:先确定你的验收标准是什么。老师或者领导问你要“能跑通的系统”,那按演示版做,别过度设计;如果对方说“要能在监控室连续跑一周”,那就必须把稳定性、日志和报警机制放在第一位。

对大多数读者来说,第一版建议按演示系统来做,但要给后续扩展留好接口。具体来说就是:模型文件单独放一个目录,检测逻辑写成独立模块,界面只负责调用和展示。这样就算后面换模型、加摄像头,也不需要重写界面。

2. YOLOv8 训练前的准备工作:数据集、环境、硬件评估

2.1 数据集是整条链路里最重要的一环

抽烟检测的数据集不像 COCO 那样容易获得,因为“人吸烟”这个动作带有很强的场景属性。很多公开数据集里的图片是摆拍或特写,跟监控摄像头拍到的画面差异很大。

如果你手头没有现成数据,可以按以下方式准备:

  • 搜集公开的吸烟检测数据集,注意看图片分辨率、场景类型和标注格式。
  • 如果数据不够,自己去拍摄或截图。手机拍、监控截图、视频抽帧都可以。
  • 标注工具推荐 LabelImg 或 LabelStudio,导出 YOLO 格式。
  • 至少要覆盖这些类别:person(人)、smoke(烟/烟雾)、cigarette(香烟),具体看你希望检测到什么粒度。

这里有个重要判断:检测“吸烟”和检测“烟”是两种难度。烟本身很小,在监控画面里可能只有几个像素,很容易漏检;而“人手持烟”这个状态往往更稳定。更稳妥的方案是先检测人,再检测人附近的烟,用逻辑判断是否在吸烟。很多论文和开源项目也是这么做的。

2.2 环境安装与版本匹配

YOLOv8 的训练环境以 PyTorch 为主,PyQt5 负责界面,两者本身不冲突,但 Python 版本和依赖包版本会影响你是否能顺利装完。

常见组合可以参考:

软件推荐版本说明
Python3.8 到 3.10PyQt5 和 PyTorch 都有较好的兼容性
PyTorch2.x 或 1.13以官网和你本机 CUDA 版本为准
CUDA11.8 或 12.1用在 NVIDIA 显卡上训练
ultralytics8.xYOLOv8 的官方包
PyQt55.15.x较稳定

如果你用的是 GTX 1660 Ti 这类老显卡,建议先查一下你的 CUDA 驱动支持哪个版本的 PyTorch,不要一上来就装最新版。显存不够时,可以把batch-size调到 4 或 2,也可以把输入分辨率从 640 降到 512。原始材料里有“GTX1660ti跑yolov8”这个热搜词,说明不少人都在关心低显存能不能训练。答案是能,但要把训练轮数和图像尺寸控制好,训练时间会明显变长。

2.3 数据标注格式转换

YOLOv8 训练需要的是 txt 格式的标签文件,每行内容为:

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

其中坐标值是相对于图片宽高的比例,取值在 0 到 1 之间。标注软件一般会帮你转好,但如果拿到的是 XML 或 JSON 格式,需要写脚本转换。网上有很多现成脚本,核心就是读取标注框坐标,再除以图片宽高。

训练前最好写一个检查脚本,确认每张图片都有对应的 txt 文件,且标签文件里没有超过图片边界的坐标。不要跳过这一步,我在实际项目中碰过不少次“训练能跑,但 mAP 一直很低”,最后发现是标注坐标越界。

3. 训练 YOLOv8 模型:参数、命令、验证与改进

3.1 准备数据集配置文件

YOLOv8 训练需要一份 YAML 配置文件,指定训练集和验证集路径,以及类别名称。例如:

path: D:/smoke_detect/data train: images/train val: images/val nc: 2 names: ['person', 'smoke']

如果你的标注里还有 cigarette 类别,就把nc改成 3,并在 names 里对应添加。注意类别顺序一定要和标注文件里的编号一致,否则模型训练出来会乱。

3.2 训练命令与参数说明

在终端进入项目目录,执行:

yolo detect train data=smoke.yaml model=yolov8s.pt epochs=100 batch=8 imgsz=640

这里有几个参数值得细说:

  • model=yolov8s.pt表示加载 YOLOv8s 预训练权重作为起点。如果你机器性能一般,选yolov8n.pt更轻量,但精度会略低。
  • epochs不是越大越好。常见经验是:小数据集 50 到 100 轮足够;如果训练到后面损失不再下降,再增加轮数意义不大。
  • batch受显存限制。显存报错时,优先调小 batch,再考虑调小 imgsz。
  • imgsz训练分辨率。640 是默认值,检测小目标时可以考虑 960,但显存占用和耗时都会上升。

训练过程中要盯两个东西:一是 loss 曲线是否在下降,二是 val 集的 mAP50 和 mAP50-95 是否在上升。不要只看 loss,loss 下降不代表检测效果好。

3.3 模型验证

训练完以后,项目目录下会生成runs/detect/train文件夹,里面有训练曲线、验证图片和最佳权重best.pt。用下面命令验证效果:

yolo detect predict model=runs/detect/train/weights/best.pt source=test.jpg

预测结果会保存到runs/detect/predict下。这时候你需要人工检查检测框位置准不准、有没有误报、小目标有没有漏掉。模型好不好,靠肉眼看图比看指标更直观。

3.4 精度不够时怎么改进

如果你的模型在测试集上表现一般,先别急着换模型结构。按这个顺序排查:

  1. 数据集是否足够大。低于 1000 张图,可以考虑做数据增强或补充样本。
  2. 标注是否准确。标注框过大或过小都会影响学习效果。
  3. 类别是否容易混淆。烟和烟雾、香烟和笔这类相似物体需要更多标注。
  4. 检测头是否适合小目标。YOLOv8 本身有小目标检测能力,但如果你的目标只有十几个像素,可以尝试在 YAML 配置里调整 anchor 或添加 P2 检测层,也可以参考网上“YOLOv8小目标检测头”的改进思路。
  5. 注意力机制。像“引入多头注意力机制MHSA”这类改进,通常在特定数据集上有效,但会增加计算量,建议在 baseline 跑通后再尝试。

记住:先保证 baseline 能稳定复现,再谈改进。很多人一上来就叠注意力、换网络结构,结果模型是跑起来了,但精度提升不明显的案例我见过不少。

4. PyQt5 界面集成:线程、信号槽、实时显示

4.1 界面功能怎么规划

一个抽烟检测系统的界面,至少要包含以下模块:

  • 图片检测:选择图片,显示检测结果。
  • 视频检测:选择视频文件,逐帧检测并播放结果。
  • 实时摄像头检测:打开摄像头,实时识别。
  • 参数区:置信度阈值、IOU 阈值。
  • 日志区:显示每次检测的时间、目标数量、耗时。
  • 模型加载状态:显示当前加载的权重路径。

第一次写界面时,先别把功能做全。我的经验是:先跑通“图片检测 + 日志输出”,再扩展视频和摄像头。视频和摄像头本质上都是“取帧 -> 检测 -> 显示”的循环,区别只在于取帧来源。

4.2 线程处理是重点中的重点

很多人用 PyQt5 做检测系统,遇到最典型的问题是:点击“开始检测”后,界面直接卡死。

原因是检测过程是耗时操作,如果你把它直接放在 GUI 线程里执行,界面就会失去响应。正确做法是用QThreadQTimer把视频流读取、模型推理和界面刷新拆开。

最简单的方案是自定义一个继承自QThread的检测线程:

class DetectThread(QThread): frame_signal = pyqtSignal(QImage) log_signal = pyqtSignal(str) def __init__(self): super().__init__() self.model = YOLO("best.pt") self.running = True self.source = 0 # 0 表示摄像头 def run(self): cap = cv2.VideoCapture(self.source) while self.running: ret, frame = cap.read() if not ret: break results = self.model(frame, conf=0.5) annotated_frame = results[0].plot() # 转换为 QImage,发信号到主界面显示 self.frame_signal.emit(self.cv2qimage(annotated_frame)) cap.release() def stop(self): self.running = False

界面主线程通过接收到frame_signal来更新 QLabel 显示,通过log_signal更新日志。这样界面就不会卡死。

注意:不要在run()里直接修改界面控件,所有界面更新都用信号槽来完成。这是 PyQt5 开发的铁律。

4.3 视频播放的“伪实时”问题

检测系统跑视频文件时,很常见一个现象:画面播放速度比实际视频慢很多,甚至几秒才出一帧。这不是单纯代码效率问题,而是模型推理速度跟不上视频帧率。

处理方法有两种:

  • 跳过帧:比如每 2 帧或 3 帧检测一次,中间帧直接显示原图。
  • 降低分辨率:把输入帧缩小到 640x640 以内再做检测,显示时再放大回去。

如果是摄像头实时检测,还要考虑视频缓冲。OpenCV 默认会积压摄像头帧,导致你画面看到的是几秒前的旧画面。可以设置:

cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)

这行代码能减少延迟,在实时监控场景里很有用。

4.4 下拉框闪退和超链接问题

原始热搜词里有“pyqt5 下拉框闪退”和“pyqt5 文本框超链接点击后执行自定义操作”,这两个问题都很典型。

下拉框闪退,常见原因是QComboBox的 item 数据里有特殊字符,或者在某些 PyQt5 5.15.x 版本下样式表冲突。解决办法是不要自定义复杂样式表,使用默认样式测试;如果仍然闪退,检查 Python 环境和 PyQt5 是否多个版本混乱,建议在干净虚拟环境重装。

超链接点击执行自定义操作,可以用QTextBrowserQLabelsetOpenExternalLinks(False),然后通过anchorClicked信号绑定自己的函数。这属于界面小技巧,但如果你要在日志区输出带颜色的链接文本,这个功能很实用。

5. 性能优化和部署:低配置也能跑,但要有取舍

5.1 单条任务跑的稳,再谈批量处理

很多人在开发阶段只跑一条视频,觉得没问题就结束了。但一旦你想把这个系统用于真实场景,就要考虑批量任务、连续运行和失败重试。这里面最容易忽略的是:

  • 输出命名冲突。连续处理多张图片时,如果输出文件都叫result.jpg,后来的会覆盖先前的。
  • 视频文件损坏或格式不支持。建议在代码里加 try-except,检测失败的帧或视频要跳过或记录。
  • 日志输出。每一帧检测到的数量、耗时和置信度都要有时间戳,方便以后排查。
  • 资源释放。摄像头长期打开不释放,内存会持续上涨。

我更建议的做法是:先写一个不依赖界面的命令行脚本,把图片文件夹、视频文件夹和输出目录规划好,跑通批量任务后,再让界面调用同一个检测函数。这样既方便测试,也方便以后做服务化接口。

5.2 CPU 推理的边界

如果你电脑没有 NVIDIA 显卡,YOLOv8 也能在 CPU 上跑推理,但速度会慢很多。以 YOLOv8n 为例,CPU 上单帧 640x640 大概需要 100 到 300 毫秒左右(具体和 CPU 性能有关),人眼看起来就是 3 到 10 帧每秒。如果换成 YOLOv8s 或更大模型,幀率会进一步下降。

对于 CPU 环境,有几个优化方向:

  • 使用model.predict(source, half=True)不会生效,因为 CPU 不支持半精度。可以忽略。
  • 使用 OpenCV 的cv2.dnn转换 ONNX 模型推理,有时比 PyTorch 快一点,但通用性差一些。
  • 降低检测分辨率。model.predict(frame, imgsz=480)会减少计算量。
  • 换用 YOLOv8n 或 YOLOv8n-seg,轻量版在低配机器上体验差异很大。

如果你要在嵌入式设备(比如 RK3588)上跑,思路更不一样。RK3588 的 NPU 需要把模型转换成 RKNN 格式,转换过程中有些算子可能不支持,需要做算子和精度验证。原始热搜词里也有“rk3588部署yolov8”,说明这是一个常见的部署方向。我的建议是:先在本机确认检测效果,再考虑交叉编译和部署,否则调试成本会反复叠加。

5.3 ONNX 转换和跨平台思路

如果你想脱离 Python 环境运行,或者把模型接入 C++/C# 程序,把 YOLOv8 导出成 ONNX 是一种常见做法。命令如下:

yolo export model=best.pt format=onnx opset=12

导出后用onnxruntime在 Python 里做推理,可以脱离 PyTorch。速度快一些,部署也更方便。

但要注意:

  • ONNX 导出后,有些后处理逻辑(如 NMS)需要自己实现,ultralytics 的 Python 包已经封装好了,但如果你要接入 PyQt5 之外的框架,需要额外处理。
  • 模型导出后可能存在精度下降,建议导出后跑一批测试图片对比结果。
  • 如果你要用 GPU 版本的 onnxruntime,需要额外安装onnxruntime-gpu,版本和 CUDA 需要匹配。

如果只是做一个本地 GUI 系统,直接用 ultralytics 包就够了,没必要为了“看起来专业”强行导出 ONNX。

6. 开发中常见的报错和排查思路

6.1 报错不一定是模型问题,先排查环境和数据

我遇到过很多次“代码换一台电脑就报错”的情况。刚开始我会去查模型结构和推理逻辑,后来发现 80% 的问题出在环境依赖上。

下面是几个高频问题的排查顺序:

现象排查方向备注
启动即报错ModuleNotFoundError检查依赖是否安装齐全,特别是 PyQt5、ultralytics、opencv-python在虚拟环境里重新安装
模型加载报错检查权重路径、ultralytics 版本是否兼容不同版本之间权重文件可能有差异
摄像头打开失败检查摄像头编号、权限、是否被其他程序占用了摄像头Windows 上摄像头编号通常从 0 开始
视频卡顿或延迟高看推理耗时和显示耗时,优先对推理部分做耗时统计不要一开始就改界面逻辑
检测结果没有框检查置信度阈值是否过高,检查输入图片是否过大导致缩放异常可以先把阈值调到 0.1 测试

6.2 日志是排查问题的第一工具

写检测系统时,最好从一开始就加入日志输出。日志内容至少包括:

[2025-01-15 10:23:45] 加载模型完成: best.pt [2025-01-15 10:23:45] 开始处理视频: demo.mp4 [2025-01-15 10:23:46] 帧 120: 检测到 1 个目标, 耗时 45ms [2025-01-15 10:24:01] 视频处理完成, 总帧数 1200, 平均耗时 50ms

这些日志不仅帮你验证功能是否正常,也方便以后接入消息通知或数据库。如果系统在真实环境运行,日志留存是必须的,不然出了问题没有依据。

6.3 界面和模型解耦,是以后扩展的基础

现在很多项目会宣传“多模态检测识别”“基于视觉检测的深度学习模型构建”,听起来很复杂,但落地时核心还是模型、数据、界面、存储四层。如果一开始就把模型和界面写得耦合在一起,后续换模型、加功能都会动到界面代码,风险很高。

一个更稳妥的目录结构是:

smoke_detect_system/ ├── models/ # 存放训练好的权重文件 │ └── best.pt ├── ui/ # 界面代码 │ ├── main_window.py │ └── detect_thread.py ├── core/ # 检测逻辑,不依赖界面 │ ├── detector.py │ └── video_processor.py ├── data/ # 输入输出数据 │ ├── input/ │ └── output/ ├── logs/ # 日志目录 ├── requirements.txt └── main.py

detector.py里只负责模型加载和推理,返回标注后的图像和检测结果列表;video_processor.py负责读视频、循环调detector、控制帧率;main_window.py只负责按钮事件和信号槽。这样分工清晰,以后加摄像头、加数据库、加 Web 接口都很方便。

7. 几个容易被忽略,但很影响体验的细节

7.1 阈值调节的实时性

很多检测系统把置信度阈值写死在代码里,用户不能调。但不同场景下阈值需求差异很大:室内光线好,0.5 可能够用;室外逆光时,识别结果置信度普遍偏低,需要下调到 0.35 左右。

界面设计时,用QSlider绑定置信度参数,并让检测线程实时读取阈值,是提升系统可用性的关键。不要在每次滑动滑块后重新加载模型,只需要让线程在下一帧推理时使用新阈值即可。

7.2 结果保存和报警

如果你做的检测系统要用于安全监督,检测到吸烟行为后需要截图保存,并触发报警或记录到表格。保存图片的命名最好带上时间戳和检测目标数,比如:

20250115_102345_box1_conf0.82.jpg

这样方便以后统计和回查。报警可以先用界面弹窗或声音提示,更高级的可以接企业微信机器人或短信接口。这部分因场景而异,但一定要做记录,否则“检测到了”和“提醒到了”是两回事。

7.3 关于“多模态”和“注意力机制改进”的建议

网上很多项目会提到“引入多头注意力机制MHSA”“多模态检测识别数据集”等改进方向。如果你是为了学习,可以跟读论文和代码;但如果你是为了交付一个抽烟检测系统,我建议先把 baseline 跑通,再考虑改进。原因很简单:

  • 注意力机制通常会增加参数量和计算量,你的显卡可能扛不住。
  • 改进效果和数据集高度相关,在公开数据集上有效不代表在你的烟头数据集上有效。
  • 训练时间会大幅增加,调试成本也更高。

先拿到稳定可运行的 v1 版本,再在 v2 里做改进,是比较推荐的节奏。

8. 打包和交付:让别人也能双击运行

8.1 PyInstaller 打包的注意事项

开发完成后,如果要把系统给没有 Python 环境的同事用,需要用 PyInstaller 打包成 exe(Windows)。

打包命令示例:

pyinstaller -w -F main.py --hidden-import=ultralytics --hidden-import=PyQt5

有几个坑非常常见:

  • -w表示不显示命令行窗口,但这样出错时看不到输出,建议调试阶段先去掉-w
  • 模型文件 best.pt 不会被自动打包进去,需要单独放一个目录,然后用路径访问。可以通过sys._MEIPASS处理临时路径,也可以直接把模型放在 exe 同级目录下。
  • PyQt5 有些插件文件(比如platforms/qwindows.dll)会被 PyInstaller 自动处理,但如果你用了非标准控件或样式,要检查是否缺 DLL。
  • 打包以后 exe 体积会比较大,一般 100MB 起步,属于正常现象,不必太过纠结。

8.2 给用户的最小使用说明

系统交付时,建议附一个简单的 README 或运行说明,至少包括:

  • 模型文件放在哪里。
  • Python 版本和依赖怎么安装。
  • 第一次启动要修改哪些路径。
  • 检测阈值默认值是多少,如何在界面上调整。
  • 日志文件在哪里,出现问题时发哪部分日志。

这些细节看起来琐碎,但在实际使用中特别重要。很多系统“开发的时候一切正常,一交付就各种莫名其妙的问题”,绝大多数是路径不对、目录没有权限、模型文件缺失导致。

9. 最后留几个我会优先看的点

如果你准备动手做这个系统,或者在已有代码上改,建议按下面的顺序检查一遍:

  1. 数据集标注格式是否正确,图片和 txt 文件是否一一对应。这一步最基础,也最容易出错。
  2. 训练配置里类别数量和你标注的类别总数是否一致。
  3. 训练完成后,用best.pt在测试视频上验证,不要只看验证集指标。
  4. 界面加载模型时,确认模型路径、置信度阈值、输出目录都是可配置的,不要写死。
  5. 摄像头实时检测时,确认帧率和延迟是否可接受,不要打开摄像头后界面假死。
  6. 打包时确认权重文件是否已经放入正确目录,在另外一台机器上测试过再交付。

这类“深度学习模型 + 桌面界面”的项目,真正验证功力的地方不在于模型多高级,而在于能不能稳定运行、能不能方便维护、能不能解决实际场景里的具体问题。先把单条图片检测做稳,再把视频和摄像头接起来,最后再考虑批量化和打包,这个顺序能帮你少走很多弯路。

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

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

立即咨询