烟火检测数据集VOC解析与YOLOv8训练避坑指南

发布时间:2026/10/27 18:31:42
烟火检测数据集VOC解析与YOLOv8训练避坑指南 简介这是一套面向目标检测与计算机视觉学习者的VOC格式烟火数据集专门用于烟雾和明火两类目标的检测模型训练与评估。资源包总大小约687.88MB包含6460张jpg原图和对应的6460个xml标注文件另附使用说明txt一份。数据集由labelImg工具完成矩形框标注标注类别为smoke和fire其中烟雾标注框7901个、明火标注框11066个每张xml均记录对应图片中的目标类别与边界框坐标便于直接解析训练。图像内容覆盖交通事故、森林火灾、建筑失火、柴木生火等多类烟雾场景以及蜡烛、柴火、奥运火炬等多种明火形态有助于增强模型在多样化环境下的适应能力与泛化效果。压缩包目录结构清晰jpg与xml一一对应可直接接入主流检测框架目前已有2559人学习使用适合需要进行烟火识别算法研究或相关项目开发的数据集需求方。1. 烟火检测数据集选型VOC 格式的 6460 张为什么是复现首选做烟火识别项目最磨人的往往不是模型结构而是数据集。我接过好几版网上流传的烟雾明火图要么缺标注要么类别写错要么标注坐标直接越界跑起来全是玄学问题。这份 [数据集][VOC][202206][重制版] 烟火数据集烟雾明火2类别数据集VOC-6460张是标准的 Pascal VOC 组织格式一共 6460 张标注图像覆盖烟雾、明火两个目标类别重制版重点是把标注质量和划分文件重新清理过一遍。它的价值在于通用。VOC 格式的 XML 标注几乎是目标检测的通用语言YOLO、SSD、Faster R-CNN、DETR 都能直接解析拿来当基线数据集非常合适。做消防通道监控、油烟检测、森林防火这类场景的从业者拿到手就能开始做模型验证。当然直接丢进训练脚本里还是会翻车。类不平衡、坐标越界、划分重叠、难样本被误删这些坑我在后面按踩坑记录一条条讲清楚照着做能少折腾好几天。2. 数据集结构与标注解析JPEGImages、Annotations 与 XML 字段拿到压缩包先别急着解压训练先把目录结构摸清楚。Pascal VOC 的目录约定很固定这个重制版沿用的是同一套规范只是把图像和标注重新整理过一遍。标准布局如下dataset/ ├── JPEGImages/ # 全部图像jpg 格式 ├── Annotations/ # 每张图像对应一个同名 XML 标注 └── ImageSets/ └── Main/ ├── train.txt # 训练集图像名列表 ├── val.txt # 验证集图像名列表 └── trainval.txt # 训练验证全集2.1 目录布局与数量核对先统计再动手JPEGImages 放原图Annotations 放 XML两者靠文件名一一对应。比如 JPEGImages/smoke_000123.jpg 一定对应 Annotations/smoke_000123.xml缺一个就说明数据集有残缺。ImageSets/Main 下的 txt 每行一个图像名不带扩展名用来划分训练集和验证集。我拿到任何数据集的第一件事就是做数量核对不会直接信说明文档。命令行三分钟能完成$ ls JPEGImages | wc -l 6460 $ ls Annotations | wc -l 6460 $ sort ImageSets/Main/train.txt | head -5 smoke_000001 smoke_000002 smoke_000120 fire_000004 fire_000011两个文件数对不上说明有图没标或有标没图这种数据集直接训练会出莫名其妙的漏检。还要对比 train.txt、val.txt 和 trainval.txt 的关系正规做法是 trainval 是全集train 和 val 互不重叠且并集等于 trainval。用 comm 命令可以快速查重叠$ comm -12 (sort ImageSets/Main/train.txt) (sort ImageSets/Main/val.txt)这条命令输出空才是正常有输出就说明划分重叠后面我会解释为什么这是个大坑。这一步属于花钱买防坑保险最多五分钟就能做完整套数据一致性检查。提示解压后如果 JPEGImages 和 Annotations 数量一致但 ImageSets 里的文件名在两张表里都找不到大概率是重制时换了命名前缀先用 basename 对照再跑脚本。2.2 XML 标注字段逐项解析理解框架怎么读你的数据VOC 的标注文件是 XML每个 object 节点就是一个目标框。随便打开一张标注annotation folderVOC2022/folder filenamesmoke_000123.jpg/filename size width1920/width height1080/height depth3/depth /size object namesmoke/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin231/xmin ymin84/ymin xmax1204/xmax ymax910/ymax /bndbox /object /annotationsize 节点里的 width 和 height 是归一化坐标的分母必须和 jpg 实际尺寸一致不一致时转 YOLO 格式坐标会整体漂移。object 节点里 name 是类别名bndbox 是框坐标。VOC 约定坐标从 1 开始计数xmin、ymin 最小值是 1 而不是 0xmax、ymax 最大可以等于图像宽高转换时要注意这一刀切在哪里。truncated 表示目标在图像边缘被截断difficult 表示这个目标本身模糊、难辨认。这两个字段在转换时是保留还是丢弃直接影响最终效果第 5 章我会专门讲 difficult 的处理。另外注意一个常见误读folder 和 filename 字段在解析时完全可以忽略训练框架只认文件实际路径不认 XML 里写的名字很多人在这里被带偏以为改 XML 里的 filename 就能换图。2.3 类别与数量分布先摸清家底再训练烟火数据集最容易出现类别不均衡。常规情况是烟雾样本多、明火样本少因为现实中烟雾出现频率远高于明火。动手前先统计一下每个类别的目标框总数import xml.etree.ElementTree as ET from pathlib import Path cnt {smoke: 0, fire: 0} both 0 empty 0 for xml_file in Path(Annotations).glob(*.xml): root ET.parse(str(xml_file)).getroot() names [obj.find(name).text for obj in root.iter(object)] if not names: empty 1 for n in names: cnt[n] cnt.get(n, 0) 1 if len(set(names)) 2: both 1 print(类别框数:, cnt) print(同时含烟雾明火的图:, both) print(无目标的图:, empty)这段脚本用 ElementTree 解析全部 XMLiter(object) 拿到所有目标节点再按 name 统计。empty 统计的是没有任何目标的背景图训练时背景图是用来压误检的数量太多或太少都会影响模型对负样本的判别。both 统计的是单张图同时出现两类目标的样本这类是烟火联动场景里最有价值的训练素材后面做难例挖掘时优先从这里下手。统计结果如果 smoke 是 fire 的三倍以上就要考虑类别加权或者后续做数据增强补足。我见过有人跳过这一步直接开训最后 mAP50 只有 0.6一查发现 fire 的 recall 才 0.3白白浪费几十个小时的显卡时间。这个统计脚本建议保存下来换数据集时改一下类别名就能复用。3. VOC 转 YOLO 与 COCO两条转换路线的脚本与参数细节3.1 为什么非要转格式训练框架只认自己的标注VOC 的 XML 虽然通用但现代训练框架都不直接吃 XML。YOLOv8 要的是每张图一个 txt 文件每行类别ID cx cy w h坐标全部归一化到 0~1MMDetection 和 Detectron2 更习惯 COCO 的单个 json 文件YOLOv5 的旧版本还要额外的 dataset.yaml 和数据目录约定。所以拿到 VOC 数据集的第一步是把它转成你要用的框架格式。转换脚本本身不难坑全在坐标约定和边界处理上。我自己拆过不下十个数据集VOC、COCO、KITTI、BDD 之间互相切最后总结出一条规律先搞清楚源格式的坐标原点是 0 还是 1再做转换否则差一个像素的偏移在 640 分辨率下看不出来到了 1280 训练时就开始掉点。这套切换流程同样适用于 COCO2017 结构的数据集原理是一模一样的。3.2 VOC 转 YOLO归一化坐标脚本与边界处理我一般用下面这段脚本做转换兼容 Python 3只用标准库不用额外依赖import xml.etree.ElementTree as ET from pathlib import Path CLASSES [smoke, fire] # 类别顺序就是类别 ID定下来就不能改 INPUT_DIR Path(Annotations) OUTPUT_DIR Path(labels) OUTPUT_DIR.mkdir(exist_okTrue) def convert(xml_path: Path) - None: root ET.parse(str(xml_path)).getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in CLASSES: continue if int(obj.find(difficult).text) 1: continue # 默认丢弃 difficult1 的难样本理由见第 5 章 box obj.find(bndbox) x1 max(float(box.find(xmin).text), 0) y1 max(float(box.find(ymin).text), 0) x2 min(float(box.find(xmax).text), img_w) y2 min(float(box.find(ymax).text), img_h) if x2 x1 or y2 y1: continue # 越界后框宽高为负直接跳过 x_center ((x1 x2) / 2) / img_w y_center ((y1 y2) / 2) / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h lines.append(f{CLASSES.index(name)} {x_center:.6f} f{y_center:.6f} {w:.6f} {h:.6f}) out OUTPUT_DIR / f{xml_path.stem}.txt out.write_text(\n.join(lines)) for xml_file in INPUT_DIR.glob(*.xml): convert(xml_file) print(转换完成输出目录:, OUTPUT_DIR)这里有三处参数要特别说明。第一CLASSES 列表的顺序决定了类别 IDsmoke 是 0、fire 是 1后面训练 yaml 里的 names 必须和这里完全一致顺序反了就是模型学到一半整个标签错位推理结果全乱。第二x1/y1/x2/y2 做了 clamp把越界的坐标拉回到图像范围内防止归一化后出现大于 1 的坐标导致 loss 异常。第三丢弃 difficult1 的框需要谨慎这个数据集如果 difficult 标注得比较松直接全丢会损失一批真实的难样本先按 5.3 的方法统计数量再决定。提示转换后检查一下标签文件总数。labels 目录下 txt 数量应该等于 Annotations 里 XML 数量减去空标注的数量对不上就回头查日志别急着开训练。3.3 转 COCO 的关键字段与组织方式如果要用 MMDetection 或 Detectron2就得转 COCO json。COCO 的核心是三个顶层字段categories、images、annotations。categories 记录类别 ID 和名称images 记录每张图的 id、文件名、宽高annotations 记录每个框的 bboxx, y, w, h左上角坐标、area、image_id、category_id。下面这个表把最容易出错的字段列出来COCO 字段来源常见错误bbox(xmin, ymin, xmax-xmin, ymax-ymin)误把 xmax/ymax 直接塞进去框会偏大area(xmax-xmin) * (ymax-ymin)不填或用宽高之积以外的算法image_id与 images 里的 id 对应漏掉或对不上训练时报 KeyErrorannotation id全 json 唯一自增从 0 重复coco eval 直接乱VOC 的 bndbox 是 xmin/ymin/xmax/ymaxCOCO 要的是 x/y/width/height转换时减一下就行很多人栽在忘了减上。area 字段在评估时用于大小目标分组如果和图实际面积对不上小目标那一档的 AP 会失真看起来 mAP 挺高实际落地时小目标全漏。转完 COCO 后建议用官方 pycocotools 的 loadRes 加载一次能通过说明 json 结构没问题这一步能挡住一半以上的低级错误。顺带一提很多做自动驾驶数据集转换的同事也踩过同样的坑COCO 的 annotation id 全局唯一这件事几乎每个手写转换脚本的人都会忘。4. 用 YOLOv8 跑通烟雾明火训练数据配置与超参调优4.1 数据 yaml 与目录准备转到 YOLO 格式之后把文件按训练目录约定摆好。ultralytics 的规则是 images 和 labels 分目录且文件名一一对应image 目录用 train/val 区分labels 目录结构要完全镜像smoke_fire/ ├── images/ │ ├── train/ # 约 80% 图像 │ └── val/ # 约 20% 图像 └── labels/ ├── train/ └── val/划分直接用第 2 章核对过的 train.txt、val.txt。我一般把官方划分当成默认值定死只在明显不均衡的时候手动重划。然后在数据集根目录放一个数据描述文件path: /data/smoke_fire # 数据集根目录绝对路径或相对路径 train: images/train val: images/val names: 0: smoke 1: firenames 的顺序必须和转换脚本里的 CLASSES 一致不能因为 fire 更重要就把它排到 0ID 一旦乱了模型训练出来就是废的。nc类别数不需要手写yaml 里有几个 names 就自动识别几个这也是最容易偷懒出错的地方——有人把 names 写成 1: smoke, 0: fire训练能启动但标签全反最后看 confuse matrix 才反应过来。4.2 训练命令与关键参数数据准备好后一条命令就能开训yolo detect train \ datasmoke_fire.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ patience20 \ workers4modelyolov8s.pt 是带 COCO 预训练权重的 s 版本烟火检测这种目标对比度强、结构不算复杂的任务s 级足够没必要上来就上 l 或 x先跑通流程再按需升级。imgsz 默认 640但明火很多是小目标640 下可能只有十几个像素有条件就上 1280。imgsz 改成 1280 后显存占用大约翻两倍batch 要从 16 降到 8显卡不够时先保证分辨率再保 batch分辨率对烟火小目标的影响远大于 batch size。patience20 是早停轮数20 个 epoch 内验证集 mAP 没提升就自动停省时间。workers 是数据加载线程数Windows 上设 0 最稳Linux 上 4~8 都行设太高会频繁报 DataLoader worker 崩溃。关于预训练权重有一点要提醒COCO 预训练模型没见过烟雾这种半透明、无锐利边缘的目标前几十个 epoch 的 loss 会掉得很慢这是正常的不是代码写错了。想加速收敛可以先用 3 个 epoch 的小跑测通流程再开正式训练这一步能避免你对着一个跑了一半才报错的命令干瞪眼。4.3 验证指标mAP、混淆矩阵与 PR 曲线训练结束后ultralytics 会在 runs/detect/train 下输出 results.csv。我用最简单的方式看最后一行的 mAPimport csv with open(runs/detect/train/results.csv) as f: rows list(csv.DictReader(f)) last rows[-1] print(mAP50:, last[metrics/mAP50(B)]) print(mAP50-95:, last[metrics/mAP50-95(B)])mAP50 是 IoU0.5 时的平均精度工业上常用来判断能不能用mAP50-95 对框的位置要求更苛刻学术报告偏爱用它。做烟火检测我主要看 mAP50定位要求是别把烟囱当烟、别把灯光当火框稍微差几个像素不致命。val_batch 预测图能直观看到漏检和误检但我更推荐看混淆矩阵。混淆矩阵在 runs/detect/train/confusion_matrix.png按行是真实类别按列是预测类别。对角线亮说明正常如果 fire 那一行大部分落到了 background就是明火小目标漏检严重对应第 5 章第 2 条的处理方法。PR 曲线则用来判断置信度阈值放在哪曲线右下角弯曲说明低置信度区间误检多部署时阈值就得往上抬。5. 烟火数据集避坑指南五条翻车记录与排查思路5.1 训练 loss 变 nan坐标越界与空标签现象训练跑十几个 batch 后 loss 直接变成 nan或者某张图反复报all labels empty。原因VOC 的坐标写成 (0, 0, 0, 0) 或者 xmax 超过图像宽度转 YOLO 时归一化坐标出现负数或大于 1另一类情况是某些 XML 里 object 节点存在但 bndbox 为空转换出的 txt 是空文件YOLO 对这种空标签图会直接跳过多了就影响 batch 统计。解决转换脚本里对 x,y,w,h 做 clamp 和x2x1 就跳过的防护这是第一道保险。第二道保险是数空标签文件labels 目录下大小为 0 的 txt 要单独列表确认是有意保留的背景图还是坏数据。$ find labels -name *.txt -size 0 | wc -l这个数字如果是几十且和 JPEGImages 里的纯背景图对得上可以留如果几百个就得回源头查 XML。我踩过一次训练到一半全崩查了两天才发现是某个批次下载的 XML 被截断bndbox 只剩了半个标签。5.2 明火几乎检不出来类别不均衡与输入尺寸现象训练完 mAP50 看着还行但 val_batch 图上火苗一个没框住或者 fire 的 recall 只有 0.2 左右。原因一个是数据不均衡烟雾框动辄占图面积的 40%明火框只有几十个像素模型天然倾向学大块灰白区域另一个是 imgsz 太小20 像素的火焰在 640 分辨率下被下采样到 5 个像素以内特征直接消失。解决先按 2.3 的统计确认 fire 框数量少了就做复制增强对含 fire 的图做随机裁剪放大、旋转、亮度扰动把 fire 样本量补到烟雾的一半以上。同时把 imgsz 升到 1280 重训mAP50 通常能涨 3~5 个点。这条是我做过烟火项目里性价比最高的改动没有之一。5.3 验证集虚高、实拍翻车difficult 样本被误删现象训练集上 mAP50 有 0.85拿到现场摄像头一测烟雾浓、遮挡多、目标糊的场景全部漏检。原因转换脚本把 difficult1 的框全丢了。这个重制版里部分难样本确实标了 difficult但它代表的是难不是错全删等于把最难学的样本从训练集里抹掉了模型学到的全是标准清晰目标泛化自然差。解决先统计 difficult1 的框数少于总数 10% 就保留只在训练时把难样本单独提出来做困难样本挖掘如果确实噪点多也要单独留出一部分做验证不能全删。从那以后我转换脚本默认不再硬删 difficult而是先打印数量再人工决策这个习惯救了我好几次。5.4 train 和 val 出现同一张图划分文件重叠现象训练 loss 收敛很快val mAP 冲到 0.9但换全新场景就崩分布完全不像这个量级。原因train.txt 和 val.txt 有重叠模型在训练时已经见过验证图验证失去意义这叫数据泄漏。常见于多批数据合并时文件名重排或者有人手动往 val 里补图之后没同步改 train。解决第 2 章的 comm 命令专门用来查这个。发现重叠就把重叠部分从 val 里剔除并保证 trainval 并集覆盖全集。最关键的是这个检查要写进每次换数据集的固定流程不能只看 loss 曲线曲线会骗人泄漏不会。5.5 烟雾大目标被 mosaic 切碎数据增强没调现象训练指标正常但推理时大片烟雾被切成好几个框或者漏掉半透明边缘。原因YOLOv8 默认开 mosaic把四张图拼成一张烟雾这种跨半张图的大目标在拼图时被切得只剩角落模型学到的目标形态是碎片自然学不会完整的烟柱。解决大目标占比高的数据集建议把 mosaic 关掉或降到 0.5 以下同时把 scale 增强范围收窄。ultralytics 里可以直接在训练命令加 mosaic0.0 参数或者改配置文件保留轻度翻转和亮度增强就够。烟雾检测和常规的目标检测不一样的地方就在这——别人怕目标太小烟火项目怕目标太大被增强切没。6. 进阶难例挖掘与 TTA 把烟火模型的漏检压到最低这算是我每次交付烟火检测模型前的固定收尾动作。基础训练跑完之后先用低置信度阈值把验证集整个过一遍yolo detect predict \ modelruns/detect/train/weights/best.pt \ sourceval_images \ conf0.05 \ save_txtTrue \ save_confTrueconf 设成 0.05 而不是默认的 0.25目的是逼模型把所有它其实有点想框但犹豫了的目标都吐出来。预测结果里每个 txt 带置信度按置信度升序排取最低的那批图人工看from pathlib import Path scores [] for txt in Path(runs/detect/predict/labels).glob(*.txt): for line in txt.read_text().splitlines(): parts line.split() scores.append((float(parts[-1]), txt.stem)) scores.sort() for conf, name in scores[:50]: print(f{name}: {conf:.3f})这批低置信度框只有两种命运确实是漏检的难例把它们连同原图抽出来混进训练集重新训一轮确实是不存在的误检则说明模型对这类背景还没建立负样本概念收集对应背景图补进去。我的一贯做法是难例优先背景图跟上两边都缺模型就不稳。另一个低成本手段是 TTA测试时增强火灾报警这类场景误报代价高宁可慢一点也要稳。ultralytics 预测时加 --augment 参数模型会对同一张图做多尺度推理再合并结果小目标召回率有明显提升。缺点是推理耗时翻几倍实时视频流慎用做离线审核很合适。烟火数据集的迭代终点不是 mAP 刷到多高而是难例库再也没有新增。我把每次线上漏检的截图都丢回难例池三个月后模型对逆光、薄雾、远处小火苗都稳了。从那以后我每次拿到新数据集都强制自己走一遍先数文件数再查拆分重叠然后统计类别分布最后才动训练命令。这一步省下来的调试时间远大于它花掉的那十分钟。这套流程同样适用于你手里的这份重制版烟火数据集——文件名记得是 [数据集][VOC][202206][重制版] 烟火数据集烟雾明火2类别数据集VOC-6460张下载后先对照第 2 章的目录结构核对一遍再开工。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询