
简介火焰目标检测数据集包含1553张人工精选标注的火焰图片并配套1853个jpg原始图像、1854个txt标签及1553个xml标注文件压缩包内共5260个文件整体大小约194MB。数据集面向计算机视觉开发者尤其适合训练YOLOv5等目标检测模型txt与xml标注中记录了火焰位置、边界框形状与尺寸等关键信息可直接用于模型训练、验证与性能评估。基于该数据集训练YOLOv5mAP.5达到0.953mAP.5:.95为0.679表明模型在火焰识别上具备较高精度与较强鲁棒性。资源目录按图像、标签、标注文档清晰分类便于快速加载和进行数据增强。目前已有4898人学习下载适合需要构建火灾预警、视频监控火焰识别等应用场景的开发者作为训练基础也可显著减少数据采集与标注成本、提升算法迭代效率。1. 火焰数据集标注好的标签不一定能直接喂给模型拿到一份“火焰数据集含标注好的标签”很多人的第一反应是解压、看两眼、直接跑train.py。实际做火灾检测项目时你会发现所谓的“标注好”只是这份数据不像网上某些裸图集需要你自己画框但标注格式、标签类别、框的质量、场景分布每一样都可能让训练直接翻车。我做过的几个火焰检测方案里真正决定模型能不能落地的从来不是网络结构选得有多新而是数据集在进训练管线之前有没有被认真审过一遍。这份数据集通常解决的是这样一个问题你不想从零收集火焰图片也不想花几周人工标注拿来就希望能训练一个能识别火焰的检测模型。但“能用”的门槛远高于“能打开”。这篇笔记我按自己做项目的流程把数据集的构成、标注格式、转换脚本、增强与去重、常见坑和最终验证一次讲透新手能照着做老手可以跳过前两节直接看避坑和验证部分。2. 火焰数据集的标签结构与格式VOC、YOLO、COCO 怎么选2.1 标注文件长什么样三种主流格式的区别“含标注好的标签”这个描述落到文件层面通常是三种情况之一Pascal VOC 的 XML 文件、YOLO 的 TXT 文件、COCO 的 JSON 文件。我做项目时拿到过三种混着的压缩包也拿到过只有其中一种的。先搞清楚你手里是哪一种再谈后续处理。VOC 格式每个图片对应一个同名 XML核心信息是object节点里的name和bndbox。bndbox给的是左上角和右下角的绝对像素坐标。YOLO 格式每个图片对应一个同名 TXT每行代表一个目标五个数字分别是class_id x_center y_center width height全部除以图片宽高做了归一化。COCO 格式是一个大 JSON包含images、annotations、categories三个数组框坐标是绝对像素的[x, y, width, height]。我一般拿到数据集第一件事不是看图片而是写个小脚本统计标注文件的格式和类别分布。原因很简单网上能下载到的火焰数据集经常标注混用比如一个包里有 XML 也有 TXT或者类别名一会儿叫fire一会儿叫flame。这种不一致如果不在最开始清掉后面每个环节都会被拖累。2.2 标签类别与标注字段解析统计脚本直接抄下面这个脚本能帮你快速摸清数据集的底细。它遍历目录下的所有标注文件统计类别数量、每类目标个数、以及是否有空标注文件。不需要装额外依赖Python 标准库就能跑。import os import glob from collections import Counter def parse_voc_label(xml_path): 解析VOC格式XML返回类别列表 import xml.etree.ElementTree as ET tree ET.parse(xml_path) root tree.getroot() classes [] for obj in root.iter(object): name obj.find(name).text.strip() classes.append(name) return classes def parse_yolo_label(txt_path): 解析YOLO格式TXT返回类别列表每行第一个数字是类别ID classes [] with open(txt_path, r, encodingutf-8) as f: for line in f: line line.strip() if not line: continue parts line.split() classes.append(int(parts[0])) return classes # 假设标注文件在 labels/ 目录 label_dir ./labels ext *.xml # 改成 *.txt 或 *.json 适配你的数据 all_classes [] empty_count 0 total_files 0 for label_file in glob.glob(os.path.join(label_dir, ext)): total_files 1 try: if ext *.xml: classes parse_voc_label(label_file) else: # *.txt classes parse_yolo_label(label_file) except Exception as e: print(f解析失败: {label_file} - {e}) continue if len(classes) 0: empty_count 1 all_classes.extend(classes) print(f标注文件总数: {total_files}) print(f空标注文件数: {empty_count}) print(类别分布:, Counter(all_classes))这个脚本的逻辑很简单先把所有标注文件都解析一遍统计出类别ID或类别名出现的次数空文件单独计数。火焰数据集里空标注文件是个常见问题特别是从视频抽帧得来的数据某些帧确实没有火焰但有些打包者会把空标注也保留下来。这类文件如果混进训练集会被模型当成负样本数量多了会明显拉低误报率表现。参数说明label_dir指你的标注目录ext决定解析格式。如果数据集是 COCO 的 JSON 格式我不建议自己写解析函数直接用pycocotools里的loadRes加载后再遍历比自己处理 JSON 嵌套结构稳得多。这个脚本跑完你就知道这份数据值的类别名是否统一、每个类别大概多少样本、空标注占比多高。我见过一份标着“火焰数据集”的包统计出来 40% 是空标注剩下的框里还有三分之一框的是路灯和落日——这种数据直接训练模型学出来的东西可想而知。2.3 标注质量评估框的准不准怎么看统计完类别分布下一步是看标注框质量。火焰检测里最典型的标注问题有两个框得过大把整片烟雾区域都框进去和框得过小只框了火焰中心边缘火苗全漏掉。这两种情况光看类别分布看不出来得实际框可视化。我习惯的做法是随机抽 50 张图把标注框画上去生成一张拼图然后人眼过一遍。这个步骤不要省哪怕数据集描述里写着“人工精确标注”。因为火焰本身是半透明、边缘不规则的物体不同标注员的尺度标准差异很大有的人倾向贴合火苗主体有的人会把余烬和高温区域全包进去。这种标准不一致会让模型在预测时框的尺度飘忽不定。可视化可以用 OpenCV 直接画矩形框代码很短但作用极大。如果你发现一批数据的框明显偏大后文会讲数据增强和超参调整时怎么针对性处理。另外要注意检查标注坐标有没有越界——比如框的x_min是负数、或者x_max大于图片宽度。这类脏数据会让 YOLO 训练时 loss 变成 NaN而且不是必现的可能跑了几百个 epoch 才炸一次排查起来非常痛苦。3. 标注格式转换把 VOC 转成 YOLO 的完整脚本与边界坑3.1 为什么通常要统一到 YOLO 格式做火焰检测现在主流还是 YOLO 系列而 YOLO 训练最方便的就是 TXT 格式的标注。如果你手里的火焰数据集是 VOC XML直接拿来做 YOLO 训练会非常别扭Ultralytics 虽然也支持 VOC但每个版本对 XML 的解析细节略有差异处理类别映射时不透明。我一般会写个脚本统一转成 YOLO TXT 格式再进训练管线这样后续换模型、换框架、做数据增强都只需要面对一种格式。3.2 VOC 转 YOLO 的转换脚本转换逻辑本身不复杂读取 XML 里的bndbox把绝对坐标转成归一化坐标再把类别名映射成类别 ID。但有几个细节不注意就会转出错位数据。import os import xml.etree.ElementTree as ET from glob import glob # 类别映射表根据你的数据集实际情况修改 class_mapping { fire: 0, smoke: 1 } def voc_to_yolo(xml_file, output_dir, img_width, img_height): tree ET.parse(xml_file) root tree.getroot() yolo_lines [] for obj in root.iter(object): name obj.find(name).text.strip() if name not in class_mapping: print(f跳过未知类别: {name} in {xml_file}) continue class_id class_mapping[name] bbox obj.find(bndbox) x_min float(bbox.find(xmin).text) y_min float(bbox.find(ymin).text) x_max float(bbox.find(xmax).text) y_max float(bbox.find(ymax).text) # 坐标越界修正把超出图片边界的部分裁掉 x_min max(0, min(x_min, img_width - 1)) y_min max(0, min(y_min, img_height - 1)) x_max max(0, min(x_max, img_width - 1)) y_max max(0, min(y_max, img_height - 1)) # 过滤掉宽度或高度为0的无效框 if x_max - x_min 0 or y_max - y_min 0: print(f跳过无效框: {xml_file}) continue # 转换为YOLO归一化坐标 x_center (x_min x_max) / 2.0 / img_width y_center (y_min y_max) / 2.0 / img_height width (x_max - x_min) / img_width height (y_max - y_min) / img_height yolo_lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) if yolo_lines: base_name os.path.splitext(os.path.basename(xml_file))[0] out_path os.path.join(output_dir, base_name .txt) with open(out_path, w, encodingutf-8) as f: f.write(\n.join(yolo_lines)) # 使用示例 voc_dir ./Annotations yolo_out ./labels_yolo img_width, img_height 1920, 1080 # 从你的图片实际尺寸读取不要写死 os.makedirs(yolo_out, exist_okTrue) for xml_path in glob(os.path.join(voc_dir, *.xml)): voc_to_yolo(xml_path, yolo_out, img_width, img_height)这段代码我加了三个关键处理。第一个是坐标越界修正有些 XML 里x_max会比图片宽度多几个像素不处理的话 YOLO 训练时锚框计算会出问题。第二个是无效框过滤宽或高为 0 的框必须跳过否则 loss 计算除零。第三个是未知类别的跳过逻辑你不希望一个拼写错误的类别名导致整个转换程序崩掉。参数说明class_mapping需要根据你数据集的实际情况改先跑第 2 章的统计脚本看类别名有哪些。img_width和img_height我在示例里写死了实际你最好从图片文件读取因为同一个数据集里尺寸不一致很常见用 PIL 的Image.open读一下宽高最保险。这里的核心是转换脚本本身不难难的是对脏数据的容忍策略。3.3 转换后的验证逆向检查转换完必须做逆向验证——从生成的 TXT 里读坐标画回图上跟原 XML 画的图对比。这一步不能省我吃过亏有一次类别映射写反了导致fire和smoke的标签全部对调模型训练出来看到火光报警烟雾、看到烟雾报警火灾线上线下跑了两周才发现问题。验证代码很简单随机抽几个转换后的 TXT把框画出来存成图片即可。这本质上是在确认转换过程中没有丢失信息、没有坐标错位、类别对应正确。做一次这个验证大概十分钟能避免后面所有环节基于错误标签白跑。验证通过后再做训练集划分顺序不要反。4. 数据集划分与预处理从原始压缩包到可训练的训练集/验证集4.1 划分比例与随机种子别让火焰数据泄漏标注格式统一之后下一步是把数据集分成训练集、验证集、测试集。火焰数据集有个特殊的坑如果数据是从视频抽帧来的相邻帧之间画面高度相似简单随机划分会导致训练集和验证集里出现几乎相同的图片验证指标虚高。我在项目里用的是按视频片段分组划分而不是按单张图片划分——每个视频的帧要么全进训练集要么全进验证集这样验证集才真正测出模型的泛化能力。划分策略适用场景优点缺点随机划分图片来源独立、互不相关简单快速视频帧数据会泄漏按视频文件分组划分数据来自监控视频抽帧验证指标真实需要额外记录来源信息按场景/时段划分数据包含白天/夜间/室内/室外能测场景泛化性需要额外标注场景属性划分后建议保存一份划分清单哪个文件进哪个集合不要每次重新随机划分。否则后续调参、换模型、加数据时训练集变化会让模型对比失去意义。我一般会把划分结果存成一个 CSV包含filename, split, source_video三列这样可复现、可审计。4.2 去重与清洗感知哈希去除重复帧处理视频抽帧数据时去重比划分更优先。重复帧会让模型对特定画面过拟合而且重复帧在训练集和验证集之间泄漏的话mAP 指标会虚高到骗自己。我用的是感知哈希去重对每张图计算一个 8x8 的灰度缩略图哈希值汉明距离小于等于 5 的判定为近似重复只保留一张。from PIL import Image import imagehash import os from collections import defaultdict def deduplicate_images(image_dir, threshold5): 用感知哈希去除近似重复图片返回保留的文件列表 hash_groups defaultdict(list) for img_name in os.listdir(image_dir): img_path os.path.join(image_dir, img_name) if not img_name.lower().endswith((.jpg, .jpeg, .png)): continue try: with Image.open(img_path) as img: img_hash imagehash.phash(img.convert(L).resize((8, 8))) except Exception as e: print(f图片读取失败: {img_path} - {e}) continue hash_groups[str(img_hash)].append(img_path) keep_files [] drop_files [] for h, paths in hash_groups.items(): if len(paths) 1: keep_files.extend(paths) else: # 保留文件名最短的通常代表更早的关键帧其余丢弃 paths.sort(keylambda p: len(os.path.basename(p))) keep_files.append(paths[0]) drop_files.extend(paths[1:]) return keep_files, drop_files keep, drop deduplicate_images(./images, threshold5) print(f保留 {len(keep)} 张丢弃 {len(drop)} 张)参数说明threshold在这里没有直接参与比较因为我把哈希值精确匹配做了分组。实际像素级完全相同的帧哈希一定相同但火焰场景里相邻帧有烟雾流动哈希会有细微差异。想放宽阈值的话需要改成两两比较汉明距离复杂度会从 O(n) 变成 O(n²)两万张图时计算量较大。我一般先用精确哈希去重再用差异阈值处理“几乎相同”的帧效果和效率平衡得比较好。去重后记得同步删除对应的标注文件否则训练时图片和标签对不上会报错。这一步坑很多下一章细讲。4.3 数据增强火焰检测特有的增强策略火焰检测和通用目标检测的增强策略不完全一样。火焰是半透明的、形状不规则的、亮度变化剧烈的目标常规的翻转和缩放帮助有限更有效的是以下几类增强。亮度扰动排第一。火焰在白天、黄昏、夜间三个时段的视觉差异极大而数据集里夜间样本通常偏少。在 HSV 空间对 V 通道做随机增强相当于模拟不同光照条件比单纯调 RGB 亮度更自然。对比度增强也很关键火焰在图像里往往是局部高亮区域提高对比度能强化这个特征。我习惯用albumentations库做增强它的RandomBrightnessContrast参数可以控制亮度和对比度单独调整。第二个推荐的增强是 MixUp 和 Cutout 的组合。火焰目标形状不规则且容易跟背景融在一起Cutout 随机遮挡一部分区域能强迫模型学习火焰的局部特征而不是整体模板。MixUp 把两张火焰图叠加混合可以让模型对半透明目标更鲁棒。不过注意 MixUp 的混合系数不要设太大火焰目标本来就小混合过头会变成一张糊图模型学不到有效特征。第三个容易被忽略的是尺度扰动。火焰数据集里大量样本是近景大火框占图片面积很大但实际部署场景经常要检测远处的小火苗所以训练时一定要做随机缩放。常见的做法是 Mosaic 增强把四张图拼成一张相当于变相增加了小目标样本。这个操作 YOLO 系训练框架自带开箱即用不需要手写。5. 火焰数据集实战避坑标注、采样、评估的 5 条踩坑记录5.1 标注框把大片烟雾框进去导致模型误检现象模型训练后看到白色水汽、汽车尾气就报警误报率高到没法上线。原因数据集的标注员把“可见烟雾区域”和“火焰本身”混在一起标框里大部分像素是烟雾不是火焰。模型学到的特征被烟雾主导。解决把标注里smoke类别和fire类别分开统计框的尺寸分布如果fire的框普遍宽高比异常大说明框到了大量烟雾区域。我当时的处理是写脚本按宽高比过滤掉明显异常的框比如宽度超过高度 3 倍的 fire 框再人工复核。如果数据集里有单独的smoke类最好把标注重新分成fire_only和smoke_only两个类别不要混标。5.2 视频抽帧数据在训练集和验证集之间泄漏现象训练时验证 mAP 高达 0.95但部署到真实场景后表现惨不忍睹几乎每帧都漏检。原因数据集划分时用了随机划分视频相邻帧同时出现在训练集和验证集里。模型在验证集上“背题”真实场景没见过类似画面就露馅。解决按视频片段分组划分数据。每一批连续帧属于同一个视频来源划分时以视频为最小单位。如果没有视频来源信息可以用感知哈希先聚类把近似重复的帧视为同一组再按组划分。5.3 图片 EXIF 旋转信息导致标注错位现象训练时 loss 正常下降但检测框整体偏移预测框位置偏左上或右下固定距离。原因部分手机拍摄的图片带有 EXIF 旋转信息cv2.imread读取时不会自动应用旋转但标注工具按旋转后的图像标的框。图片实际内容是横的标注坐标却是按竖的算的框自然全错了。解决在数据预处理阶段统一把所有图片转正并清除 EXIF 信息再做标注格式转换。不要依赖训练框架的自动处理YOLO 系框架有的不会修正 EXIF有的版本行为不一致主动处理最稳。5.4 类别分布极度不均衡火焰多烟雾少现象模型对火焰检测性能很好但烟雾几乎检不出来而实际场景里早期火灾往往先有烟雾。原因数据集中fire类别样本远多于smoke或者fire类目标每张图多个smoke类每张图只有一个。模型在训练中轻易优化大类忽略小类。解决不要只做整体数据的采样均衡要做目标级别框级别的均衡。可以用过采样策略复制烟雾样本图片连同标注进入训练集让每轮 epoch 里烟雾框的数量占比不低于 30%。如果使用 YOLO 训练可以调整loss里的类别权重参数或者给烟雾类单独设置更高的cls_pw。5.5 验证集里没有小目标导致模型近处灵敏远处全盲现象模型在近距离火焰检测非常灵敏但在监控画面远端出现小火苗时全部漏检而实际业务需求恰恰要覆盖远端。原因验证集或测试集的标注框面积普遍偏大小目标样本极少。模型的评估指标被大目标主导小目标性能差没被暴露。解决在验证集和测试集中额外按目标面积分层保证小目标面积占比在 0.3% 以下的样本数不低于整体 30%。评估时分别统计mAP0.5和mAP_s/mAP_mCOCO 风格的按面积分段指标。如果火焰数据集本身小目标就少优先通过 Mosaic 增强和复制小目标样本的方式补足而不是指望模型自己泛化出来。6. 训练后验证与模型可信度用交叉检验确认火焰检测的真实效果6.1 训练曲线解读怎么判断标签质量是否真的过关训练完成后先看 loss 曲线和 PR 曲线但不要只盯着最终 mAP 数值。火焰检测有个特点火焰目标的背景变化非常大室内白墙、室外天空、夜间黑背景都有如果训练集场景单一loss 曲线收敛后 validation loss 会缓慢走高这是过拟合的典型信号。我习惯的做法是把训练日志按 epoch 画两条曲线训练 loss 和验证 loss。两条线都下降且差距不大说明状态正常训练 loss 持续下降但验证 loss 在第 30 个 epoch 左右开始反弹说明模型开始背训练集了。这时候不要急着调早停先回去看数据增强是否已开启、增强强度是否足够。火焰检测里最常见的过拟合原因就是增强没开够尤其是亮度扰动和尺度扰动。6.2 交叉验证火焰数据集普遍不够干净单次划分不可信如果时间允许我会对火焰数据集做 K 折交叉验证而不是只训一次。因为火焰数据集的标注质量参差不齐单次划分的验证集可能碰巧比较简单mAP 虚高。K5 的交叉验证能帮你看到一个 mAP 的范围比如第一次 0.88第二次 0.79说明某一份数据里包含了不少标注质量差的样本或者难例模型性能波动大。这时候要回到第 2 章的统计脚本去看是不是某段视频、某个场景的数据整体有问题。交叉验证的另一个作用是检查标注是否存在系统性偏见。比如如果 5 折里夜间样本的那一折 mAP 明显低于其他折说明夜间标注质量可能有问题或者夜间样本量太少。火焰检测里白天和夜间是两种完全不同的视觉任务混合训练时经常互相干扰交叉验证能帮你定位到这一点。6.3 真实场景验证清单离线指标只是入场券有人问过我火焰检测模型上线前除了 mAP 还要看什么。我的建议是准备一段从未出现在训练集里的视频最好是实际部署场景的监控录像按不同距离、不同光照跑一遍模型人工数漏检和误检。离线 mAP 是模型在测试集上的平均表现但它测不出三个关键问题模型对连续视频帧的抖动是否严重、对远处小火苗的持续检测能力、对相似物体的区分是否稳定。这一节收个尾火焰检测项目的成败七成在数据集处理上。我第一次做火焰检测时拿着标注好的数据集直接训练mAP 看着不错一到现场就翻车——后来发现是验证集泄漏加标注框尺度混乱两个问题叠加。后来每次拿到新数据集先跑统计脚本、再做可视化抽查、再按视频分组划分、再交叉验证流程走完基本不会出大问题。做技术落地最怕的不是模型效果差而是不知道差在哪。这套流程能让你在模型翻车时快速定位是数据、标注还是训练参数的问题。希望帮到你。本文还有配套的精品资源点击获取