多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

红外小目标飞机检测数据集构建与YOLO训练实战指南

红外小目标飞机检测数据集构建与YOLO训练实战指南 简介面向红外小目标飞机检测场景的训练数据集适合计算机视觉初学者与算法工程师用于目标检测模型的训练与验证。资源按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, step1, resizeNone): output_dir Path(output_dir) output_dir.mkdir(parentsTrue, exist_okTrue) 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, interpolationcv2.INTER_AREA) cv2.imwrite(str(output_dir / f{saved_idx:06d}.png), gray) saved_idx 1 frame_idx 1 cap.release() print(ftotal 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% 分位作为上下限做线性拉伸这样能保留低对比度目标。预处理还有一个容易忽略的动作裁掉无效区域。很多红外相机的画面四周有冷反射、坏像素或者非均匀性残留这些区域的统计特征和正常背景差异很大如果不裁掉模型会学习“看到固定位置的暗角就认为没有目标”这种伪特征。我会用一张纯黑或纯白背景的均值图像把固定噪声区域标出来在训练前用掩膜把边缘区域裁掉或者直接设置忽略区域。提示抽帧后建议随机挑几十张图把目标位置的灰度值单独统计一下。如果目标和背景的灰度差不足 100-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_id0): # 支持 .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, connectivity2) 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.yamlpath: /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 \ modelyolo11n.pt \ datair_aircraft.yaml \ epochs100 \ imgsz640 \ batch16 \ device0 \ mosaic0.0参数说明imgsz640是默认值但如果原始红外图像是 640×512我建议直接传原始短边附近的尺寸比如imgsz640,640不要为了统一尺寸把图缩到 320否则小目标直接消失。batch16是否跑得动取决于显存一般 12 GB 显存可以用 16 配 640显存不够时优先降 batch不要降分辨率。mosaic0.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 增强把小目标缩没了模型学不到飞机现象训练时把mosaic1.0打开loss 前几十轮下降很慢最终验证集 mAP 只有 0.3 左右换到不带 Mosaic 的版本mAP 直接翻倍。原因YOLO 的 Mosaic 增强在拼图后会做缩放四张 640×640 的图拼成一张 640×640 的新图每张图等效变成 320×320。红外小目标原本只有 8×8经过这轮缩放就变成 4×4如果再叠加随机裁剪目标直接缩到 2×2甚至被当成噪点丢掉。解决训练时显式设mosaic0.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 相机的目标灰度可能是 200B 相机里同类目标只有 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 张图单独导出来按目标灰度、背景类型、目标尺寸三个维度分组看一眼。很多时候你会发现模型栽在同一个问题上要么是目标在云层边缘要么是特定距离段目标太小。定位到问题后再去决定是补数据、调增强还是改网络效率远高于盲目试参。我现在拿到一个红外小目标飞机检测项目第一件事永远是做数据体检查序列划分有没有泄漏、目标尺度分布是否合理、灰度范围是否统一然后才打开训练命令。这套习惯是从一次次翻车里换来的也帮你避开其中大部分。希望帮到你。本文还有配套的精品资源点击获取
返回列表