
简介图像中烟雾检测是基于MATLAB实现的完整可运行项目面向图像处理初学者、安全监控与火灾预警相关研发人员。项目围绕烟雾识别核心任务通过颜色特征、边缘检测、纹理分析及机器学习等方法演示从图像预处理、特征提取到区域分割与结果评估的完整流程帮助读者快速理解并上手烟雾检测算法。资源包整体仅1KB共1个文件为可直接运行的.m脚本适合用作课程设计或算法验证基础。目前已有3245人学习。通过运行脚本可观察烟雾区域标定效果结合代码理解Canny边缘检测、颜色空间转换、Gabor/LBP纹理分析等具体实现思路为后续在不同场景下扩展检测方案提供可修改的代码起点。 做图像烟雾检测这个项目最初的动机其实很朴素火灾发生时烟雾往往比明火早出现几十秒甚至几分钟如果能提前把这些烟雾抓住就能给疏散和灭火抢出宝贵时间。但真上手才发现烟雾检测远没有“找个人、找辆车”那么简单——烟这个东西半透明、没有固定形状、边缘模糊颜色从白到灰到黑都有背景稍微复杂一点就分不清到底是烟、是雾还是单纯的云。这篇文章把我从数据准备、模型选型、训练调参一直到边缘端部署的完整过程记录下来包含我踩过的坑和一些常规文档里不会写的工程经验给同样想做烟雾检测或者类似弱纹理目标检测的朋友一个参考。1. 项目背景与核心难点1.1 为什么烟雾检测比火焰检测更棘手很多人觉得烟雾检测就是“找白色物体”实际完全不是这么回事。烟雾是半透明介质它没有稳定的边缘轮廓颜色会随着光照、背景、燃烧物种类发生剧烈变化。白天逆光下的白烟和黑夜灯光下的灰烟在图像上几乎是两种形态。更麻烦的是火灾初期的烟雾往往只占画面很小一块区域可能只有十几个像素在监控画面里跟远处的云、近处的蒸汽几乎没有区别。从视觉特征上看烟雾的纹理很弱没有火焰那种鲜明的颜色和跳变边缘也没有固定形状深度学习模型能抓到的判别性特征本身就少。另一个难点是高度相似物太多云、雾、霾、蒸汽、厨房油烟、烟囱排放甚至白色墙面反光都可能被模型误判成烟雾。我在项目初期就被云狠狠坑过——第一版模型在测试集上mAP不低一到户外场景就把天空中的静止云层全报成烟雾报警响到运维直接要求关停系统。1.2 项目需求的真实约束做检测项目技术指标和工程约束永远是两回事。烟雾检测对实时性要求很高监控摄像头普遍25帧左右算法端到端延迟不能明显拖后腿否则预警就失去意义。硬件平台也往往不是满血GPU服务器很多时候要部署到边缘盒子或者摄像头附近的嵌入式设备上算力有限这就直接决定了模型不能选得太重。更关键的是误报容忍度极低。火灾报警系统的特点是“狼来了”效应如果一天误报十几次运维人员会逐渐麻木最后真出事也不当回事整个系统就废了。所以烟雾检测这个任务真正要优化的核心指标不是简单的AP高一点而是在“可接受误报率”前提下把召回率顶上去。这个约束贯穿了后面所有的数据配比、模型选择和部署策略建议大家做类似项目时先把这个前提想清楚。2. 技术路线选型从传统方法到深度学习2.1 传统视觉方案的局限开始动手之前我花了两周时间把传统视觉方案过了一遍确认它们确实扛不住真实场景。帧差法和背景建模先被淘汰烟雾在连续帧间变化很慢背景模型更新参数稍微调快烟雾就被当背景吃掉了调慢又会在光照变化和树叶晃动时疯狂误报。颜色阈值法也只对实验室里单一背景下的白烟有效真实环境的烟雾颜色随光照变化固定阈值根本守不住。纹理特征方案我也试过用LBP或GLCM配合分类器去识别烟雾粗糙度在某些静态图上能到80%多准确率但输入分辨率稍微降低、烟雾区域稍微变小性能就崩。这个结果其实符合预期传统方法本质上是靠人工设计特征而烟雾的视觉特征恰恰是“变化多端、纹理模糊”人工特征很难覆盖全。所以那段验证让我死心塌地走向深度学习同时保留了运动区域检测作为预处理手段只用于缩小候选区域不承担最终判断。2.2 深度学习方案怎么选深度学习方案大致有三条路图像分类、目标检测、语义分割。分类网络最简单但只回答“图里有没有烟”给不出位置信息监控场景里联动摄像头、喷淋系统都需要坐标所以不能直接用。语义分割能给出精确轮廓但标注成本高、推理速度慢对边缘部署不友好。目标检测恰好是性价比最高的方案输出位置框工程链路成熟能直接嵌入到现有监控系统里。目标检测框架里我选了YOLO系列作为基线没有用Faster R-CNN或更重的模型。原因很实际YOLO单阶段推理速度快、部署生态完善TensortRT和各家NPU工具链对YOLO都有现成支持烟雾检测大部分部署场景是边缘设备实时性和工具链成熟度比极限精度更重要。至于带时序的ConvLSTM、SlowFast这类视频模型我也评估过它们确实能利用连续帧的运动信息来抑制静态误报但训练复杂度、数据要求和工程成本都不低对早期轻微烟雾的提升却未必明显。最后我的策略是首版先把单帧检测跑通时序问题用工程手段多帧确认解决不急着上视频模型。这个决定在后面部署时证明非常明智。3. 数据集构建与预处理3.1 数据来源与标注规范数据是整个项目的基石这块我花的时间比模型调参还多。数据来源分三块公开的火灾烟雾数据集自己录制的烟饼和烟雾发生器场景还有合成数据。合成数据不是简单的贴图而是把真实烟雾素材抠出来按不同的光照、背景、透明度叠加到真实场景图上可以快速扩充小目标样本但要注意合成比例别太高否则模型会对贴图纹理过拟合。标注规范是个容易被忽视的细节。烟雾的半透明特性使得边缘很难界定我最终定的规则是标注框比目视可见的烟雾区域稍微外扩一点把边缘模糊的过渡区也包进来。原因是网络真正能学到的判别特征分布在烟雾主体的半透明纹理上框得太紧反而让模型去学边缘切割效果不好。另外负样本库要单独建云、雾、霾、蒸汽、厨房油烟、烟囱废气、灯光光晕都要大量收。负样本和正样本的比例我控制在1.5比1到2比1之间这个比例偏低容易误报偏高则会让模型过度保守把真烟也滤掉。3.2 预处理和数据增强策略预处理阶段除了常规的归一化和随机翻转我加了三个对烟雾特别有用的增强。一是随机HSV扰动模拟不同光照条件下的烟雾颜色变化二是mixup和随机擦除强迫模型不要过度依赖整块的白色区域特征三是多尺度训练因为烟雾的尺度变化极大同一套参数既要在近景大烟团上准又要在远景小烟点上不丢。还有一个针对烟雾的核心经验单纯做单帧增强是不够的因为静态云和真烟在单帧画面里经常几乎一样区别只在于运动。我的做法是在数据端把“连续帧中的动态局部区域”单独裁剪出来作为增强样本让模型在训练时能接触到更多动态纹理线索而不是只对着静止的天空、云层做判断。这个操作不改变模型输入的形态但能明显降低后续多帧确认机制的压力。另外对小目标我会把高分辨率图像切成重叠patch再做推理虽然耗时翻倍但对远处小烟团的召回率提升非常显著。4. 模型训练与调优4.1 基线模型与参数配置我用的基线是YOLOv5s输入分辨率640乘640。没有直接沿用COCO预训练锚框而是用k-means在自有数据集上重新聚类了anchor因为烟雾目标的形状比例和常见物体差异挺大默认anchor会造成回归收敛慢。训练配置方面batch size开到32初始学习率0.01配合cosine退火和3个epoch的warmup总训练轮数150到200轮数据集规模在5万到10万张之间收敛速度很快。关于分辨率的取舍这里有个实际的权衡。测试过1280输入小目标召回确实提高但边缘端推理速度直接掉一半以上得不偿失。如果你的烟雾检测场景小目标问题特别严重我建议优先用切patch或多尺度训练来妥协而不是盲目上高分分辨率。模型参数量方面也反复试过从YOLOv5n到YOLOv5m都跑了一圈最后在准确率和部署FPS之间折中选了s。代码层面其实改动很小YOLOv5本身工程化做得不错主要精力还是要放在数据和训练策略上。4.2 训练中的调优与踩坑记录训练过程踩了三个大坑每一个都值得单独说。第一个是mAP高但误报多问题出在负样本比例太低。第一版训练集负样本只占不到20%测试出来mAP有0.85一到现场就把云和雾全报出来。后来把负样本补到60%以上误报才明显下降。这说明评估指标一定要结合场景离线mAP并不能反映真实误报风险。第二个坑是小目标几乎检不到。排查发现标注框边长小于32像素的样本占了将近一半早期YOLO对小目标本就吃力这个数据分布直接把召回率拖垮。解决办法有三个方向同时上提高输入分辨率、开启多尺度训练、在neck部分增加一个浅层小目标检测头。改完之后远处小烟团的召回率从不到50%提到了70%以上。第三个坑是验证集loss振荡。查了很久才发现原因是同一视频场景的连续帧被随机切到了训练集和验证集两边场景严重重叠模型等于在背答案。后来按视频序列切分而不是按帧切分问题立刻消失。这个坑特别隐蔽分享出来希望后来者别重蹈覆辙。损失函数方面我保留了YOLOv5默认的BCE加CIoU只适当调高了分类损失的权重因为烟雾检测的主要矛盾是误报多分类损失权重高一点模型会更倾向于“不确定就不报”。5. 评估、部署与常见问题排查5.1 评估指标怎么定才靠谱离线评估阶段我同时看mAP0.5、mAP0.5:0.95和召回率但心里真正认的指标是在固定误报率下能达到多少召回率。具体做法是把报警节奏换算成时间维度假设一个监控点上每天最多容忍一次误报那对应的置信度阈值就能通过长期视频回放测出来然后再看这个阈值下的召回率。这个“场景化指标”比单纯追求mAP高几个点有意义得多。而衡量错误也有优先级区分。把真烟漏掉后果是致命的把云误报成烟虽然烦人但不会酿成大祸。所以我给召回率设置了更高的权重在模型收敛后用验证集统计各置信度阈值下的P/R曲线最后选择了偏保守的阈值——宁可置信度要求高一点也不要漏报。另外测速也提个醒一定要在目标硬件上按真实输入分辨率测不能拿GPU浮点算力估算边缘端实测的FPS才是有效指标。5.2 边缘端部署优化部署流程是PyTorch权重转ONNX再转TensorRT用FP16推理。YOLOv5s在Jetson Orin Nano上FP16大约能跑到40到60FPS基本满足实时监控需求。如果部署到NPU平台流程类似但要把预处理算子尽量塞进模型里减少host和设备之间的数据搬运。INT8量化这里要特别谨慎。烟雾是弱纹理目标INT8量化带来的精度损失比普通目标更明显。我的做法是先把FP16版本上线跑稳定再做INT8尝试用少量真实场景校准集验证AP下降在3个点以内才考虑采用。实测结果是有些平台INT8省内存很明显但精度掉得厉害最后建议稳妥的团队可以先FP16上线后续再优化。5.3 典型误报场景与排查把项目过程中最常遇到的几个问题整理成一张表方便排查场景现象排查方向云和雾天气静止云层被当成烟雾加入多帧确认机制连续N帧同位置有目标才报警蒸汽与厨房油烟频繁误报扩充对应负样本或按区域配置检测规则夜景灯光眩光灯光周围光晕被误检提高置信度阈值限制检测区域远处小烟团漏报切patch推理、多尺度检测、增大输入分辨率多帧确认机制是我在实际项目里加的最有效的工程兜底策略单帧检测结果出来以后并不直接触发报警而是要求同一位置连续3到5帧都检测到目标才确认。这种机制直接过滤掉了云、飞鸟、灯光闪烁带来的一次性噪声虽然会损失大概一两秒的响应时间但对烟雾这种缓慢变化的早期信号完全够用。另外我还专门做了一个本地回归测试集每次模型更新都要把历史现场视频完整跑一遍防止新版本在修掉一类误报的同时又引入新的误报。最后分享一点体会。做烟雾检测和做通用目标检测的思维方式很不一样通用检测追求的是“准”烟雾检测追求的是“稳”误报率必须压到运维能接受的程度同时不能漏掉真实火情。我见过太多测试集表现很好、一到现场就崩的项目大多不是模型结构不够先进而是数据和场景没对齐。所以我会把大半精力花在数据配比、负样本扩充和现场回归测试上这一块带来的收益比换任何模型结构都明显。如果你也想做类似项目第一个版本别急着上花哨的视频时序网络或Transformer老老实实把“单帧检测多帧确认”这条基线跑通拿到真实的误报数据再决定下一步优化方向能少走很多弯路。本文还有配套的精品资源点击获取