简介:面向红外小目标飞机检测场景的训练数据集,适合计算机视觉初学者与算法工程师用于目标检测模型的训练与验证。资源按VOC格式划分训练集与验证集,训练集包含一万六千五百五十一张图像,验证集包含四千九百五十二张图像,类别仅有一种,即飞机类,专注单类红外飞机小目标识别;同时提供两种标注文件,可兼容主流工具链,减少格式转换成本。压缩包内共两千个文件,以扩展标记语言标注、纯文本标签及位图红外图像为主,并附少量缓存文件,整体大小约三十七点四兆字节,体积轻量、便于快速获取和部署。图像样本覆盖多种背景与目标尺度,可直接用于搭建红外目标检测实验、评估模型性能或开展数据增强研究。已有一百六十九人学习下载,适合作为课题研究、毕业设计或竞赛练手的实用数据基础。
1. 红外小目标飞机检测数据集 train:一个 16×16 像素的亮斑就够折腾一天
“红外小目标飞机检测数据集 train” 看起来像一句项目备注,实际是红外目标检测里最磨人的组合:飞机在成像面上可能只有十几乘十几甚至几个像素,而 train 这个动作决定了整个项目能不能落地。很多团队拿通用目标检测的数据集和训练流程硬套,结果模型在验证集上指标漂亮,一到真实红外视频里就全是虚警,根子往往不在网络结构,而在数据集没按红外小目标的逻辑处理。
红外图像没有颜色,目标和背景的温差决定了灰度差异,云层边缘、建筑物反射都可能比飞机还亮。通用检测里的 anchor 尺度、数据增强、评估指标到这里全部失灵。这篇文章面向正在准备红外小目标飞机检测数据集并开始训练的工程师和研究员,按数据选型、预处理、标注转换、训练划分、避坑到进阶评估的顺序写,目标是让你照着能跑通自己的一版,而不是停留在“能过个 demo”。
2. 数据从哪来、怎么预处理:红外小目标飞机检测数据集的选型与清理
2.1 红外小目标到底小在哪:信噪比、尺寸与背景三重压力
先给“小目标”定个量。在 640×512 的常见红外图像里,一架 3 公里外的战斗机通常只占 4×4 到 16×16 像素;对比一下 COCO 数据集里动辄占据画面三分之一的物体,完全不是同一个任务。按照 SPIE 的定义,小目标通常指成像尺寸小于 9×9 像素、占整幅图像面积不到 0.15% 的目标。飞机在这种尺度下没有形状、纹理、颜色信息,能用的特征只剩下“局部灰度比周围高”和“在连续帧里位置连续变化”。
更麻烦的是信噪比。白天飞机蒙皮被太阳加热,目标与天空背景温差可能还有几度;夜间或阴天,这个温差可能只有零点几度,经过探测器和信号链路后,目标灰度只比背景高几个灰度级,随机噪声都能盖过它。这时候目标看起来不是“亮点”,而是噪点。模型很难天然区分“飞机的像素簇”和“探测器响应波动形成的伪目标”,所以要靠数据集把这种不确定性的边界撑大。
背景杂波是第三重压力。云层边缘、地物棱线、建筑转角都是高频区域,在图像上会形成与飞机尺寸相近的高亮小斑。如果数据集里大量样本都是“飞机出现在干净天空”的理想状态,模型学到的是“亮斑即目标”,一旦遇到复杂地物背景就崩溃。这也是为什么直接拿通用红外数据集来训飞机检测经常翻车——数据集里的“目标”可能是行人、车辆、火焰,背景分布也完全不同。
2.2 选数据集别图省事:公开数据集与自建数据的取舍原则
红外小目标飞机检测数据集的来源通常分两类。一类是学术公开数据集,常见的有 NUAA-SIRST、IRSTD-1k 这类红外小目标检测数据,它们提供了单帧图像和对应的 mask 标注,适合快速验证算法流程。但要注意,这些数据集里很多目标是无人机、导弹、车辆等,飞机占比不一定高;即便含飞机,也多是固定翼或直升机单帧,缺少连续运动信息。你拿来训练前,必须先按类别过一遍标注,把非飞机目标剔除或重新归类,否则模型会把所有红外小亮点都当成飞机。
另一类是自建数据,这也是很多落地项目最终要走的路。常见做法是用长波红外热像仪实地采集机场、航线、近海空域的视频,覆盖不同季节、时段、天气和目标距离。自建数据的核心原则不是“越多越好”,而是“背景和目标状态的覆盖度够”。至少要有三类变化:目标尺度从 3×3 到 30×30 像素的分布、背景从干净天空到复杂地物边缘的分布、信噪比从高到低的分布。单一场景下采集几万帧,不如多场景各采几千帧,因为后者决定模型的泛化边界。
选型时还要避开几个看着相关、实际帮倒忙的数据源。电力红外数据集是巡检电气设备用的,目标和背景都是设备发热区;红外可见光目标检测数据集里大多是行人车辆,尺度偏大;人脸、手势这类红外数据集更是完全偏离。如果你手头只有这些数据,宁可先做合成数据:把真实的飞机红外切片用随机位置、随机亮度、随机噪声叠加到真实天空背景图上,这样能快速补足“干净天空 + 小目标”的基础样本量,再配合少量真实数据微调。
2.3 train 前的数据预处理:抽帧、裁剪、去噪的最小脚本
拿到原始视频后,第一步不是标注,而是把视频变成干净的图像序列。我一般会先抽帧,抽帧间隔要看飞机的角速度。飞机在画面里运动快时,间隔 1 帧取 1 帧;运动慢、背景变化不大时,可以隔 5 帧取 1 帧,避免相邻帧几乎重复,白白增加标注和训练负担。下面这个脚本按步长抽帧,并统一转成灰度 PNG。
import cv2 from pathlib import Path def extract_frames(video_path, output_dir, step=1, resize=None): output_dir = Path(output_dir) output_dir.mkdir(parents=True, exist_ok=True) cap = cv2.VideoCapture(str(video_path)) frame_idx = 0 saved_idx = 0 while True: ret, frame = cap.read() if not ret: break # step 控制抽帧间隔,间隔越大,相邻帧差异越明显 if frame_idx % step == 0: gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) # resize 会让小目标尺度进一步缩小,谨慎使用 if resize is not None: gray = cv2.resize(gray, resize, interpolation=cv2.INTER_AREA) cv2.imwrite(str(output_dir / f"{saved_idx:06d}.png"), gray) saved_idx += 1 frame_idx += 1 cap.release() print(f"total frames: {frame_idx}, saved frames: {saved_idx}")参数说明:step调抽帧密度,对红外飞机检测,我通常从 1 开始试,如果相邻帧目标位移小于 2 个像素,就适当加大步长;resize要慎用,原本 6×6 像素的目标缩到 3×3 以后,标注难度和训练难度都会陡增。如果相机输出的是 14 bit RAW,不要直接按 8 bit PNG 保存,先用设备软件做非均匀校正(NUC)和坏元剔除,再把动态范围映射到 8 bit。常见的做法是取整个视频灰度分布的 1% 和 99% 分位作为上下限做线性拉伸,这样能保留低对比度目标。
预处理还有一个容易忽略的动作:裁掉无效区域。很多红外相机的画面四周有冷反射、坏像素或者非均匀性残留,这些区域的统计特征和正常背景差异很大,如果不裁掉,模型会学习“看到固定位置的暗角就认为没有目标”这种伪特征。我会用一张纯黑或纯白背景的均值图像把固定噪声区域标出来,在训练前用掩膜把边缘区域裁掉,或者直接设置忽略区域。
提示:抽帧后建议随机挑几十张图,把目标位置的灰度值单独统计一下。如果目标和背景的灰度差不足 10(0-255 范围),说明信噪比太低,靠单帧检测很难有稳定效果,后面应该把时序信息纳入推理,而不是继续堆网络深度。
3. 把数据集喂给 YOLO:标注格式转换、序列划分与最小训练命令
3.1 把单点标注和 mask 转成 YOLO 框:一个中心点不够用
红外小目标飞机检测数据集的标注格式比通用检测数据集更不统一。有些公开数据集只给目标中心点坐标,有些给的是像素级 mask,只有少数给的是矩形框。而 YOLO 训练默认需要框标注,格式是class_id x_center y_center width height,其中坐标都归一化到 0 到 1。直接用单点坐标去算 IoU,预测框和标注框之间的交集几乎为零,正样本分配会出问题,损失根本降不下去。
如果你的标注是 mask,用连通域分析转框最稳,见下面脚本:
import numpy as np from skimage import measure def mask_to_yolo(mask_path, img_w, img_h, class_id=0): # 支持 .npy 或 .png 格式的 mask if mask_path.endswith(".npy"): mask = np.load(mask_path) else: mask = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE) > 0 labeled = measure.label(mask, connectivity=2) boxes = [] for region in measure.regionprops(labeled): if region.area < 1: continue minr, minc, maxr, maxc = region.bbox x_center = (minc + maxc) / 2 / img_w y_center = (minr + maxr) / 2 / img_h w = (maxc - minc) / img_w h = (maxr - minr) / img_h boxes.append(f"{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") return boxes如果你手里的标注只有中心点,转框时最忌讳的是统一给一个固定尺寸。飞机在 1 公里和 5 公里距离上的成像尺寸差好几倍,固定 5×5 的框在近距离样本上只盖住目标一部分,在远距离样本上又框进大量背景。我一般会把训练集里所有单点对应的真实目标尺寸聚类,按距离远近分成 2 到 3 组,再给每组设定单独的 half_size 参数。
参数说明:class_id建议先统一为 0,把“飞机”作为一个类别。很多红外小目标数据集里的飞机和无人机在 8×8 像素尺度下肉眼都难区分,强行分多类只会增加标注噪声,训练时模型也会困惑。如果想区分固定翼和旋翼,等单类模型先达到可用的检测率再说。
3.2 按序列切分训练集:防止数据泄漏的划分脚本
这是红外小目标飞机检测数据集 train 过程中最容易踩的坑,也是最容易被忽视的:划分训练集和验证集时,按“帧”随机切,而不是按“序列”切。
红外飞机检测视频连续性强,相邻帧里目标位置只移动几个像素,背景几乎不变。如果同一段视频的帧既出现在训练集又出现在验证集,模型相当于把一部分答案背下来了,验证集分数会虚高。到了真正部署时,换一段新视频、新场景,效果立刻崩盘,这种“高分低能”已经坑过很多人。正确做法是把视频序列视为最小单元,整段序列要么进训练集、要么进验证集、要么进测试集。
import random from pathlib import Path random.seed(42) # 假设每个序列目录下都有 images 子目录 seq_dirs = sorted([p for p in Path("data/sequences").iterdir() if p.is_dir()]) random.shuffle(seq_dirs) n_train = int(len(seq_dirs) * 0.8) n_val = int(len(seq_dirs) * 0.1) train_dirs = seq_dirs[:n_train] val_dirs = seq_dirs[n_train:n_train + n_val] test_dirs = seq_dirs[n_train + n_val:] # 每个 split 保存一个文件列表,供 YOLO 的 data.yaml 引用 for split, dirs in [("train", train_dirs), ("val", val_dirs), ("test", test_dirs)]: out_path = f"{split}.txt" with open(out_path, "w") as f: for seq in dirs: for img in sorted((seq / "images").glob("*.png")): f.write(str(img.resolve()) + "\n")random.seed(42)保证划分可复现;n_val取总量的 10% 看起来不多,但红外序列往往上万帧,10% 已经能反映分布。测试集最好单独保留 10% 到 20%,并且尽量选模型没见过的背景类型,比如训练集都是机场天空,测试集就要有海面和山地区域,否则测试没有说服力。
另外要注意,不同视频序列之间可能存在同一架飞机的重复轨迹,或者同一设备在不同天拍摄的相似背景。如果两个序列高度相似,它们本质上还是同一个序列,划分前要人工筛查一遍,把拍摄时间、地点接近的序列合并成一个逻辑单元。
3.3 用 YOLO11 跑通最小训练:命令与关键参数
数据整理完,就到了真正跑train的环节。近两年大家讨论得比较多的 YOLO11 小目标优化,重点在于检测头和多尺度特征融合,但具体效果好不好,取决于你的数据集匹配度。我推荐先拿yolo11n.pt做一次完整训练,跑通流程后再换更大的模型。
先写数据配置,ir_aircraft.yaml:
path: /path/to/infrared_aircraft train: train.txt val: val.txt names: 0: aircraft注意 YOLO 的train和val既可以写图片目录路径,也可以写txt文件列表。names里的类别名要和标注文件里的class_id对应,当前只有一类飞机,所以是 0 到 aircraft。
然后是最小训练命令:
yolo detect train \ model=yolo11n.pt \ data=ir_aircraft.yaml \ epochs=100 \ imgsz=640 \ batch=16 \ device=0 \ mosaic=0.0参数说明:imgsz=640是默认值,但如果原始红外图像是 640×512,我建议直接传原始短边附近的尺寸,比如imgsz=640,640,不要为了统一尺寸把图缩到 320,否则小目标直接消失。batch=16是否跑得动取决于显存,一般 12 GB 显存可以用 16 配 640;显存不够时优先降 batch,不要降分辨率。
mosaic=0.0是红外小目标训练里一个容易被忽略的关键参数。Mosaic 增强会把四张图拼在一起再缩放,结果原本 8×8 像素的飞机缩到 2×2,模型根本学不到目标特征。我建议第一轮训练就关掉 mosaic,等基线跑完,再慢慢把 mosaic 开到 0.5 试试,如果验证集掉点明显就保持关闭。这个参数不调,很多人会以为模型能力不行,其实是被增强策略坑了。
训练跑完后,先看val损失和P/R曲线,不要急着部署。如果R(召回率)在 0.8 以下,说明模型漏检严重,优先去查数据里的目标尺度分布,而不是加数据;如果P(精确率)低,说明虚警多,下一步要查标注有没有把噪声误标成目标,以及是否缺少复杂背景的负样本。
4. 红外小目标飞机检测训练避坑指南:5 个反复出现的翻车现场
4.1 训练集和验证集来自同一段视频,指标虚高
现象:loss 正常下降,验证集 mAP 超过 0.95,换成一段新拍摄的红外视频直接漏检大半。
原因:这是最常见的数据泄漏。按帧随机划分数据集时,同一段视频中目标位置只差几帧的图片分别进了训练集和验证集。模型记住了这条轨迹附近的背景特征,验证分数自然好看。红外视频单段长度动辄几千帧,帧与帧相似度极高,这种泄漏很难从曲线图上直接发现。
解决:回到 3.2,把序列作为最小不可分割单位重新划分。划分后看一眼每个序列里的目标数量,确保目标总数大致按 8:1:1 分配,而不是序列数量按比例,因为不同序列的目标出现频率可能差十倍。
4.2 Mosaic 增强把小目标缩没了,模型学不到飞机
现象:训练时把mosaic=1.0打开,loss 前几十轮下降很慢,最终验证集 mAP 只有 0.3 左右;换到不带 Mosaic 的版本,mAP 直接翻倍。
原因:YOLO 的 Mosaic 增强在拼图后会做缩放,四张 640×640 的图拼成一张 640×640 的新图,每张图等效变成 320×320。红外小目标原本只有 8×8,经过这轮缩放就变成 4×4,如果再叠加随机裁剪,目标直接缩到 2×2,甚至被当成噪点丢掉。
解决:训练时显式设mosaic=0.0。如果一定要用增强来提升泛化,只保留轻度平移、翻转、对比度扰动。对红外小目标,灰度对比度拉伸比几何增强更有效,因为目标没有稳定纹理,几何变换带来的收益很有限。
4.3 只报 mAP,不报虚警率,测试现场被频繁误报打脸
现象:项目验收时 mAP 达标,一到真实运行环境,系统每分钟报几十个“疑似飞机”,全是地面热源或探测器噪声。
原因:mAP 对置信度阈值不敏感,它统计的是不同阈值下的平均精度,只要存在一个能让精确率和召回率都还不错的阈值区间,mAP 就好看。但红外小目标场景里,虚警和目标的灰度分布高度重叠,无论怎么调阈值,虚警都压不下来。
解决:评估阶段同时统计 PD(检测概率,检测到的真实目标数除以真实目标总数)和 FA(单帧平均虚警数)。给用户看的不只是一条 mAP,而是给定 FA 下的 PD,比如“每 1000 帧虚警不超过 10 次时,检测率 0.92”这种表述。如果 FA 降不下来,优先加时序信息,而不是调 NMS 阈值。
4.4 单点标注训练的模型总是“有目标但框不准”
现象:用中心点标注的数据训 YOLO,训练 loss 能降,但预测框和真实目标位置总是偏半个目标尺寸,测 IoU 时成绩上不去。
原因:单点标注本身没有尺度信息。YOLO 训练时要计算预测框和标注框的 IoU,单点转框时如果给了一个不合理的固定框,比如目标实际是 4×4,你给的是 16×16,模型会被迫学习这个误差,最终输出框偏大且位置偏移。
解决:先统计真实目标尺度。如果没有真实框,就用 mask 转换脚本生成框;如果只有单点,聚类出 2 到 3 个典型框尺寸。另一个选择是换用支持中心点监督的检测头,像一些 anchor-free 结构里可以用高斯热图标签直接监督单点,省去转框的误差。
4.5 红外数据来源单一,换一台相机就失灵
现象:在 A 相机采集的数据上训练效果不错,换到 B 相机的同场景数据,检测率掉了三成。
原因:不同红外相机的探测器响应、非均匀校正参数、增益和灰度映射范围不一样。A 相机的目标灰度可能是 200,B 相机里同类目标只有 120。模型在训练时把“灰度 200 附近”当作目标特征的一部分,遇到灰度范围偏移就失效了。
解决:训练前对所有图像做全局灰度归一化,把每张图的灰度分布映射到统一区间,例如用均值加减标准差做标准化。条件允许的话,把多台相机的数据混合训练,并且保留一小部分为目标域做微调。不要迷信网络结构能自己学会跨域不变性,红外灰度偏移这件事属于数据领域,得从数据侧解决。
5. 从 mAP 好看变成现场好用:评估与提效的三个进阶技巧
5.1 用时序信息做二次确认,虚警率能掉一半
单帧检测器再强,也很难把“真实飞机”和“固定位置的热源噪声”完全分开,因为它们在单帧图像上长得一样。最简单的时序过滤是对同一个目标在连续 N 帧内检测结果做一致性判断:目标位置应连续变化,且尺度不会突然抖动。常见做法是做一个轻量的轨迹管道,把连续 3 到 5 帧中位置变化不超过阈值的检测合并为一次有效报警。这样能滤掉大量随机出现的单帧虚警,几乎不影响真实目标。
5.2 用 PD/FA 曲线替代单点评估
红外小目标检测领域更通用的评估方式是 PD/FA 曲线,而不是只看 mAP。横轴是平均单帧虚警数,纵轴是检测概率。得到最终模型后,把置信度阈值从 0.1 到 0.9 扫一遍,画出一条 PD/FA 曲线,然后根据现场可接受虚警率选定阈值。我习惯把这条曲线连同测试视频的漏检截图一起存档,这样后面调参时能快速看出“提升”到底提升在哪,而不是看一张孤立的 mAP 数。
5.3 训练完先看失败样本,再动网络结构
最后一个技巧是养成先查失败样本的习惯。训练结束后,自动把验证集里漏检和虚警最严重的 50 张图单独导出来,按目标灰度、背景类型、目标尺寸三个维度分组看一眼。很多时候你会发现模型栽在同一个问题上:要么是目标在云层边缘,要么是特定距离段目标太小。定位到问题后,再去决定是补数据、调增强还是改网络,效率远高于盲目试参。
我现在拿到一个红外小目标飞机检测项目,第一件事永远是做数据体检,查序列划分有没有泄漏、目标尺度分布是否合理、灰度范围是否统一,然后才打开训练命令。这套习惯是从一次次翻车里换来的,也帮你避开其中大部分。希望帮到你。
本文还有配套的精品资源,点击获取