首页 / 资讯中心 / 文章详情

烟雾明火烟火火灾数据集:VOC+YOLO双格式3000张实战指南

烟雾明火烟火火灾数据集:VOC+YOLO双格式3000张实战指南 ★ FEATURED ARTICLE
简介这份烟雾明火烟火火灾目标检测数据集面向计算机视觉方向的学习者与算法工程师适用于火灾预警、烟火识别等场景下的模型训练与验证。数据集共3007张jpg图片每张均配有对应的VOC格式xml标注文件与YOLO格式txt标注文件标注工具为labelImg采用矩形框方式标注类别分为fire与smoke两类其中fire框数5198、smoke框数1651总框数达6849类别分布清晰便于直接用于主流检测框架的训练与评估。压缩包为rar格式整体约299.85MB内含1999个xml文件与1个说明txt文件组织规整方便按需提取与转换。目前已有656人学习下载适合需要快速获取烟火标注数据、开展目标检测实验或课程设计的中高级读者参考使用。1. 烟雾明火烟火火灾数据集3000张VOCYOLO双格式到底能干什么你手头如果只有一堆标注好的火灾图片却不知道怎么喂给 YOLO或者拿到的压缩包里同时有 XML 和 TXT 两套标注不确定该用哪套、怎么切分、怎么防止训练出来只会认“火”不会认“烟”那这份 3000 张规模的烟雾明火烟火火灾目标检测数据集就是拿来解决这类落地问题的。它同时提供 Pascal VOC 的 XML 标注和 YOLO 的 TXT 标注意味着你不需要自己写转换脚本就能在两类主流框架之间切换。适合做园区消防通道监控、林区早期火点识别、储能电站烟火预警的算法工程师也适合刚入门目标检测、想拿一个真实场景数据集跑通训练和推理全流程的人。这一章先把“这份数据能解决什么、不能解决什么”说清楚后面几章再动手。2. 先搞懂 VOC 与 YOLO 双格式为什么同一批图要存两套标注2.1 VOC 的 XML 和 YOLO 的 TXT 到底差在哪Pascal VOC 格式用一张图对应一个 XML 文件里面记录图片尺寸、目标类别和边界框的左上角、右下角绝对坐标。YOLO 格式用一张图对应一个 TXT 文件每行是一个目标格式为类别索引 中心x 中心y 宽 高四个坐标全部除以图片宽高做归一化。两者最核心的差异是坐标系和归一化方式VOC 是绝对像素、左上右下YOLO 是归一化、中心宽高。很多新手直接把 XML 里的坐标塞进 YOLO 训练脚本结果 loss 不降、框全跑到图外就是没做这一步换算。这份数据集同时给了两套好处是你用 LabelImg 复查时看 XML 更直观用 YOLOv5/v8 训练时直接读 TXT 更省事。但要注意两套标注必须来自同一次标注结果否则会出现同一张图 XML 和 TXT 框不一致的“双标打架”问题。拿到压缩包后第一件事不是解压就训而是抽查 10 到 20 张确认 XML 和 TXT 的框能对上。2.2 类别定义与标注粒度烟、明火、烟火混合怎么分火灾场景里“烟”和“火”是两类视觉特征完全不同的目标。烟是半透明、边界模糊、颜色从白到黑都有明火是高亮、边缘锐利、颜色集中在红橙黄。如果标注时把烟和火合成一个“fire”类模型学到的特征会互相干扰早期烟雾检测召回率会明显偏低。常见做法是至少分smoke和fire两类有些项目还会加fire_smoke混合类或spark火星类。拿到数据集后先看类别文件。YOLO 格式通常有classes.txt或data.yaml里的names列表VOC 格式则要看 XML 里name标签出现了哪几种值。如果只有一类你要评估自己的场景是否真的只需要“有火/无火”二分类如果要做早期预警建议至少保留烟、火两类哪怕自己补标一部分。类别顺序在 YOLO 里是索引0对应names[0]一旦训练前改了顺序而没同步改 TXT模型会把烟认成火这种翻车在现场排查时非常难发现。2.3 3000 张的规模在目标检测里算什么水平3000 张在通用目标检测里不算大COCO、BDD100 都是十万级。但火灾烟火是垂直场景背景相对集中、目标类别少3000 张如果覆盖了白天、夜间、室内、室外、远距离、近距离、遮挡、逆光等条件是能训出可用模型的。关键不是数量是分布。你要做的是统计这 3000 张里有多少张只有烟、多少张只有火、多少张两者都有、多少张是负样本无目标。如果负样本比例低于 10%模型容易把云、雾、灯光误报成烟火这是消防场景最致命的假阳性。一个可操作的检查方法解压后统计 TXT 文件里非空行数和类别分布再随机抽 50 张看场景多样性。如果发现 80% 都是白天室外明火那这份数据更适合做“明火确认”而不是“早期烟雾预警”选型时要诚实面对。3. 从压缩包到可训练VOC 转 YOLO 与数据切分的完整操作3.1 解压后的目录该长什么样一份规范的 VOCYOLO 双格式数据集解压后常见结构是JPEGImages放图、Annotations放 XML、labels放 TXT外加classes.txt或data.yaml。但很多压缩包结构不统一可能图在一个文件夹、XML 在另一个、TXT 又在第三处。先别急着写脚本用下面命令把结构摸清楚# 查看解压后一级和二级目录确认图片、XML、TXT 各自位置 find ./fire_dataset -maxdepth 2 -type d | sort # 统计图片数量确认是否接近 3000 find ./fire_dataset -iname *.jpg -o -iname *.png | wc -l # 统计 XML 和 TXT 数量两者应和图片数基本一致 find ./fire_dataset -iname *.xml | wc -l find ./fire_dataset -iname *.txt | wc -l如果 TXT 数量远少于图片说明 YOLO 标注不完整需要自己从 XML 转如果 XML 和 TXT 都有但文件名对不上要以图片文件名为基准做一次对齐。这一步不做后面训练时会出现“找不到标签”的静默跳过你以为在训 3000 张实际只用了 1800 张。3.2 用 Python 把 VOC XML 转成 YOLO TXT即使数据集已经带了 TXT我也建议自己跑一遍转换脚本因为你需要理解坐标换算而且转换过程能顺便做类别映射和异常框过滤。下面脚本读取 XML输出归一化后的 TXTimport os import xml.etree.ElementTree as ET # 类别映射顺序必须和 data.yaml 里的 names 完全一致 classes [smoke, fire] # 输入输出路径按实际解压位置改 xml_dir ./fire_dataset/Annotations out_dir ./fire_dataset/labels_converted os.makedirs(out_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in classes: continue # 跳过未定义类别避免索引错位 cls_id classes.index(name) bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 裁剪到图像边界防止标注越界导致归一化后为负 xmin, ymin max(0, xmin), max(0, ymin) xmax, ymax min(w, xmax), min(h, ymax) if xmax xmin or ymax ymin: continue # 过滤无效框 cx (xmin xmax) / 2.0 / w cy (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) out_name os.path.splitext(xml_file)[0] .txt with open(os.path.join(out_dir, out_name), w) as f: f.write(\n.join(lines))逻辑说明classes列表顺序决定 TXT 里的类别索引必须和训练配置一致坐标裁剪和无效框过滤是防止标注人员手抖画出负宽高保留 6 位小数是 YOLO 官方脚本的习惯精度足够。参数上如果你的数据集类别是中文或大小写不一致要在name比较前统一转小写或做映射表否则会整类被跳过。3.3 切分训练集、验证集与负样本处理3000 张按 8:1:1 切训练 2400、验证 300、测试 300 是常见做法。但火灾场景要按场景切不能随机切否则同一段视频的相邻帧会同时出现在训练和验证里验证指标虚高。正确做法是先按视频源或时间段分组再在组间切分。下面脚本按文件名前缀分组后切分import os, random, shutil img_dir ./fire_dataset/JPEGImages lbl_dir ./fire_dataset/labels_converted out_root ./fire_dataset/split random.seed(42) # 按文件名前缀分组假设前缀代表不同视频源 groups {} for f in os.listdir(img_dir): if not f.lower().endswith((.jpg, .png)): continue prefix f.split(_)[0] groups.setdefault(prefix, []).append(f) group_keys list(groups.keys()) random.shuffle(group_keys) n len(group_keys) train_g group_keys[:int(n*0.8)] val_g group_keys[int(n*0.8):int(n*0.9)] test_g group_keys[int(n*0.9):] for split, gs in [(train, train_g), (val, val_g), (test, test_g)]: for sub in [images, labels]: os.makedirs(os.path.join(out_root, split, sub), exist_okTrue) for g in gs: for img in groups[g]: stem os.path.splitext(img)[0] shutil.copy(os.path.join(img_dir, img), os.path.join(out_root, split, images, img)) lbl stem .txt src_lbl os.path.join(lbl_dir, lbl) dst_lbl os.path.join(out_root, split, labels, lbl) if os.path.exists(src_lbl): shutil.copy(src_lbl, dst_lbl) else: open(dst_lbl, w).close() # 无目标图生成空标签作为负样本负样本处理是火灾检测的关键。空 TXT 文件在 YOLO 里就是负样本参与训练能显著降低误报。如果你的数据里没有负样本建议从相似场景有雾、有晚霞、有车灯里补 200 到 500 张无目标图空标签放入训练集。参数上random.seed(42)保证可复现分组前缀规则要按你实际文件名调整如果文件名没有统一前缀就按拍摄日期或文件夹名分组。4. 训练配置与参数YOLOv8 跑烟火检测的必调项4.1 data.yaml 怎么写才不出错YOLOv8 训练靠data.yaml找图和标签。路径写错是最常见的“训练启动即报错”原因。标准写法path: ./fire_dataset/split train: train/images val: val/images test: test/images nc: 2 names: [smoke, fire]path是根目录train等是相对路径。nc必须等于names长度且顺序和转换脚本里的classes完全一致。如果训练时提示No labels found先检查labels文件夹是否和images同级、TXT 文件名是否和图片名一致。YOLO 默认把图片路径里的images替换成labels找标签所以目录结构必须对称。4.2 输入尺寸、batch 与学习率的取舍火灾检测里小目标远处烟雾和大目标近处明火同时存在。输入尺寸imgsz设 640 是默认但如果你的场景以远距离早期烟雾为主建议提到 960 或 1280代价是显存和训练时间上升。batch 根据显存定8G 显存跑 640 可以到 16跑 1280 可能只能到 4。学习率用lr00.01起步如果 loss 震荡明显降到 0.001。训练轮数epochs建议 100 到 300配合patience50早停。一个血泪经验火灾数据类别不平衡时火多烟少不要直接开cos_lr或激进增强先把mosaic关掉试一轮。Mosaic 会把四张图拼一起烟雾这种低对比度目标拼完更容易和背景混在一起早期验证 mAP 可能虚低让你误以为模型不行。4.3 训练命令与关键监控指标yolo detect train \ data./fire_dataset/split/data.yaml \ modelyolov8n.pt \ imgsz960 \ epochs200 \ batch8 \ lr00.01 \ patience50 \ projectfire_runs \ nameexp1跑起来后重点看三个指标box_loss是否稳定下降、mAP50是否上升、precision和recall是否失衡。火灾场景宁可 recall 高一点漏报比误报后果更严重。如果 recall 长期低于 0.6检查标注是否漏标了大量烟雾如果 precision 低看验证集里误报的图多半是云、雾、灯光被认成烟。模型选型上yolov8n适合边缘设备yolov8m精度更高但推理慢园区摄像头实时预警一般 n 或 s 够用。5. 避坑与排查烟火检测训练中最容易翻车的 5 个点5.1 现象训练 loss 正常下降但验证 mAP 一直是 0原因通常是验证集标签路径不对或者验证集图片和标签没对上。YOLO 在验证时如果找不到标签会当作无目标处理mAP 自然为 0。解决手动打开val/labels看是否有 TXT文件名是否和val/images里图片一一对应TXT 内容是否非空。另一个可能是data.yaml里val路径写成了绝对路径但迁移后失效。5.2 现象模型把晚霞、路灯、黄色衣服认成火这是典型的假阳性根因是负样本不足或背景单一。解决补 200 到 500 张含晚霞、路灯、暖色灯光的无目标图作为负样本重新训练。同时检查标注里是否有把反光、灯光误标成 fire 的情况这种脏标注会直接教坏模型。增强上可以加hsv_h0.015、hsv_s0.7做颜色扰动让模型不依赖单一色调。5.3 现象烟雾漏检严重尤其远距离小烟雾原因一是输入尺寸太小烟雾在 640 下只剩几个像素二是烟雾标注框画得太紧只框了浓烟核心忽略了扩散边缘。解决把imgsz提到 960 或 1280复查标注烟雾框应包含可见烟羽整体训练时开scale0.5做多尺度增强。如果还不行考虑单独训一个烟雾检测模型和明火模型做级联。5.4 现象XML 和 TXT 框位置对不上可视化时框偏移原因是转换时用了错误的图片宽高或者 XML 里size和实际图片尺寸不一致。解决转换前用 PIL 读一次实际图片尺寸和 XML 里的width、height比对不一致时以实际图片为准。另外注意有些标注工具导出的 XML 坐标是 1-based转换时要减 1否则整体偏移一个像素小目标上很明显。5.5 现象训练到一半显存爆了或者速度突然变慢常见原因是imgsz或batch设太大或者数据加载线程workers开太多导致内存交换。解决先用batch4、workers2跑通再逐步加。如果用了 mosaic 增强最后 10 个 epoch 关掉close_mosaic10能稳定收敛。另外检查是否有损坏图片YOLO 遇到坏图会反复重试拖慢速度用PIL.Image.verify()批量扫一遍。6. 进阶技巧用验证集反查标注质量与模型边界训练完不是终点验证集的最大价值是反查标注质量。把预测结果和真实标签叠在同一张图上重点看三类图漏检的、误报的、框明显偏的。漏检图如果人眼也看不清烟说明数据本身太难考虑剔除或补光如果人眼能看到但模型没检出多半是标注漏标回去补标再训。误报图如果背景里有类似烟火的纹理把这些图加入负样本。框偏的图检查 XML 和 TXT 是否一致。一个具体操作用 YOLO 的val模式导出预测 TXT然后写个小脚本和真实 TXT 做 IoU 比对把 IoU 低于 0.3 的图筛出来人工看。这个习惯我坚持了很久每次都能揪出几十张脏标注重训后 mAP 能涨 3 到 5 个点。另一个技巧是拿模型去跑一段没参与训练的真实监控视频按帧看误报和漏报这比看验证集指标更接近落地效果。火灾检测没有后悔药模型上线前多花一天看 bad case比上线后天天被误报叫醒强得多。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站