7559张红外微小目标检测数据集:VOC转YOLO与YOLOv8训练实战
发布时间:2026/10/1 23:53:20 锦皓数字建站

简介这份红外微小目标检测数据集面向无人机、直升机、飞机与飞鸟识别方向的算法开发者与科研人员适用于红外场景下的目标检测模型训练、微调与对比实验。数据同时提供Pascal VOC与YOLO两种标注格式jpg图片与对应的xml、txt标注文件一一对应可直接接入主流检测框架省去格式转换环节。压缩包共约2000个文件以1999个xml标注文件和1个说明用txt为主整体约175.53MB采用7z格式打包便于一次性获取与本地解压管理。数据集共7559张红外图像标注类别为Airplane、Bird、Drone、Helicopter四类总框数7858个其中Drone框数最多达4242个Bird、Helicopter、Airplane分别为1214、1431和971个类别分布清晰适合开展小目标与多类别检测研究。目前已有1122人学习下载可作为红外弱小目标检测课题的可靠数据基础。1. 7559 张红外微小目标检测数据集从 VOC 到 YOLO 的落地路径拿到一个标注好的红外微小目标数据集第一反应往往不是兴奋而是怀疑——7559 张里有多少是真正可用的4 个类别无人机、直升机、飞机、飞鸟在红外波段下的对比度极低目标像素常常只有个位数标注框稍微偏一点训练出来的模型就全是误检。这个数据集以 VOC 和 YOLO 双格式打包意味着你可以跳过最耗时的标注环节直接进入模型训练和调参。它适合两类人一是做低空安防、机场净空监测的算法工程师需要快速验证红外小目标检测方案二是研究无人机视觉感知的学生想找一个规模适中、类别清晰的基准数据集跑通全流程。核心痛点在于红外图像的信噪比远低于可见光VOC 的 XML 标注转成 YOLO 的 txt 格式时坐标归一化和类别映射稍有差池整个训练就变成玄学。下面从数据解构、格式转换、训练配置到避坑把这条链路拆开讲清楚。2. 红外微小目标的数据特性与 VOC/YOLO 双格式拆解2.1 红外波段下 4 类目标的成像差异红外成像依赖目标与背景的温差无人机和直升机通常有电机或发动机热源在图像中表现为亮斑飞机在巡航高度时机体与天空背景的温差可能只有几度目标边缘模糊飞鸟的体温虽然高于环境但羽毛隔热导致红外特征不稳定经常出现时隐时现的情况。这 4 个类别在红外域的可分性并不均匀——无人机和直升机的热特征最明显飞机次之飞鸟最难。7559 张图像覆盖了不同季节、不同时段和不同背景天空、云层、地面杂波但类别分布未必均衡。拿到数据后第一件事是统计各类别的样本数和目标像素面积分布如果飞鸟类样本过少或目标面积普遍小于 10×10 像素后续训练需要针对性做数据增强。常见做法是用脚本遍历 VOC 的 Annotations 目录解析每个 XML 中的 object 标签统计类别名和 bndbox 的宽高。下面这段代码可以直接跑import os import xml.etree.ElementTree as ET from collections import Counter ann_dir VOC2007/Annotations cls_counter Counter() size_list [] for xml_file in os.listdir(ann_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(ann_dir, xml_file)) root tree.getroot() for obj in root.findall(object): cls_name obj.find(name).text cls_counter[cls_name] 1 bbox obj.find(bndbox) w float(bbox.find(xmax).text) - float(bbox.find(xmin).text) h float(bbox.find(ymax).text) - float(bbox.find(ymin).text) size_list.append((cls_name, w, h)) print(类别分布:, cls_counter) # 按类别统计目标像素面积 for cls in cls_counter: areas [w * h for name, w, h in size_list if name cls] if areas: print(f{cls}: 平均面积 {sum(areas)/len(areas):.1f}, 最小 {min(areas):.1f}, 最大 {max(areas):.1f})这段代码的逻辑很直接遍历所有 XML提取类别名和边界框坐标计算宽高和面积。参数上唯一需要注意的是VOC2007/Annotations这个路径如果你的目录结构是VOCdevkit/VOC2007/Annotations要相应调整。跑完之后你会得到一张类别分布表如果某个类别的目标平均面积低于 100 像素说明属于微小目标范畴训练时 anchor 尺寸要调小否则召回率上不去。2.2 VOC 与 YOLO 格式的坐标映射关系VOC 的标注是绝对坐标(xmin, ymin, xmax, ymax)YOLO 需要的是归一化后的中心点坐标和宽高(x_center, y_center, width, height)且所有值除以图像宽高。转换公式看起来简单但有两个容易翻车的地方一是图像尺寸必须从对应的 JPEGImages 里读取不能硬编码二是类别索引要从 0 开始连续编号如果 VOC 里的类别名有大小写不一致或空格映射就会错位。7559 张图像如果手动转几乎必然出错必须用脚本批量处理。import os import xml.etree.ElementTree as ET from PIL import Image voc_img_dir VOC2007/JPEGImages voc_ann_dir VOC2007/Annotations yolo_label_dir labels os.makedirs(yolo_label_dir, exist_okTrue) # 类别映射必须与训练时的 data.yaml 一致 classes [drone, helicopter, airplane, bird] cls_to_id {name: i for i, name in enumerate(classes)} for xml_file in os.listdir(voc_ann_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(voc_ann_dir, xml_file)) root tree.getroot() img_name root.find(filename).text img_path os.path.join(voc_img_dir, img_name) if not os.path.exists(img_path): print(f缺失图像: {img_name}) continue with Image.open(img_path) as im: img_w, img_h im.size lines [] for obj in root.findall(object): cls_name obj.find(name).text.strip().lower() if cls_name not in cls_to_id: print(f未知类别: {cls_name} in {xml_file}) continue cls_id cls_to_id[cls_name] bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 归一化并裁剪到 [0,1] x_center max(0, min(1, (xmin xmax) / 2 / img_w)) y_center max(0, min(1, (ymin ymax) / 2 / img_h)) w max(0, min(1, (xmax - xmin) / img_w)) h max(0, min(1, (ymax - ymin) / img_h)) lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) txt_name os.path.splitext(xml_file)[0] .txt with open(os.path.join(yolo_label_dir, txt_name), w) as f: f.write(\n.join(lines))逻辑说明先建立类别名到 ID 的映射然后逐个解析 XML读取对应图像的宽高做归一化。关键参数是classes列表的顺序必须和后续 YOLO 训练配置文件里的names完全一致否则模型学到的类别会张冠李戴。归一化后的坐标用 6 位小数足够再多是浪费存储。如果遇到xmin xmax或坐标越界的情况代码里用max(0, min(1, ...))做了裁剪但更好的做法是提前检查并记录这些异常标注因为越界框往往意味着标注错误直接裁剪会引入噪声。2.3 数据集划分与 YOLO 目录结构转换完成后需要按比例划分训练集、验证集和测试集。常见做法是 7:2:1 或 8:1:1但对于 7559 张的规模如果某些类别样本偏少建议用分层抽样保证每个子集的类别分布一致。YOLO 格式的目录结构通常是images/train、images/val、labels/train、labels/val图像和标签文件名一一对应。下面是一个划分脚本的片段import random import shutil from sklearn.model_selection import train_test_split all_files [os.path.splitext(f)[0] for f in os.listdir(yolo_label_dir) if f.endswith(.txt)] train_val, test train_test_split(all_files, test_size0.1, random_state42) train, val train_test_split(train_val, test_size0.2, random_state42) for split, files in [(train, train), (val, val), (test, test)]: os.makedirs(fimages/{split}, exist_okTrue) os.makedirs(flabels/{split}, exist_okTrue) for name in files: shutil.copy(os.path.join(voc_img_dir, name .jpg), fimages/{split}/{name}.jpg) shutil.copy(os.path.join(yolo_label_dir, name .txt), flabels/{split}/{name}.txt)这里用train_test_split做了两次划分先分测试集再分验证集。random_state42保证可复现。注意图像扩展名可能是.jpg也可能是.png需要根据实际数据调整。划分完成后检查每个子集的标签文件数量是否与图像数量一致缺失标签的图像在训练时会被跳过但最好提前清理。3. 用 YOLOv8 跑通红外微小目标检测的训练配置3.1 环境搭建与 data.yaml 的关键字段YOLOv8 是目前落地最顺手的选择安装命令不复杂但红外小目标对版本敏感建议锁定 ultralytics 的稳定版本。下面是一套经过验证的环境配置conda create -n ir_detect python3.10 -y conda activate ir_detect pip install ultralytics8.1.0 opencv-python pillow scikit-learn安装完成后在项目根目录创建data.yaml这是 YOLO 训练的数据入口。字段必须包含path、train、val、nc、names。path是数据集根目录train和val是相对于path的图像目录。nc是类别数这里是 4。names的顺序必须与转换脚本里的classes完全一致。path: /home/user/ir_dataset train: images/train val: images/val test: images/test nc: 4 names: 0: drone 1: helicopter 2: airplane 3: bird一个常见的翻车点是path用了相对路径而训练时的工作目录变了导致找不到图像。建议用绝对路径或者确保在data.yaml所在目录执行训练命令。另外如果图像和标签不在同一级目录YOLO 会默认在images同级找labels目录结构要严格对应。3.2 针对微小目标的 anchor 与输入尺寸调整YOLOv8 默认的 anchor 尺寸是基于 COCO 数据集设计的最小 anchor 对应 8×8 像素的目标。红外微小目标经常只有 4×4 甚至更小默认 anchor 会导致正样本匹配不足召回率极低。解决办法有两个一是增大输入分辨率比如从 640 提到 1024 或 1280让目标在特征图上占据更多像素二是用 k-means 重新聚类 anchor但 YOLOv8 是 anchor-free 的所以更直接的方式是调整imgsz和reg_max参数。from ultralytics import YOLO model YOLO(yolov8s.pt) results model.train( datadata.yaml, epochs150, imgsz1024, batch8, device0, workers4, optimizerAdamW, lr00.001, lrf0.01, warmup_epochs5, box7.5, cls0.5, dfl1.5, patience30, save_period10, projectir_drone_runs, nameexp1 )参数说明imgsz1024是红外小目标的关键640 下很多目标只剩 2-3 个像素特征提取网络很难学到有效特征。batch8是因为 1024 分辨率下显存占用大如果显卡是 24G 可以提到 16。box7.5提高了边界框回归的损失权重因为小目标的定位误差对 IoU 影响更大。cls0.5是分类损失权重红外图像中类别间差异小不需要过高的分类权重。patience30是早停轮数如果 30 轮验证集指标不提升就停止避免过拟合。optimizerAdamW在小数据集上比 SGD 收敛更稳但最终精度可能略低如果追求极致可以换 SGD 并调低学习率。3.3 训练过程监控与指标解读训练启动后YOLO 会在ir_drone_runs/exp1下生成results.csv和权重文件。重点看三个指标metrics/mAP50、metrics/mAP50-95和val/box_loss。红外小目标的 mAP50 能到 0.6 以上就算不错mAP50-95 通常只有 0.3-0.4因为小目标的 IoU 对位置偏移极其敏感。如果val/box_loss持续下降但mAP50不涨说明模型在过拟合训练集的标注噪声需要检查标注质量或增加数据增强。常见做法是在训练时开启plotsTrueYOLO 会自动生成混淆矩阵和 PR 曲线。混淆矩阵能直观看出哪两个类别容易混——无人机和飞鸟在红外域经常互相误检因为两者的热特征在远距离下都表现为小亮斑。如果混淆严重可以考虑合并类别或增加更多飞鸟样本。PR 曲线则能帮你选择最佳置信度阈值红外小目标的置信度普遍偏低默认的 0.25 可能漏检很多需要根据曲线下调到 0.1 左右再测试。4. 红外小目标检测的避坑与排查清单4.1 标注框偏移导致的训练崩溃现象训练 loss 正常下降但验证集 mAP 始终在 0.1 以下推理时框的位置明显偏离目标。原因VOC 转 YOLO 时坐标归一化用错了图像尺寸比如用了缩略图的尺寸而不是原图或者 XML 里的size字段与实际图像不一致。解决在转换脚本里强制用PIL.Image.open读取实际图像宽高不要信任 XML 里的width和height字段。转换完成后随机抽 20 张图像用 OpenCV 把 YOLO 标签画出来目视检查确认框贴合目标。4.2 类别映射错位引发的“张冠李戴”现象模型把无人机识别成飞鸟或者直升机识别成飞机混淆矩阵中特定类别对严重交叉。原因data.yaml里的names顺序与转换脚本里的classes列表不一致比如脚本里是[drone, helicopter, airplane, bird]而 yaml 里写成了[bird, drone, helicopter, airplane]。解决把类别列表单独写在一个 Python 文件里转换脚本和 yaml 生成脚本都从这个文件导入杜绝手写不一致。训练前用model.names打印类别顺序与标注文件里的 ID 逐一核对。4.3 小目标被下采样吞掉的召回率陷阱现象大目标检测正常但小于 8×8 像素的目标几乎全部漏检召回率低于 0.3。原因YOLO 的 FPN 结构在 P3 层stride 8输出特征图640 输入下 8×8 目标只占 1 个格子1024 输入下占 1.5 个格子仍然偏小。解决把imgsz提到 1280 或 1536同时把reg_max从默认的 16 调到 8让回归分支更关注小偏移。如果显存不够可以用切片推理SAHI把大图切成小图分别检测再合并但训练时仍建议用大分辨率。4.4 红外图像对比度低造成的验证集波动现象同一模型在不同验证集划分下 mAP 波动超过 0.1训练过程 loss 震荡剧烈。原因红外图像的信噪比低某些子集恰好包含大量低对比度样本导致验证指标不稳定。解决用分层抽样代替随机划分确保每个子集的类别分布和亮度分布一致。训练时加入hsv_v增强但红外图像没有色彩信息应该用hsv_v的亮度通道做随机缩放范围设 0.3-0.5模拟不同温差条件。另外mosaic增强对小目标有帮助但红外图像拼接后背景不连续可能引入伪影建议mosaic0.5而不是默认的 1.0。4.5 数据泄露导致的“虚假高精度”现象测试集 mAP 异常高达到 0.9 以上但实际部署时效果很差。原因划分数据集时没有按图像来源分组同一段视频的连续帧被分到了训练集和测试集模型记住了背景而不是目标。解决如果数据来自视频抽帧必须按视频片段划分同一片段的帧只能出现在一个子集中。检查方法是计算训练集和测试集图像的感知哈希如果存在大量相似图像说明划分有问题。7559 张里如果有连续帧建议先做去重或按时间戳分组再划分。5. 从 7559 张到产线模型提升红外小目标召回率的三个技巧第一个技巧是标签平滑与软标签。红外小目标的标注框本身存在 1-2 像素的模糊边界硬标签会让模型对边界过于自信。在 YOLOv8 的损失函数里可以把label_smoothing设为 0.05让分类目标不再是 0/1 而是 0.025/0.975模型对模糊边界的容忍度更高。实测在飞鸟类上召回率能提升 3-5 个百分点。第二个技巧是测试时增强TTA。推理时把图像水平翻转、垂直翻转和多尺度缩放各跑一次把检测框做 NMS 融合。YOLOv8 内置了augmentTrue参数但默认只做水平翻转。对于红外小目标多尺度 TTA 更有效——把图像缩放到 0.8、1.0、1.2 三个尺度分别推理小目标在某个尺度下可能刚好落在特征图的响应峰值上。代价是推理速度降到 1/3适合离线分析场景。第三个技巧是难例挖掘与增量训练。第一轮训练完成后用模型在训练集上推理把置信度低于 0.3 但 IoU 大于 0.5 的样本挑出来这些是模型“看到了但不确定”的难例。把这些难例复制 3-5 份加入训练集重新训练 50 轮。注意不要复制太多否则过拟合难例。我一般会控制难例在总样本的 10% 以内。这个流程跑两轮mAP50 通常能从 0.6 提到 0.7 左右。最后说一个我踩过的坑红外数据集的 7z 压缩包解压后文件名可能包含中文或空格YOLO 的 dataloader 在某些系统上会报编码错误。我现在的习惯是解压后先跑一遍重命名脚本把所有文件名改成纯英文数字下划线标签文件同步改名。这个操作花不了几分钟但能省掉后面排查编码问题的一两个小时。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。