简介:面向火灾检测与目标检测学习及项目开发者,提供一份包含1000张真实场景火焰图像的标注数据集,可同时满足YOLO、VOC、COCO三种主流格式需求,无需额外转换即可直接投入YOLOv5/v8/v10等模型训练,有效解决数据采集与格式统一难题。压缩包共112个文件,以104个XML标注文件、5个Python脚本及配置文本为主,整体仅97KB,目录包含images、labels、Annotations、coco/annotations等模块,结构清晰便于检索。已有62人学习下载。配套的split_dataset.py支持按自定义比例划分训练集、验证集与测试集,并生成符合规范的ImageSets文件;详细教程涵盖Windows/Linux环境下的依赖安装、数据路径配置、训练与推理命令及常见报错处理,适合课程设计、毕业设计或真实场景火焰识别项目快速落地。 前段时间一位做视觉检测的朋友跟我聊起火灾早期预警项目,卡在数据集上快一个月。他从网上东拼西凑了一批火焰图片,有的给VOC格式标注,有的给COCO,还有一批根本没标注,硬着头皮转成YOLO格式之后,训练出来mAP只有0.4。他跟我说了一句话我印象很深:数据这关过不了,后面全是白搭。
我后来把手里整理过的一套真实火灾火焰图像数据集重新梳理了一遍,共1000张真实场景图像,把VOC、COCO、YOLO三种格式的标签统一做好,又写了一个自动划分训练集/验证集/测试集的脚本,最后用YOLO系列模型完整跑了一遍训练流程。这篇文章就把这整套东西拆开讲清楚:数据集怎么组织的、三种标签格式之间怎么换算、划分脚本到底解决了什么问题、YOLO训练时哪些参数值得调、哪些坑必须避开。无论你是刚接触目标检测的新手,还是想快速出baseline做火灾检测项目的工程师,这套流程都可以直接“抄作业”。
1. 火灾火焰检测真正的门槛:数据准备
1.1 火焰目标为什么这么难标、难检
做目标检测的人对行人、车辆这类刚性目标很熟悉,它们有相对固定的外形,模型学起来容易。火焰完全是另一回事。它没有固定形态,燃烧时形状持续变化,颜色从亮黄到橙红再到蓝色都有,半透明且边缘模糊,还经常和背景融在一起。同一个火苗,在白天强光下和夜间暗场里拍出来,视觉特征差异极大。
这些特性导致两个直接后果。第一,标注火焰框时,不同标注员的判断标准会差别很大,同样一张图,有人把最外圈的橙色光晕也框进去,有人只框核心火焰区,这种标注不一致会直接拉低模型收敛速度。第二,模型学到的特征往往不是“火焰的本质”,而是“某个颜色段加某个形状”,所以红色灯笼、车尾灯、晚霞下的红旗这些目标很容易被误判成火灾。理解这一点,后面所有关于标注清洗、负样本补充、训练参数调整的内容才说得通。
1.2 真实火焰图像为何稀缺,1000张怎么用
真实火灾场景的图像在公开渠道里非常少。消防现场拍摄条件恶劣,监控画面往往有烟尘遮挡,无人机航拍又受视角限制,而可控火源实验只能覆盖特定燃料和场景,很难模拟真实火灾的复杂状态。市面上的公开数据集要么图片量少,要么分辨率低,要么标注质量参差不齐,直接拿来训练效果很不可控。
这里要老老实实说一句:1000张图在深度学习里不算多,但对火焰检测这种目标类别单一、场景模式相对集中的任务来说,已经足够跑出一个可用的baseline。很多实际项目就是从几百张图起步的。关键在于这1000张要覆盖尽量多的视角——室内监控、室外开阔地、夜间暗光、逆光、浓烟伴生等情况都要有,同时配上准确统一的标注,再用数据增强把变化撑起来。我推荐的做法是:先用这套数据把整个训练流程跑通,拿到一个可用的mAP基线,再根据实际部署场景补充更多现场数据,一轮一轮迭代,而不是一上来就追求数据集规模。
2. VOC/COCO/YOLO 三格式标签的换算式与清洗技巧
2.1 数据集的目录结构安排
拿到一套数据集,第一件事不是看训练代码,而是先看目录结构是否清晰。我这套数据集的目录是这样组织的:
datasets/fire/ ├── images/ │ ├── fire_001.jpg │ ├── fire_002.jpg │ └── ... ├── annotations/ │ ├── voc/ │ │ ├── fire_001.xml │ │ ├── fire_002.xml │ │ └── ... │ ├── coco/ │ │ └── annotations.json │ └── yolo/ │ ├── fire_001.txt │ ├── fire_002.txt │ └── ...图像文件统一放images,三种格式的标签分别放在annotations下的voc、coco、yolo三个子目录。这样做的最大好处是,不管用哪个训练框架,都不用再到处找标签文件,一目了然。图像命名统一用有含义的前缀加序号,避免中文名、空格、特殊字符,这些字符在Linux路径处理和后续训练时经常会惹出莫名其妙的错误。
2.2 三种格式的坐标换算关系
VOC、COCO、YOLO这三种格式,核心区别就是坐标表示方式不同。我做一个表直接对照:
| 标注格式 | 文件形式 | 坐标定义 | 典型使用场景 |
|---|---|---|---|
| VOC | 每张图对应一个XML文件 | xmin, ymin, xmax, ymax,像素绝对值 | 通用检测、早期模型、开源标注工具 |
| COCO | 整个数据集一个JSON文件 | x, y, width, height,像素值,左上角为原点 | 通用检测、实例分割、学术评测 |
| YOLO | 每张图对应一个TXT文件 | x_center, y_center, width, height,归一化到0~1 | YOLO系列模型训练 |
转换公式也不复杂。VOC转COCO,就是两个对角点转成左上角点加宽高:x保持xmin,y保持ymin,width等于xmax减xmin,height等于ymax减ymin。COCO转YOLO,需要把像素坐标换算成归一化坐标:x_center等于x加width的一半,再除以图像宽度;y_center同理;width和height分别除以图像宽和高。
这里有一个非常容易踩的坑:类别索引不对齐。COCO的category_id通常从1开始,YOLO的class id从0开始,VOC的标签里存的是类别名字符串。转换时如果不建立一张“类别名—COCO ID—YOLO ID”的映射表,极容易出现所有框的类别全部错一位的情况。比如nc设为1,标注类别却写成了1,训练时YOLO会提示类别越界,很多人第一反应是怀疑模型配置,其实问题出在转换脚本上。
2.3 转换前必须先做的标注清洗
从公开渠道整理来的素材,标注问题往往比想象中严重。我处理这套数据时发现几类高频问题:一是标注框超出图像边界,可能因为标注时截图尺寸和最终图不一致,这类框会导致YOLO训练时坐标越界警告,需要将坐标clip到图像范围内;二是框的宽或高为0甚至负数,这类无效标注必须直接剔除,不然后续计算IoU时会出现NaN;三是图像明明有火焰但没有任何标注,这类图如果直接放进训练集,会作为背景样本参与训练,无形中告诉模型“这里没有火”,对检测效果是伤害。
我的建议是,所有格式转换完成之后,不要急着训练,先写一个校验脚本扫一遍:检查每张图像是否都有对应的标签文件,检查标签文件中的每一行坐标是否都在合理范围,检查每个类别的索引是否在nc范围内,检查是否存在空标签但不该存在的图。这一步看起来琐碎,但能省下后面排查训练异常的大量时间,尤其是当你打算把数据集分享给团队其他人使用时,校验脚本本身就是一份数据质量说明。
3. 自动划分脚本:从“凑合用”到“一次到位”
3.1 划分前必须先决定的两件事
很多人划分数据集是直接写几行随机shuffle的代码,把图片和标签按比例copy到train、val、test目录。这个做法对付普通数据集还算能用,但对监控场景采集的火焰数据,有两个问题必须提前想清楚。
第一,必须固定随机种子。如果不固定,每次运行划分结果都不同,训练集和验证集会变,导致同一批实验之间没有可比性。尤其当你需要对比不同模型效果、调超参数时,数据集不稳定会让所有对比结果都失去参考价值。第二,必须按视频源或者场景源分组划分,而不是按单张图划分。火焰连续帧之间的相似度极高,如果同一段连续画面里,一部分帧进训练集、一部分帧进验证集,验证指标会虚高,因为模型相当于“见过了答案再来考试”。我见过不少项目在验证集上mAP很高,一上真实监控视频就露馅,往往就是划分时没考虑这个因素。
3.2 脚本核心逻辑与可直接用的代码
我最终的划分思路是:以图为最小单位,先按文件名前缀提取“视频段”或“场景ID”,对场景ID洗牌,再按比例切分,然后拷贝对应图片和YOLO标签,最后过滤COCO的JSON文件。下面这个是去掉COCO过滤逻辑后的核心版本,可以直接保存为split_dataset.py运行:
import os import random import shutil random.seed(42) IMG_DIR = "datasets/fire/images" LAB_DIR = "datasets/fire/annotations/yolo" OUT_DIR = "datasets/fire_split" # train:val:test = 8:1:1 RATIOS = [0.8, 0.1, 0.1] # 1. 收集所有图片 images = [f for f in sorted(os.listdir(IMG_DIR)) if f.lower().endswith((".jpg", ".jpeg", ".png"))] # 2. 按场景前缀划分,避免同一场景的连续帧被切散 scene_groups = {} for img in images: # 假设文件名格式是 scene001_frame012.jpg scene_id = img.split("_")[0] scene_groups.setdefault(scene_id, []).append(img) scene_ids = list(scene_groups.keys()) random.shuffle(scene_ids) # 3. 按场景组数量切分 n_total = len(scene_ids) n_train = int(n_total * RATIOS[0]) n_val = int(n_total * RATIOS[1]) train_scenes = set(scene_ids[:n_train]) val_scenes = set(scene_ids[n_train:n_train + n_val]) test_scenes = set(scene_ids[n_train + n_val:]) # 4. 拷贝对应图片和标签 split_map = { "train": train_scenes, "val": val_scenes, "test": test_scenes, } for split_name, scenes in split_map.items(): img_out = os.path.join(OUT_DIR, "images", split_name) lab_out = os.path.join(OUT_DIR, "labels", split_name) os.makedirs(img_out, exist_ok=True) os.makedirs(lab_out, exist_ok=True) for scene_id in scenes: for img_name in scene_groups[scene_id]: stem = os.path.splitext(img_name)[0] shutil.copy2(os.path.join(IMG_DIR, img_name), os.path.join(img_out, img_name)) lab_file = os.path.join(LAB_DIR, stem + ".txt") if os.path.exists(lab_file): shutil.copy2(lab_file, os.path.join(lab_out, stem + ".txt"))这段代码的核心是用scene_id做分组再shuffle,因为火焰数据大多来自视频抽帧,按场景分组能最大限度避免训练集和验证集出现“近亲样本”。如果你要同步VOC和COCO格式,VOC格式和YOLO格式一样按照文件拷贝即可;COCO就要稍微费点事:读取原始JSON,按划分结果保留对应image_id的images条目和annotations条目,重新写成三个独立JSON文件。有一个容易遗忘的细节是COCO的licenses和categories字段要保持不变,否则有些训练脚本解析时会报错。
3.3 划分完之后的验收清单
划分完成不等于结束,我每次都会做一轮验收检查,确认三件事。
第一,每个split下的图片数量和标签txt数量是否一致。如果不一致,说明有些图片没有对应标签文件,要找到这些样本单独处理。第二,COCO JSON里的annotations数量是否和YOLO目录下全部txt文件的行数总和一致,这是验证COCO过滤是否出错最有效的办法。第三,随机抽查几个验证集样本,用可视化工具把标注框画出来看一遍,重点看有没有明显错位、漏标、类别错标。这个过程虽然耗时,但能避免你把一份带问题的数据集直接喂给模型,等训练完才发现根本没法用。
4. YOLO训练实操:环境、参数和报错处理
4.1 环境搭建与数据集目录配置
训练部分我用的YOLOv8,Ultralytics这个版本对新手最友好,一条pip命令就能装完:pip install ultralytics。如果你本地没有合适的GPU,不用纠结,直接租一块云GPU,国内像阿里云、AutoDL这类平台都有现成的深度学习镜像,装好驱动和CUDA之后,把数据和代码传上去就能跑。
数据集目录建议直接放在工程下,确保路径中没有中文和空格。YOLO训练时会自动读取images/train、labels/train这种约定好的目录结构,只要你的数据和前面划分脚本生成的目录结构一致,就不需要额外改代码。
4.2 fire.yaml 配置与训练命令
YOLO训练需要一份数据集配置文件,内容很简单,指向划分好的目录并声明类别数:
# fire.yaml path: /root/autodl-tmp/fire_dataset # 改成你自己的绝对路径 train: images/train val: images/val test: images/test nc: 1 names: 0: firepath建议写绝对路径,因为相对路径是相对于yaml文件所在目录计算的,有时候工程启动目录一变,路径就找不到,排查起来很烦。nc是类别数,当前数据集只有火焰一类,所以是1;如果后续加了烟雾类别,这里要同步改成2,names里也要加上smoke。
训练命令最基础的一条:
yolo detect train data=fire.yaml model=yolov8n.pt epochs=100 imgsz=640 batch=16 device=0model参数可以换成yolov8s.pt、yolov8m.pt,规格越大模型容量越大,但对硬件要求也更高。第一次跑建议直接用yolov8n,先确认整条链路是通的,再换大模型追求精度。epochs设100对单类火焰数据足够了,因为数据集相对简单,模型一般在第40到60个epoch就收敛,设太多反而浪费时间。
4.3 训练日志怎么看、参数怎么调
训练过程中,屏幕会不断刷每一类的精度指标,包括Precision、Recall、mAP50、mAP50-95。很多人一看mAP50-95低就慌,其实火焰这种非刚性目标,框的边界本身含模糊区域,mAP50-95通常不会像行人检测那么高。我更关注mAP50,它衡量的是IoU在0.5时的平均精度,对火焰检测更有实际意义。我在这类数据集上常见的结果是mAP50能到0.85以上,mAP50-95在0.55到0.7之间都属于正常,不用因为mAP50-95不高就怀疑模型坏了。
参数调整方面有三个经验值得分享。第一,imgsz可以从640起步,如果检测场景中火焰目标较小,可以试着提到768或896,小目标召回率会有明显提升,但显存占用会按输入尺寸的平方增长,显存不够时要同步降低batch。第二,如果训练集里夜间、逆光样本偏多,可以适当增加HSV色彩增强的幅度,让模型对光照变化更鲁棒。第三,训练时打开早停机制,patience设20左右,验证指标连续20个epoch不提升就自动停掉,能省不少时间。
4.4 三个高频报错与快速定位方法
用这套流程训练时,常见的问题我列成一个表,方便你对照排查:
| 现象 | 可能原因 | 处理方法 |
|---|---|---|
| 训练日志里大量打印坐标越界警告 | 标签归一化时计算错误,或标注框本身超出图像边界 | 用校验脚本扫描标签,把越界坐标clip到[0,1]区间,剔除宽高为0的框 |
| 报错“All labels empty” | 图片和标签文件名不匹配,或标签文件内容为空 | 检查labels目录下TXT文件名是否和图片文件名一致,确认后重新生成标签 |
| 训练中途CUDA out of memory | 显存不足 | 降低batch、降低imgsz,或者换更大显存的GPU实例 |
如果你训练时发现mAP始终上不去,先别急着调模型结构,回到数据本身检查:标注框有没有明显错位,有没有该标没标的漏标样本,有没有大量空标签图片混进训练集。我在这上面吃过不少亏,花了一周调各种数据增强参数,最后发现是某一步格式转换时把十分之一的标签文件写坏了。
5. 别被测试集指标骗了:真实场景的误报整治
5.1 mAP很高不代表现场不误报
模型在测试集上拿到0.85的mAP,是不是就可以直接部署了?我告诉你,大概率不行。测试集的评估只能说明模型在这批静态图像上的检测能力,到了真实监控环境,画面会连续变化,背景也远比测试集复杂。我实际部署时遇到的最典型问题,是把红色消防栓箱、灭火器上的红色图案、厂区里红色的车辆和旗帜误判成火焰。这些目标的颜色区间和火焰高度重合,单靠提升mAP解决不了本质问题。
所以我的建议是,训练完不要急着上线,先拿几段没有火焰的监控视频去跑一遍,统计误报数量。这个动作能非常快地暴露模型的“知识盲区”,也帮你判断后处理需要加哪些过滤规则。
5.2 加背景负样本是我用过最有效的降误报手段
针对红色误报,最有效的办法不是调阈值,而是给模型补充“无火焰但有红色物体”的样本。做法很简单:从部署现场没有火焰的时段里抽一些画面,放到训练集images目录下,然后在对应的labels目录下创建同名的空TXT文件。这些负样本参与训练之后,模型能学到“这类红色区域不是火焰”的决策边界。
负样本的加入量不用多,我一般控制在正样本数量的10%到20%,加太多会让数据集里背景图占比过大,干扰正常火焰样本的学习。这个操作加上视频验证,能把夜间的误报从一晚上十几次压到两三次。如果你正在做火焰检测项目,我强烈建议把这一步纳入你的标准流程,它的性价比超过很多复杂的后处理算法。
最后再分享一个实际操作中养成的习惯:每次训练完,不只看best.pt的指标,还专门拿部署场景的几段原始视频做一遍推理,把检测结果录下来逐帧看。这样做虽然费时间,但能帮你提前发现很多指标上看不出来的问题。数据整理、格式转换、清洗、划分、训练、验证这套流程,我前前后后跑过好几个项目,最大的感受是,火焰检测的瓶颈从来不在模型结构,而在数据是否扎实。把数据这关做扎实了,YOLO训练本身反而是一路顺畅的。希望这份整理能帮你少走一点弯路。
本文还有配套的精品资源,点击获取