航空图像野火探测数据集:标注、训练与YOLOv8实战

发布时间:2026/10/8 7:02:30
航空图像野火探测数据集:标注、训练与YOLOv8实战
简介这份资源是面向野火探测与火灾识别方向的航空图像目标检测数据集适合从事深度学习、计算机视觉研究及遥感灾害监测的开发者与科研人员使用。数据集包含4500个图像注释文件注释以XML格式手动标注明确给出图像中目标对象的位置与对应标签并借助Roboflow完成标注流程保证整体质量与一致性。压缩包共2000个文件全部为xml注释文件包体约165.02MB可直接用于YOLO、Faster R-CNN等检测模型的训练与验证。目前已有362人学习下载说明其在野火识别任务中具备一定参考价值。读者可借助这些标注数据快速构建火灾检测实验用于模型训练、精度评估与算法对比也可作为航空图像目标检测课题的标注范例减少自行标注的时间成本。1. 航空图像野火探测数据集从标注格式到训练落地的完整路径森林防火指挥中心的值班员盯着无人机回传画面烟柱已经起来了但可见光镜头里树冠遮挡严重等他确认坐标再通知地面队伍火线已经推进了三百米。这个场景暴露的问题很具体通用目标检测数据集里根本没有足够的航空视角野火样本模型没见过从三百米高空俯拍的小火点自然也就谈不上早期预警。航空图像野火探测数据集就是冲着这个缺口来的——它把无人机和有人机在巡护航线中拍到的可见光与红外影像做像素级标注覆盖烟雾、明火、过火区域三类目标让检测模型学会在复杂林区背景下把火从树影、反光、云雾里摘出来。如果你在做林火监测、应急响应或者遥感目标检测这个方向值得投入因为公开可用的航空野火标注数据一直稀缺而它恰好补上了从“有图”到“有标签”这一步。2. 航空野火数据集长什么样标注体系与选型逻辑2.1 三类标注目标与航空视角的物理约束航空图像野火探测数据集的核心标注对象通常分三类烟雾羽流、明火区域、过火迹地。烟雾标注用多边形勾勒扩散边界明火用紧贴火焰外缘的边界框过火迹地则按烧焦地表范围做语义分割掩码。为什么不用单一检测框统一处理因为烟雾在航空视角下形态极不规则一个矩形框会把大量未燃树冠包进去训练时模型学到的是“有烟的地方框大一点”而不是“烟在哪里”。明火区域相对集中边界框够用过火迹地面积大且边界模糊分割掩码才能表达真实范围。航空视角带来的物理约束直接决定标注策略。飞行高度通常在 150 到 800 米之间地面采样距离从几厘米到几十厘米不等。小火点在图像上可能只有十几个像素标注时如果框太松模型会把周围植被当正样本框太紧又容易在数据增强后丢失。常见做法是明火框外扩不超过 5 个像素烟雾多边形则允许包含少量背景因为烟雾本身半透明边界天然模糊。提示拿到数据集先看标注文件里的iscrowd字段。航空图像里过火迹地经常连片如果iscrowd1的样本占比超过三成训练时要把这类样本的损失权重调低否则模型会偏向预测大区域。2.2 可见光与红外双模态的配准要求航空巡护吊舱通常同时挂载可见光和红外相机但两个传感器的视场角和分辨率不同。数据集如果包含双模态影像配准精度直接决定融合训练的上限。我见过最粗糙的情况是可见光和红外图像只做了时间戳对齐空间上差了几十个像素模型学出来的融合特征其实是错位的。配准的硬指标是同一地物在可见光和红外图像上的像素偏移不超过图像短边的 0.5%。假设红外图像是 640×512偏移要控制在 3 个像素以内。检查方法很简单找几个高对比度地物比如孤立树冠、道路交叉口分别在两个模态里标出中心点算欧氏距离。如果数据集没有提供配准后的图像对自己用 SIFT 加单应性矩阵做一次对齐但要注意航空图像里纹理重复区域多特征点容易误匹配最好加 RANSAC 过滤。2.3 数据集划分与类别不平衡的处理航空野火数据集的类别不平衡是常态。巡护航线大部分时间拍的是正常林区烟雾和明火样本占比可能不到 5%。如果按随机划分验证集里可能一个明火样本都没有评估指标完全失真。我一般用分层抽样先按“有无火情”分两层再在火情层里按“烟雾/明火/过火”分三层每层按 7:2:1 划训练、验证、测试。这样能保证每个子集里三类目标都有出现。负样本也不能浪费。正常林区图像里云影、水面反光、裸露岩石都容易被模型误判为烟雾或明火。把这些困难负样本单独标一个hard_negative类别训练时给一个较小的损失权重能显著降低虚警率。具体权重设多少从 0.1 开始试如果验证集虚警率还是高加到 0.3但不要超过 0.5否则模型会变得过于保守漏掉真实小火点。3. 把航空野火数据集喂给 YOLOv8格式转换与训练配置3.1 从 COCO 标注转 YOLO 格式的脚本与边界处理航空野火数据集常见的标注格式是 COCO JSON因为多边形和分割掩码用 COCO 表达最自然。但 YOLOv8 检测训练需要每张图一个.txt文件每行class_id x_center y_center width height坐标归一化到 0 到 1。转换脚本本身不复杂坑在边界处理多边形转边界框时如果多边形有一部分超出图像边界直接算 min/max 会得到负坐标或大于 1 的值YOLO 训练时直接报错。import json import os from pathlib import Path def coco_to_yolo(coco_json_path, output_dir, img_width, img_height): with open(coco_json_path, r) as f: data json.load(f) # 建立 image_id 到文件名的映射 img_id_to_name {img[id]: img[file_name] for img in data[images]} # 建立 category_id 到连续索引的映射YOLO 要求从 0 开始 cat_id_to_idx {cat[id]: idx for idx, cat in enumerate(data[categories])} Path(output_dir).mkdir(parentsTrue, exist_okTrue) for ann in data[annotations]: img_id ann[image_id] img_name img_id_to_name[img_id] txt_name Path(img_name).stem .txt txt_path Path(output_dir) / txt_name # 多边形标注转边界框 if segmentation in ann and ann[segmentation]: seg ann[segmentation][0] # 取第一个多边形 xs seg[0::2] ys seg[1::2] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) else: x_min, y_min, w, h ann[bbox] x_max, y_max x_min w, y_min h # 裁剪到图像边界内这是最容易翻车的地方 x_min max(0, min(x_min, img_width)) x_max max(0, min(x_max, img_width)) y_min max(0, min(y_min, img_height)) y_max max(0, min(y_max, img_height)) # 如果裁剪后宽高为 0跳过这条标注 if x_max x_min or y_max y_min: continue # 归一化并计算中心点 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 class_idx cat_id_to_idx[ann[category_id]] with open(txt_path, a) as f: f.write(f{class_idx} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n) # 调用示例假设图像统一为 1920x1080 coco_to_yolo(annotations.json, labels/train, 1920, 1080)这段脚本的关键逻辑在边界裁剪和空标注跳过。x_min max(0, min(x_min, img_width))这一行同时处理了负坐标和超界两种情况。如果裁剪后x_max x_min说明这个标注完全在图像外直接跳过否则 YOLO 会生成宽度为 0 的框训练时 loss 变成 NaN。归一化用图像实际宽高不要用数据集里写的width和height字段有些数据集这两个字段是原始采集分辨率和实际保存的图像尺寸不一致。3.2 YOLOv8 训练配置针对小目标火点的参数调整航空图像里的小火点检测是典型的小目标问题。YOLOv8 默认的imgsz640对于 1920×1080 的航空图像来说下采样后小火点可能只剩几个像素。我一般把imgsz设到 1280如果显存不够至少也要 1024。batch相应降到 4 或 8用梯度累积补回来。# wildfire_yolov8.yaml path: /data/wildfire_dataset train: images/train val: images/val test: images/test names: 0: smoke 1: fire 2: burned_area 3: hard_negativeyolo detect train \ datawildfire_yolov8.yaml \ modelyolov8m.pt \ imgsz1280 \ epochs200 \ batch8 \ lr00.001 \ lrf0.01 \ warmup_epochs5 \ box7.5 \ cls0.5 \ dfl1.5 \ mosaic0.5 \ mixup0.1 \ copy_paste0.1 \ degrees15 \ translate0.1 \ scale0.5 \ fliplr0.5 \ flipud0.5 \ patience30 \ device0box7.5比默认的 7.5 没变但cls0.5是默认值这里保持不动。真正要调的是mosaic0.5默认 1.0 对航空图像太激进四张图拼在一起会引入大量无关背景小火点被淹没。copy_paste0.1是 YOLOv8 里做小目标增强的有效手段把标注的小火点复制粘贴到其他图像上能增加正样本密度。flipud0.5要打开航空俯拍图像上下翻转不改变语义但能翻倍数据多样性。注意patience30配合 200 个 epoch如果 30 轮验证指标不升就早停。航空野火数据集如果只有几千张图很容易在 80 轮左右过拟合早停比硬训到 200 轮更划算。3.3 训练日志里该盯哪几个指标YOLOv8 训练输出里metrics/mAP50-95是综合指标但航空野火检测更要看metrics/precision和metrics/recall的平衡。虚警率高的时候 precision 低漏报多的时候 recall 低。我一般先看 recall因为漏掉一个真实火点的代价远大于虚警。如果 recall 低于 0.7先检查标注质量再考虑降低conf阈值。另一个关键指标是train/box_loss和val/box_loss的差距。如果训练 loss 持续下降但验证 loss 在 50 轮后开始上升说明过拟合了。这时候不要急着加数据先把mosaic关掉再训 20 轮mosaic 增强在训练后期会干扰模型收敛。lr00.001对 YOLOv8m 偏大如果 loss 震荡厉害降到 0.0005。4. 航空野火检测的避坑与排查五个血泪教训4.1 烟雾标注把云影框进去模型学会认云不认烟现象验证集上烟雾检测的 precision 只有 0.4可视化发现模型把大片云影也标成了烟雾。原因标注时只看了单张图没有对比同一区域在时间序列上的变化。航空巡护图像里云影和烟雾在单帧上灰度分布接近但云影在连续帧里位置不变烟雾会扩散。解决标注烟雾时至少参考前后各一帧确认该区域在移动再标。如果数据集没有时间序列用红外模态辅助判断烟雾在红外图像上温度特征和云影差异明显。4.2 图像尺寸不统一导致归一化坐标错位现象训练时 loss 正常下降但推理时框的位置整体偏移。原因转换脚本里用了数据集 JSON 中images字段的width和height做归一化但实际图像文件被预处理过尺寸和 JSON 记录不一致。解决转换前用 PIL 或 OpenCV 读一遍每张图的实际尺寸用实际尺寸做归一化。如果图像尺寸不统一要么统一 resize 后再转要么在 YOLO 配置里开rectTrue做矩形训练。4.3 红外和可见光图像没配准就做通道拼接现象双模态融合训练时模型在验证集上的 mAP 比单可见光还低。原因可见光和红外图像空间错位拼接后的 6 通道输入里同一位置的可见光像素和红外像素不对应。解决先做配准再拼接。用 OpenCV 的findHomography加 RANSAC 算单应性矩阵把红外图像 warp 到可见光坐标系。配准后随机抽 10 对图像做棋盘格叠加检查偏移超过 3 个像素就重新标定。4.4 困难负样本权重给太高模型变得过度保守现象加了hard_negative类别后虚警率降了但 recall 从 0.75 掉到 0.55。原因困难负样本的损失权重设成了 0.5模型为了压低负样本损失把很多模糊正样本也判成负。解决把权重降到 0.1 到 0.2 之间同时提高正样本的cls损失权重。如果 recall 还是上不来检查困难负样本里是不是混进了真实火点标注错误比权重问题更常见。4.5 验证集划分没分层评估指标完全不可信现象训练时 mAP50 到了 0.85实际部署后漏报严重。原因验证集是随机划分的里面 90% 是正常林区图像模型只要全预测为背景就能拿到高准确率。解决按“有无火情”分层抽样确保验证集里火情图像占比不低于 30%。如果数据集本身火情样本太少用过采样把火情样本复制到训练集但验证集和测试集必须保持原始分布不能过采样。5. 让航空野火检测模型真正可用的两个进阶技巧5.1 用滑动窗口推理处理超大分辨率航空图像航空巡护图像经常是 4000×3000 甚至更大直接 resize 到 1280 会丢失小火点。我一般用滑动窗口推理把大图切成 1280×1280 的块块之间有 20% 重叠每块单独推理最后用 NMS 合并结果。重叠区域的作用是防止火点正好落在切块边界被截断。import cv2 import numpy as np from ultralytics import YOLO def sliding_window_inference(model, image_path, window_size1280, overlap0.2): img cv2.imread(image_path) h, w img.shape[:2] stride int(window_size * (1 - overlap)) all_boxes [] all_scores [] all_classes [] for y in range(0, h, stride): for x in range(0, w, stride): # 确保窗口不超出图像边界 x1 min(x, w - window_size) y1 min(y, h - window_size) x2 x1 window_size y2 y1 window_size patch img[y1:y2, x1:x2] results model(patch, conf0.25, iou0.5, verboseFalse) for r in results: boxes r.boxes if boxes is not None: for box in boxes: # 把窗口内坐标映射回原图 bx1, by1, bx2, by2 box.xyxy[0].tolist() all_boxes.append([bx1 x1, by1 y1, bx2 x1, by2 y1]) all_scores.append(box.conf[0].item()) all_classes.append(int(box.cls[0].item())) # 对所有窗口的检测结果做全局 NMS indices cv2.dnn.NMSBoxes( bboxes[[b[0], b[1], b[2]-b[0], b[3]-b[1]] for b in all_boxes], scoresall_scores, score_threshold0.25, nms_threshold0.5 ) final_results [] for i in indices: final_results.append({ box: all_boxes[i], score: all_scores[i], class: all_classes[i] }) return final_results窗口大小选 1280 是因为 YOLOv8 在这个尺寸下对小目标最友好再大显存吃不消。重叠 20% 是经验值低于 15% 边界火点容易漏高于 30% 计算量浪费严重。全局 NMS 的nms_threshold0.5比训练时略高因为重叠区域的同一火点会有多个窗口检测到阈值太低会误删。5.2 用时间序列差分降低云影和光照变化的虚警单帧检测最大的敌人是云影和光照突变。航空巡护同一航线每隔几分钟拍一次同一地物在相邻帧里位置不变但云影会移动光照会变化。我一般取前后各一帧做差分当前帧检测到的疑似烟雾区域如果在前后帧的同一位置没有对应变化就判为虚警。具体做法是对当前帧的每个检测框在前后帧的相同坐标区域算像素均值差异。如果差异小于阈值比如 15 个灰度级说明这个区域在时间上稳定大概率是云影或固定地物。如果差异大说明有动态变化保留检测。这个后处理能把虚警率压掉三到四成代价是需要缓存前后帧对实时性要求高的场景要权衡。我自己的习惯是每次拿到新的航空野火数据集先花半天时间把标注可视化一遍随机抽 50 张图把框画出来看。这一步能发现八成以上的标注问题比直接开训再调参省事得多。航空图像野火探测这个方向数据质量比模型结构重要标注干净了YOLOv8m 和 YOLOv8l 的差距可能不到两个点标注脏了换什么模型都是玄学。希望帮到你。本文还有配套的精品资源点击获取