简介面向安防视频监控、算法工程落地与计算机视觉学习场景LNTON羚通烟火识别与烟雾检测工具提供图片、RTSP实时流及mp4文件三类输入下的烟火检测能力并可将告警结果以叠框图片形式输出适合需要快速验证烟火识别效果或搭建演示原型的开发者与项目人员使用。压缩包共874个文件约324.75MB包含大量jpg样本与告警图、15个dll运行库、4个exe工具程序以及bat批处理脚本、mp4演示视频、模型权重文件、sh与lib依赖、txt说明和pdf使用文档兼顾样本查看、程序运行与部署参考。已有243人学习资源内附使用文档和工具便于读者了解检测流程、观察叠框输出并复现实验也为后续接入实际监控流或二次开发提供可操作的参考。1. 烟火识别工具的真相最难的不是找火焰而是让告警图值得复核烟火识别工具真正的难点往往不在把火焰框出来而在烟雾识别、烟火分析和烟雾分析共用一条证据链时烟火算法如何处理单帧歧义。一个反直觉的现象是白天测试很顺夜里车灯、晚霞、蒸汽一进来告警图片立刻刷屏复核的人比不装工具还累。这类工具要解决的不是“证明画面里一定有火”而是把图片、RTSP 实时流、mp4 文件里可疑的烟火候选稳定摘出来输出带叠框的告警图片让人能快速判断该不该去现场。单帧颜色阈值能给出一个框却给不出可信度检测网络能给出置信度却不一定处理得好烟雾的扩散和遮挡。真正值得搞懂的是证据怎么叠加、帧节奏怎么控制、告警怎么去重这三件事决定了工具是帮手还是噪音源。2. 火焰与烟雾的视觉证据为什么单帧阈值总在夜间翻车烟火检测的第一层直觉是“火焰高亮、偏红黄烟雾灰白、偏淡”于是很多实现会从颜色空间阈值起步。问题在于晚霞、车灯、反光玻璃、蒸汽、扬尘都能在单帧里凑出类似的高亮区域单帧阈值没有时间维度的证据阈值调低就误报调高就漏报。更合理的做法是把火焰和烟雾拆成两类证据火焰看颜色、亮度、闪烁和面积增长烟雾看低饱和度、灰度纹理、扩散和背景扰动再用多帧确认把偶发像素压下去。2.1 火焰候选区域颜色空间与运动证据的交叉验证火焰候选区域常见的实现思路是先做颜色空间筛选再做运动区域交叉。RGB 对光照变化太敏感常见做法转到 HSV 或 YCrCbHSV 里看 Hue 是否落在红橙黄区间、Saturation 是否足够高、Value 是否偏亮YCrCb 里看 Cr 分量是否偏红、Cb 分量是否偏低。只靠颜色还不够火焰通常伴随运动于是再用背景差分或帧间差分得到运动掩码把颜色掩码和运动掩码做交集候选区域会干净很多。可验证的细节在于参数不是拍脑袋写死而是跟着场景走。白天室外场景里火焰的高亮区域容易被阳光反射干扰Saturation 下限可以适当提高Value 下限不要压得太低夜间场景里车灯是强高亮但颜色偏白Hue 区间要收窄同时增加“闪烁频率”证据。火焰在连续帧里会出现亮度跳动和边缘抖动常见做法是在 8 到 15 帧的滑窗里统计候选区域的亮度方差和面积变化率方差过低或面积几乎不变的区域更像是静止光源而不是火焰。候选区域还要做形态学清理。颜色掩码容易出现碎点先做开运算去掉孤立像素再做闭运算把断裂区域连起来最后按面积、长宽比、圆形度过滤。面积太小的候选不值得进入分类器面积突然占满画面的候选更可能是镜头被遮挡或强光过曝。这里的血泪经验是不要用一个固定面积阈值打天下按画面分辨率做归一化按场景做分组配置否则换一个摄像头就要重新调参。证据类型火焰常见表现烟雾常见表现单帧是否可靠颜色红橙黄高饱和高亮低饱和灰白、偏淡火焰中等烟雾低运动边缘抖动、亮度闪烁缓慢扩散、整体漂移都需要多帧形状面积增长、边缘不规则边缘模糊、区域逐渐变大单帧容易误判干扰源车灯、反光、晚霞蒸汽、扬尘、雾夜间和逆光更明显这张表不是为了给出万能阈值而是说明为什么火焰和烟雾不能共用一套判据。火焰的证据偏“强颜色加动态闪烁”烟雾的证据偏“弱颜色加缓慢扩散”单帧阈值在火焰上还能勉强工作在烟雾上几乎必然翻车。2.2 烟雾识别为什么更依赖时序低饱和、扩散与背景扰动烟雾识别比火焰识别更玄学原因在于烟雾的视觉特征太弱。烟雾在画面里往往是低饱和度、中高亮度、边缘模糊的一大片区域颜色和背景墙体、天空、路面拉不开差距风吹过来烟雾形状还在变单帧里它可能只是一个灰白色块和蒸汽、扬尘、雾几乎没有区别。所以烟雾检测不能只看颜色必须看“它怎么动、怎么长、怎么遮”。常见的实现思路是背景建模加多帧证据。先用滑动平均或混合高斯维护背景当前帧和背景做差分得到前景区域再在前景区域里找低饱和、低边缘密度、面积逐渐增长的连通域。烟雾的扩散性可以用面积增长率描述连续多帧里连通域面积缓慢增大但边缘对比度下降这种“变大且变虚”的模式比单帧颜色更有区分度。光流也能用但计算量高实时流里通常只在小候选区域上算稀疏光流避免整帧光流拖垮吞吐。背景扰动是烟雾检测的主要干扰源。树影晃动、水面反光、镜头自动曝光变化都会让背景差分出现大片前景如果直接把这些区域送进烟雾分类误报会非常密集。更稳妥的做法是加一个“背景稳定度”门槛统计候选区域周围背景的帧间差异差异过大时暂时不告警或者降低置信度。这个门槛听起来保守但在实时流里非常必要因为一次镜头抖动就能制造出几十个假前景。烟雾识别的输出也不应该只有一个二分类标签。更有用的输出是“候选框 置信度 持续时间 面积变化率”后两个量能帮助复核人员判断这是飘过的蒸汽还是持续扩散的烟雾。工具把告警图片叠框输出框的位置和大小本身就是证据的一部分如果框只覆盖一小块高亮像素复核人员很难判断周围是不是有烟所以烟雾框通常会比火焰框略微外扩保留上下文。2.3 从手工特征到检测网络bbox 与 score 的输出约定手工特征适合做候选生成但最终判定通常要交给检测网络或轻量分类网络。检测器的输出约定要统一每个候选包含类别、边界框坐标、置信度坐标必须是原图坐标系置信度必须和阈值可比。常见实现里检测器在固定输入尺寸上推理比如把原图缩放并填充到方形输入输出框再反变换回原图如果这一步没对齐后面叠框就会偏。检测网络的价值在于它能把颜色、纹理、形状联合起来学减少手工规则的组合爆炸。但检测网络不是万能药单帧检测器对烟雾仍然容易把云、雾、蒸汽判成烟所以后处理必须有时序确认。一个可验证的约定是检测器只负责给出候选和分数时序模块负责决定要不要告警。这样调参时能分开看问题是检测器漏了还是时序确认压得太狠。置信度阈值和 IOU 阈值要按场景分组。白天室外烟雾淡置信度阈值可以略低靠多帧确认压误报夜间火焰干扰多置信度阈值可以提高同时增加闪烁证据。IOU 阈值用于非极大值抑制重叠框太多时保留分数最高的但烟雾区域往往是大框套小框IOU 阈值过高会留下多个重复框叠框图片会显得很乱。常见做法是对火焰用稍高的 IOU 阈值对烟雾用稍低的 IOU 阈值再做一次合并让告警图更干净。3. 统一输入管线图片、RTSP 实时流与 mp4 为什么不能共用帧节奏图片、RTSP 实时流、mp4 文件看起来都是“读帧、检测、画框”但帧节奏完全不同。图片是单帧请求要求低延迟返回RTSP 实时流是连续到达的解码速度跟不上就会积压积压久了延迟越滚越大mp4 是离线文件可以按时间轴采样但不能因为检测慢就把整个文件读进内存。如果三者在代码里共用一套“每帧都检测、每帧都保存”的逻辑实时流会延迟爆炸mp4 会跑得极慢图片路径反而被拖进不必要的循环。3.1 图片检测单帧路径的预处理与批处理边界图片检测是最短的路径读取图片、记录原始宽高、按检测器输入要求缩放和填充、推理、反变换坐标、叠框、保存告警图。关键点是保留原始尺寸和填充参数不能在缩放后直接画框。图片路径适合做批量检测但批处理边界要清楚一批图片可以共享模型加载和预热不能共享坐标变换参数每张图的缩放比例和填充偏移都可能不同混在一起反变换一定出错。图片路径还要处理 EXIF 方向。手机拍摄的图片可能带有旋转信息解码库读出来的像素方向和图库显示方向不一致检测框画上去就会旋转 90 度。常见做法是在读取后统一按 EXIF 方向校正再进入检测流程并把校正后的图作为告警图底图。这个细节在实时流里不明显在图片检测里却经常翻车尤其是现场人员用手机拍完直接上传的场景。批处理大小要跟显存和内存匹配。图片尺寸差异大时按固定 batch 拼图会浪费大量填充区域检测器在小目标上表现变差更稳妥的是按分辨率分桶同一桶内做批处理桶与桶之间串行。图片检测的延迟要求没有实时流那么硬但也不能让单张大图把队列堵死设置单图超时和队列上限超时后返回失败而不是无限等待。3.2 RTSP 实时流抽帧、缓冲与重连的时序设计RTSP 实时流的核心矛盾是“解码速度”和“检测速度”不匹配。摄像头按固定帧率推流检测器如果每帧都跑处理不过来时缓冲区会越堆越多画面延迟从几秒滚到几十秒告警图片的时间戳和真实时间对不上。常见做法是抽帧检测按时间间隔采样比如每 500 毫秒取一帧或者按帧序号每 N 帧取一帧抽帧后仍然要持续读取并丢弃旧帧避免解码缓冲积压。抽帧策略要跟场景匹配。火焰蔓延快抽帧间隔可以短一些烟雾扩散慢抽帧间隔可以长一些但多帧确认需要连续证据抽得太稀会让时序模块凑不够帧。更合理的做法是双节奏低分辨率快筛按较短间隔跑发现候选后再对候选区域做高分辨率确认。这样既控制算力又不丢掉短时火焰。RTSP 还要处理重连和断流。网络抖动、摄像头重启、鉴权过期都会让流中断如果代码里读到空帧就退出工具会悄无声息地停掉。常见实现是记录最后成功解码的时间超过阈值后触发重连重连失败按退避间隔重试同时把重连事件写进日志。重连后不要立刻告警先丢弃若干帧让解码器稳定否则花屏帧会被检测成奇怪的大框。def process_source(source, cfg): # source 可以是图片路径、RTSP 地址或 mp4 路径 if source.is_image: frame decoder.read_image(source) return detect_and_draw(frame, cfg) stream decoder.open_video(source) last_alarm {} last_ok_ts now() while True: frame, ts stream.read() if frame is None: # 实时流断流时重连离线文件读到结尾则退出 if source.is_live and cfg.reconnect: stream decoder.reconnect(source) continue break last_ok_ts now() # 按时间间隔抽帧避免实时流缓冲区积压 if not should_sample(ts, cfg.sample_interval): continue result detect_and_draw(frame, cfg) # 多帧确认通过后才进入告警冷却判断 if result.need_alarm and not in_cooldown(result.key, last_alarm, cfg.cooldown): save_alarm_image(result.image) last_alarm[result.key] ts这段伪代码把三类输入收进同一个入口但分支里保留了不同的帧节奏。sample_interval控制抽帧间隔实时流和 mp4 可以取不同值reconnect只对实时流生效离线文件读到结尾就退出cooldown按告警键做冷却避免同一团烟连续刷图。result.key不是简单的类别名通常由空间位置和类别联合生成否则画面里两个不同位置的火焰会互相压制告警。提示实时流里读到空帧不一定代表流结束先看最后成功解码时间再决定重连还是退出否则一个短暂抖动就会让工具停掉。3.3 mp4 离线文件按时间轴解码与告警去重mp4 文件检测的目标不是实时性而是完整性和可复现性。离线文件可以按时间轴采样也可以逐帧检测但逐帧检测加逐帧保存告警图会让磁盘迅速膨胀。更常见的做法是按固定时间间隔采样检测比如每秒取 2 到 5 帧告警后把告警时间戳附近的原始帧也保留下来方便复核前后文。离线检测的告警去重要比实时流更积极。同一段烟雾在视频里持续几十秒如果每个采样帧都输出一张告警图结果就是几百张几乎一样的图片。常见做法是按时间窗合并同一空间区域内、时间间隔小于合并窗口的告警合并成一条记录只保留置信度最高或面积最大的一帧作为代表图同时记录起止时间。这样输出的是“事件”而不是“帧列表”复核人员看起来轻松很多。mp4 还要注意可变帧率和时间戳跳变。有些文件的时间戳不是严格递增按时间采样时可能重复取到同一帧或跳过一段。稳妥的做法是同时记录解码帧序号和时间戳采样时以时间戳为主、帧序号为辅发现时间戳回退时重置采样状态。离线文件检测适合做回归验证固定一批视频跑完后对比告警数量、告警时间点和叠框位置能快速发现参数改动带来的副作用。4. 告警叠框与误报抑制从检测框到可复核图片的最后一公里检测器输出的是坐标和分数复核人员看到的是叠框图片。中间隔着坐标反变换、阈值过滤、多帧确认、告警冷却、图片编码这几道工序任何一道偷懒告警图都会变得不可信。框偏了复核人员会怀疑检测器同一团烟刷出几十张图复核人员会直接忽略告警置信度很低也输出告警工具就变成了狼来了。告警叠框不是画个矩形那么简单它是把模型输出翻译成人工可判断证据的最后一公里。4.1 坐标映射缩放、填充与原始帧的对齐检测器通常要求固定输入尺寸原图要先缩放再填充到方形画布推理输出的框是在填充画布坐标系里的。反变换要先把填充偏移减掉再除以缩放比例最后裁剪到原图边界。漏掉填充偏移框会整体偏移漏掉裁剪框会画到画面外缩放比例用错框会大小不对。这三个错误在图片检测里容易发现在实时流里因为画面一直在动反而容易被忽略。def unletterbox(box, scale, pad_x, pad_y, orig_w, orig_h): # box 为检测器输入画布坐标系下的 x1, y1, x2, y2 x1 (box[0] - pad_x) / scale y1 (box[1] - pad_y) / scale x2 (box[2] - pad_x) / scale y2 (box[3] - pad_y) / scale # 裁剪到原图边界避免叠框画到画面外 x1 max(0, min(x1, orig_w - 1)) y1 max(0, min(y1, orig_h - 1)) x2 max(0, min(x2, orig_w - 1)) y2 max(0, min(y2, orig_h - 1)) return int(x1), int(y1), int(x2), int(y2)scale是原图到检测器输入画布的缩放比例pad_x和pad_y是填充偏移orig_w和orig_h是原始帧宽高。反变换的顺序不能反先减填充再除缩放最后裁剪。如果原图是非方形填充偏移通常只出现在一个方向如果检测器输入不是方形缩放比例可能横纵不同这时要分别记录scale_x和scale_y不能用一个标量糊弄。坐标映射要做自检。最直接的办法是用一张带四角标记的测试图跑一遍检测流程看叠框是否落在标记上实时流里可以在画面四角贴虚拟标记定期检查映射是否漂移。另一个常见坑是叠框时用了缩放后的帧而不是原始帧框的坐标是对的但底图被缩过画出来仍然偏。告警图必须用原始帧画框或者在画框前把底图恢复到原始尺寸。4.2 置信度、IOU 与多帧确认告警不是检测结果的直接转发检测结果不能直接变成告警。单帧置信度高可能只是车灯恰好长得像火焰单帧置信度低也可能是烟雾刚开始扩散。更合理的链路是检测器输出候选先做置信度阈值过滤再做非极大值抑制合并重叠框然后进入多帧确认。多帧确认常见的有两种一种是 N-of-M 滑窗最近 M 帧里至少有 N 帧命中同一空间区域才告警另一种是分数累积连续命中会加分丢失会减分分数超过阈值才告警。N-of-M 的参数要跟抽帧间隔一起调。抽帧间隔 500 毫秒、M 取 10滑窗覆盖 5 秒适合烟雾这种慢变化目标火焰变化快M 可以取小一些N 也相应降低避免刚起火时被时序模块压住。空间区域匹配不能只看类别要看框的 IOU 或中心点距离IOU 阈值太低会把相邻的两个候选当成同一个太高又会让同一团烟因为框抖动而匹配不上。常见做法是用中心点距离加面积比做匹配比单纯 IOU 更适合形状变化大的烟雾。置信度阈值要分层。低阈值候选进入时序模块高阈值候选可以缩短确认窗口但不能跳过确认。告警图片上可以同时标注类别、置信度和确认帧数复核人员看到“烟雾 0.62连续 6 帧”比只看到“烟雾 0.62”更有判断依据。如果工具只输出一个框不输出分数和时序信息告警图片的信息量会少一半。4.3 告警冷却与去重同一团烟不该刷出一屏图片告警冷却是最容易被省略、也最容易导致工具不可用的一步。没有冷却同一团烟在连续帧里被反复检测到就会输出几十张几乎一样的告警图有了冷却同一空间区域在冷却窗口内只告警一次复核人员看到的是事件不是帧。冷却键通常由类别和空间网格联合生成比如把画面划分成网格同一网格内的同类告警在窗口内合并网格太细会导致同一团烟跨网格重复告警网格太粗会压制不同位置的告警。冷却窗口要跟场景风险匹配。烟雾扩散慢冷却窗口可以长一些比如 30 到 60 秒火焰蔓延快冷却窗口要短一些但不能短到每帧都告警。更稳妥的是两级冷却短窗口内同一位置只保留最高分告警图长窗口内同一事件只保留一条记录。这样既能抓住火焰的快速变化又不会让告警图刷屏。告警记录建议保留这些字段事件编号、类别、首告警时间、最后告警时间、代表框坐标、最高置信度、确认帧数、底图路径。复核人员按事件查看比按图片翻页高效得多。告警图片命名也要带时间戳和事件编号避免同一秒内多张图互相覆盖。冷却和去重不是为了让告警变少而是为了让每一条告警都值得看。字段作用常见坑事件编号串联同一团烟的多次命中用帧号当编号重跑后无法对照首告警时间判断响应延迟用文件写入时间不是检测时间代表框坐标叠框和复核定位存了缩放后坐标画框偏移确认帧数区分偶发误报和持续目标只存最高分不存时序证据底图路径保留原始帧用于复核只存叠框图无法重新画框5. 避坑与排查烟火检测工具最常见的五类翻车现场烟火检测工具在演示视频里往往表现不错一到现场就问题百出。原因不是算法一定差而是输入、帧节奏、坐标、告警策略这些工程环节没有对齐。下面五类翻车现场基本覆盖了从图片到实时流再到 mp4 的常见故障。每一条都按“现象、原因、解决”拆开方便对着日志和告警图排查。5.1 输入与解码类踩坑现象图片检测有框RTSP 实时流却一条告警都没有。原因通常不是模型不工作而是抽帧间隔太大火焰在画面里只出现很短时间采样帧刚好错过或者实时流时间戳回绕抽帧逻辑一直判定“不该取帧”。解决时先把抽帧间隔临时调小打印每帧的解码时间戳和采样标记确认采样函数真的取到了帧再用同一段视频的 mp4 版本跑离线检测对比告警时间点。如果离线能告警、实时不告警问题就在解码或抽帧不在检测器。现象叠框整体偏上或偏左框的大小看起来是对的。原因多半是坐标反变换漏了填充偏移或者填充偏移的正负号写反。图片路径里填充偏移只跟单张图有关实时流里每帧分辨率可能变化偏移量没有重新计算框就会漂。解决时用带四角标记的测试图跑完整流程量一下框和标记的像素偏差实时流里在画面四角画虚拟标记定期截图检查。坐标映射要独立成函数输入输出都打印一次别在画框代码里临时算。现象mp4 文件越跑越慢最后内存爆掉。原因通常是把检测结果和原始帧一起堆在内存里或者逐帧保存告警图没有上限。离线文件检测不需要保留所有帧按时间采样检测告警时只保存代表帧和前后少量上下文帧写图用异步队列队列满时丢弃低优先级图片而不是阻塞检测。解决时给队列设上限监控队列长度和内存占用发现持续增长就检查是不是有引用没释放。mp4 路径要按时间轴推进不要一次性读完整段视频。注意离线检测的告警图命名要带时间戳和事件编号同一秒内多张图互相覆盖复核时会对不上时间线。5.2 检测与告警类踩坑现象同一团烟连续输出几十张告警图复核人员直接忽略。原因是没有告警冷却或者冷却键只按类别生成导致不同位置的目标互相压制、同一目标反复触发。解决时把冷却键改成“类别 空间网格”同一网格内同类告警在窗口内只保留最高分代表图同时记录事件起止时间把多张图合并成一条事件。冷却窗口不能太短否则火焰快速变化时会被压住也不能太长否则不同位置的烟雾会被合并。调参时看告警事件数不要只看告警图片数。现象夜间车灯、路灯被识别成火焰白天蒸汽被识别成烟雾。原因是单帧颜色阈值和检测器置信度在夜间、逆光、低对比度场景下分布偏移训练时没覆盖够后处理也没有时序证据。解决时先分场景统计误报来源把夜间和白天分开配置阈值火焰增加闪烁频率和面积变化证据烟雾增加扩散性和背景稳定度门槛对高亮静止光源用“连续多帧位置几乎不变”作为压制条件。不要指望一个全局阈值解决所有场景分场景配置虽然麻烦但比反复调一个万能阈值可靠。这五类问题有个共同点现象看起来像算法不准根因却常常在输入节奏、坐标映射和告警策略。排查时先确认“帧有没有取到、框有没有画对、告警有没有被冷却压掉”再去看检测器。把这三步做成固定自检能省掉大量无效调参。6. 设计取舍与验证为什么“先告警再复核”比追求单帧全对更现实烟火检测工具的设计目标不是替代人而是把可疑片段稳定摘出来让复核成本降下来。这个目标决定了取舍召回优先于单帧精确率多帧确认优先于单帧高分告警冷却优先于“每帧都报”。单帧全对在真实场景里几乎不可达晚霞、车灯、蒸汽、扬尘总会有相似特征但把多帧证据、空间匹配和冷却策略做好误报可以从“刷屏”降到“可复核”漏报也能通过抽帧间隔和双节奏检测控制住。验证时不要只看模型指标要跑端到端场景。准备一小批覆盖白天、夜间、逆光、蒸汽、车灯、真实烟雾的视频和图片分别走图片、RTSP、mp4 三条路径统计告警召回、每小时误报数、首告警延迟、叠框对齐误差。对齐误差可以用四角标记图量延迟用告警时间戳减首帧命中时间。参数改动后固定跑一遍这套回放比凭感觉调阈值可靠得多。验证项怎么测看什么告警召回固定测试集回放真实烟火是否在可接受时间内告警误报密度统计每小时误报告警数夜间和蒸汽场景是否刷屏首告警延迟告警时间减首次命中时间实时流抽帧和确认窗口是否过长叠框对齐四角标记图对比坐标反变换和填充偏移是否正确从那以后我每次接入新的视频源都强制先跑一遍四角标定、抽帧回放和告警去重自检再谈模型阈值。这套烟火识别工具资源里图片、RTSP 实时流、mp4 三条输入路径和告警叠框输出正好对应这条验证链拿下来对照实现比自己从零拼管线省事得多。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?