简介:这份红外小目标飞机检测数据集面向从事红外图像目标检测的研究者与算法工程师,尤其适合需要验证YOLO系列模型在弱小目标场景下性能的开发者。数据以VOC2007格式组织,训练集16551张、验证集4952张,类别仅含air一类,可直接接入常见检测框架进行训练与评估。压缩包共2000个文件,包含926个xml标注文件、926个txt标签文件、147个bmp红外图像及1个cache缓存文件,整体约37.4MB,标注与图像一一对应,便于快速构建数据加载流程。目前已有169人学习下载。借助该数据集,读者可完成从数据解析、模型训练到指标对比的完整实验链路,尤其适合研究红外弱小目标检测、验证注意力机制或特征增强模块效果的场景,也可作为论文复现与消融实验的基础数据来源。
1. 红外小目标飞机检测数据集 train:从一份标注文件到能跑通的训练管线
红外小目标飞机检测数据集 train 这个标题,拆开看是三个东西:红外成像、小目标、飞机检测,外加一个 train 划分。它解决的是在低信噪比、目标只有几个到几十个像素、几乎没有纹理和颜色信息的红外图像里,把飞机从云层、地物和噪声背景中框出来。适合谁?做机场周界监控、低空预警、遥感红外侦察、无人机反制这类方向的算法工程师,以及手里已经拿到一份红外标注数据、想用 YOLO 系列或类似检测器跑通训练的人。我见过太多人卡在第一步:数据拿到了,但不知道标注格式对不对、类别怎么定、小目标在训练时怎么不丢。这篇就按我实际做过的路径,把这份 train 数据从检查、转换、配置到训练、排错讲清楚。
2. 红外小目标飞机检测数据集 train 的标注格式与目录结构怎么核对
2.1 先确认标注是 VOC XML 还是 YOLO TXT
红外小目标数据集常见的标注格式有两种:PASCAL VOC 的 XML 和 YOLO 的归一化 TXT。你拿到 train 目录后,第一件事不是急着写训练脚本,而是看标注文件长什么样。如果目录里是Annotations/加JPEGImages/,大概率是 VOC;如果是images/加labels/,且 labels 里是每行class x_center y_center width height,那就是 YOLO 格式。两种格式的转换逻辑完全不同,搞错了后面全白费。
我一般会先跑一段统计脚本,把图像尺寸、标注框数量、类别分布一次性看清楚。红外小目标有个特点:框特别小,宽高经常在 8 到 30 像素之间,如果图像本身是 640×512 或 1280×1024,归一化后的宽高可能只有 0.01 到 0.05。这个量级直接决定后面 anchor 和输入尺寸怎么设。
import os import xml.etree.ElementTree as ET from collections import Counter def inspect_voc(anno_dir): stats = Counter() sizes = [] for f in os.listdir(anno_dir): if not f.endswith('.xml'): continue tree = ET.parse(os.path.join(anno_dir, f)) root = tree.getroot() w = int(root.find('size/width').text) h = int(root.find('size/height').text) sizes.append((w, h)) for obj in root.findall('object'): name = obj.find('name').text bbox = obj.find('bndbox') bw = int(bbox.find('xmax').text) - int(bbox.find('xmin').text) bh = int(bbox.find('ymax').text) - int(bbox.find('ymin').text) stats[name] += 1 stats[f'{name}_w_{bw//10*10}'] += 1 print('类别与尺寸分布:', stats) print('图像尺寸样本:', sizes[:5]) inspect_voc('train/Annotations')这段脚本做三件事:遍历 XML、统计每个类别的框数量、按 10 像素分桶统计框宽。逻辑说明:红外小目标的框宽分布如果集中在 10 到 20 像素,说明输入网络前不能做太激进的下采样。参数说明:bw//10*10是分桶技巧,方便看分布;如果你发现某个类别只有个位数样本,训练时就要考虑过采样或合并类别。
2.2 目录结构决定 DataLoader 怎么写
一份规范的 train 数据,我期望看到的是:
| 目录/文件 | 作用 | 检查点 |
|---|---|---|
| images/train | 训练图像 | 格式统一为 jpg 或 png,无损坏 |
| labels/train | YOLO 标注 | 每张图对应一个 txt,空文件表示无目标 |
| classes.txt | 类别名 | 顺序必须和训练配置一致 |
| train.txt | 图像路径列表 | 每行一个绝对或相对路径 |
如果标注是 VOC,你需要先转成 YOLO。转换时最容易翻车的地方是坐标越界和浮点精度。红外小目标框本来就小,x_center/w算出来如果有 6 位小数,写文件时截断到 6 位就够,但千万别四舍五入到 2 位,否则小框直接消失。
import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, img_w, img_h, class_map): tree = ET.parse(xml_path) root = tree.getroot() lines = [] for obj in root.findall('object'): name = obj.find('name').text if name not in class_map: continue cls_id = class_map[name] b = obj.find('bndbox') xmin = float(b.find('xmin').text) ymin = float(b.find('ymin').text) xmax = float(b.find('xmax').text) ymax = float(b.find('ymax').text) xc = (xmin + xmax) / 2.0 / img_w yc = (ymin + ymax) / 2.0 / img_h bw = (xmax - xmin) / img_w bh = (ymax - ymin) / img_h lines.append(f'{cls_id} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}') return lines逻辑说明:先读 XML 的宽高,再逐 object 算归一化中心点和宽高。参数说明:class_map是类别名到 id 的映射,必须和classes.txt行号一致;.6f保留 6 位小数,是 YOLO 生态的通用做法。转换完记得抽查几张图,用可视化脚本把框画回去,确认没有偏移。
3. 用 YOLOv8 在红外小目标飞机检测数据集 train 上跑通第一轮训练
3.1 环境与数据配置文件的写法
YOLOv8 对红外小目标不是最优解,但胜在工程链路成熟、文档多、排错快。我一般先用它跑一个 baseline,确认数据管线没问题,再换更针对小目标的检测头或注意力模块。环境上,ultralytics装最新稳定版即可,CUDA 版本和显卡驱动对齐,别在这上面省时间。
数据配置文件plane_ir.yaml这样写:
path: /data/ir_plane train: images/train val: images/val nc: 1 names: 0: plane逻辑说明:path是数据集根目录,train和val是相对路径。参数说明:nc是类别数,红外飞机检测通常就一类,如果你把民航、军机、无人机分开标,这里要对应改。names的顺序必须和 labels 里的 class id 一致,否则训练出来的模型会把类别搞反。
3.2 训练命令与关键参数怎么设
第一轮训练不要一上来就 300 epoch,先跑 50 epoch 看 loss 曲线和验证集表现。命令如下:
yolo detect train \ data=plane_ir.yaml \ model=yolov8s.pt \ imgsz=640 \ epochs=50 \ batch=16 \ lr0=0.01 \ lrf=0.01 \ warmup_epochs=3 \ box=7.5 \ cls=0.5 \ dfl=1.5 \ mosaic=0.5 \ scale=0.3 \ degrees=0.0 \ translate=0.1 \ fliplr=0.5 \ flipud=0.0 \ hsv_h=0.0 \ hsv_s=0.0 \ hsv_v=0.0 \ project=runs/ir_plane \ name=baseline逻辑说明:红外图像没有颜色信息,所以hsv_h/s/v全部关掉,开了反而引入噪声。mosaic=0.5是折中值,小目标用 mosaic 容易把目标拼到边缘导致截断,0.5 比默认 1.0 稳。scale=0.3控制随机缩放幅度,红外小目标本身像素少,缩放太狠会丢。flipud=0.0是因为红外图像上下翻转后,天空和地面的热分布不符合物理规律,除非你的数据本身就是多角度采集。
参数说明:imgsz=640是起点,如果你显存够,可以试 1024,小目标在更高分辨率下召回会好一些,但速度下降明显。batch=16根据显存调,8G 显存跑 640 大概能到 16,不够就降到 8。lr0=0.01是 SGD 的初始学习率,用 AdamW 的话改成 0.001。box=7.5是框回归损失权重,小目标定位难,可以适当提到 8.0 到 10.0 试。
3.3 训练过程中看什么指标
跑起来之后,重点看三个东西:train/box_loss是否稳定下降、metrics/mAP50是否在 20 epoch 后开始爬、val/box_loss和train/box_loss的差距。红外小目标常见的情况是 mAP50 能到 0.7 以上,但 mAP50-95 很低,因为框的 IoU 很难做高。这不是训练失败,是小目标的固有难点。
如果 20 epoch 后 mAP50 还在 0.1 以下,先别调模型,回去查数据。我遇到过标注框整体偏移 2 像素的情况,人眼看不出,但归一化后小框的 IoU 直接掉一半。用可视化脚本把预测框和标注框画在同一张图上,一眼就能看出来。
4. 红外小目标飞机检测数据集 train 的避坑与排查记录
4.1 坑一:小目标在 letterbox 后消失
现象:训练时 loss 正常下降,但验证集几乎检不出目标。原因:YOLO 默认的 letterbox 会把图像缩放到 640×640,如果原图是 1280×1024,缩放后小目标可能只剩 4 到 5 像素,再经过 backbone 的 32 倍下采样,特征图上就没了。解决:把imgsz提到 1024 或 1280,或者改用rect=True保持长宽比、减少无效填充。更彻底的做法是换小目标检测头,比如加 P2 层。
4.2 坑二:空标注文件被当成负样本
现象:模型在无目标区域疯狂出框,误报率高。原因:YOLO 训练时,空 txt 文件会被当作负样本,但如果你的数据里空图比例过高,模型会学到“大部分地方没目标”的先验,导致漏检。解决:统计空标注比例,如果超过 30%,要么补充正样本,要么在 DataLoader 里对空图降采样。我一般会把空图比例控制在 10% 到 20%。
4.3 坑三:类别名大小写不一致
现象:训练能跑,但推理时类别显示为plane或Plane混乱。原因:classes.txt里写的是Plane,yaml 里写的是plane,YOLO 按 yaml 为准,但可视化工具可能读另一个。解决:统一用小写,并且在转换脚本里做一次name.lower()。这个坑不致命,但交付时很尴尬。
4.4 坑四:验证集和训练集来自同一段视频
现象:验证集 mAP 很高,实际部署掉点严重。原因:红外视频连续帧之间高度相似,随机划分会导致训练集和验证集有大量近似帧。解决:按视频段或时间戳划分,确保验证集的场景、时段、天气和训练集不重叠。这个坑我踩过两次,血泪经验是:宁可验证集小一点,也要保证独立性。
4.5 坑五:数据增强把目标翻没了
现象:训练中期 loss 突然震荡。原因:mosaic加mixup同时开,小目标被拼到图像边缘后被裁剪掉,模型学到的是不完整目标。解决:小目标场景下mosaic不超过 0.5,mixup直接关掉,copy_paste可以开 0.1 到 0.3 补充正样本。增强策略要服务于数据特性,不能照搬 COCO 的配置。
5. 从 baseline 到可用模型:红外小目标检测的进阶调优技巧
第一轮跑通之后,别急着堆 epoch。我一般会做三件事:换输入分辨率、加 P2 小目标层、用切片推理验证。
换分辨率是最直接的。把imgsz从 640 提到 1024,mAP50 通常能涨 5 到 10 个点,但推理速度会掉一半。如果你的场景对实时性要求不高,比如离线巡检,直接上 1280。如果要求实时,考虑用 TensorRT 量化,INT8 之后 1024 分辨率也能跑到 30 FPS 以上。
加 P2 层需要改模型结构。YOLOv8 的配置文件在ultralytics/cfg/models/v8/yolov8-p2.yaml,把 P2 的检测头加上,特征图从 80×80 变成 160×160,小目标召回明显提升。代价是显存和计算量增加,batch 可能要降到 8。我试过在红外飞机数据上,P2 版本比原版 mAP50-95 高 4 个点左右。
切片推理是部署阶段的技巧。把大图切成 512×512 的小块,逐块推理再合并,能有效提升小目标检出率。SAHI 这个库可以直接用,但要注意重叠区域的框合并逻辑,IoU 阈值设 0.5 到 0.6,太低会重复框,太高会漏合并。
from sahi import AutoDetectionModel from sahi.predict import get_sliced_prediction model = AutoDetectionModel.from_pretrained( model_type='yolov8', model_path='runs/ir_plane/baseline/weights/best.pt', confidence_threshold=0.25, device='cuda:0' ) result = get_sliced_prediction( 'test_ir.jpg', model, slice_height=512, slice_width=512, overlap_height_ratio=0.2, overlap_width_ratio=0.2 ) result.export_visuals(export_dir='runs/sahi_vis')逻辑说明:SAHI 把图像切片后分别推理,再按 NMS 合并。参数说明:slice_height/width根据你的目标尺寸定,目标平均 20 像素的话,512 的切片里目标占比合适;overlap_ratio=0.2是经验值,太小会切掉目标,太大增加计算量。confidence_threshold=0.25比训练时的 0.5 低,因为切片后单块置信度会下降,合并时再筛。
最后说一个验证习惯:每次调完参数,不要只看 mAP,把误报和漏报的图各抽 20 张出来看。红外小目标的误报往往来自云边缘和地物热源,漏报集中在目标与背景温差小的场景。看多了,你就知道下一步该补数据还是改模型。希望帮到你。
本文还有配套的精品资源,点击获取