简介:本资源为面向红外场景下直升机目标检测的YOLO系列算法训练数据集,适合从事无人机侦察、红外图像识别、军事目标检测等方向的研究人员与算法工程师使用,可解决红外小目标样本稀缺、标注格式不统一的问题。压缩包共1372个文件,包含457张jpg红外图像、457个txt格式YOLO标签、457个xml格式VOC标签以及1个yaml配置文件,整体约21.74MB,两种标注格式分别存放,便于直接接入不同训练框架。数据集已按训练与验证需求划分完毕,标签覆盖类别索引与归一化中心点、宽高信息,可直接用于yolov5、yolov8、yolov9、yolov7、yolov10及yolo11等模型的训练与测试。目前已有129人学习下载,读者可快速获得一套开箱即用的红外直升机检测数据,省去采集与标注成本,将精力集中于模型调参与效果验证。
1. 红外直升机数据集上手:457 张带标签图像能直接跑 YOLO 吗
拿到一个红外直升机数据集,第一反应通常不是“太好了”,而是“这玩意儿能直接训练吗”。这个包给的是 457 张红外图像,文件名像img_0697_8.jpg、img_0697_14.jpg这种,带 YOLO 格式 txt 和 VOC 格式 xml 两套标签,已经划分好训练验证结构。对做 yolo 目标检测的从业者来说,它解决的是“没有红外小目标数据、自己标又费时”的问题,适合想验证 yolov5、yolov8、yolov9、yolov7、yolov10、yolo11 训练链路的人。但 457 张属于小样本,红外图像对比度低、目标边缘糊,直接套默认参数大概率翻车。下面按“先看懂标签、再跑通训练、最后避坑”的顺序拆一遍。
2. 标签格式与目录结构:YOLO txt 和 VOC xml 到底怎么对应
2.1 两种标签的坐标逻辑差异
YOLO 格式一行一个目标,结构是<class> <x_center> <y_center> <width> <height>,后四个值都是相对图像宽高的归一化比例,范围 0 到 1。VOC 格式是 xml,里面xmin/ymin/xmax/ymax是绝对像素坐标,类别用<name>文本表示。同一个目标在两套文件里描述的是同一个框,只是表达方式不同。红外直升机这个数据集里,类别索引从 0 开始,通常只有一个类别,也就是直升机本身。
理解这一点很关键:如果你拿 VOC 的 xml 直接喂给 YOLO 训练脚本,脚本会报解析错误或者把坐标当成归一化值,框会全部跑到图像左上角。反过来,把 YOLO txt 当 VOC 用,坐标会小得几乎看不见。所以第一步永远是确认你用的训练框架吃哪种格式。
2.2 目录结构核对与类别确认
拿到压缩包解压后,常见结构是images/和labels/两个文件夹,或者JPEGImages/和Annotations/。这个数据集摘要里明确说“分别保存在两个文件夹中”,所以先列目录确认。
# 查看解压后的目录层级,确认 images 和 labels 是否成对 find . -maxdepth 2 -type d | sort # 统计图像数量和标签数量,两者应该一致 find ./images -name "*.jpg" | wc -l find ./labels -name "*.txt" | wc -l # 查看一个标签文件内容,确认类别索引和坐标范围 cat ./labels/img_0697_8.txt逻辑说明:find用来确认目录结构,wc -l统计数量,如果图像 457 张而标签只有 400 个,说明有漏标或文件缺失。cat看具体内容,正常一行应该是0 0.512 0.634 0.087 0.121这种,如果看到0 512 634 87 121这种大于 1 的数,说明标签没归一化,需要转换。
参数说明:-maxdepth 2限制递归深度,避免在大数据集上扫太久。类别索引从 0 开始,如果只有直升机一个类,所有行的第一个数字都应该是 0。如果出现 1、2,说明有多类或者标签串了。
2.3 写一个校验脚本把问题提前暴露
在训练之前,我一般会写个小脚本扫一遍所有标签,检查坐标是否越界、类别是否超范围、有没有空文件。
import os import glob label_dir = "./labels" img_dir = "./images" num_classes = 1 # 红外直升机数据集通常只有一类 bad_files = [] for txt_path in glob.glob(os.path.join(label_dir, "*.txt")): with open(txt_path, "r") as f: lines = f.readlines() if len(lines) == 0: bad_files.append((txt_path, "空标签文件")) continue for line in lines: parts = line.strip().split() if len(parts) != 5: bad_files.append((txt_path, "字段数不对")) break cls, x, y, w, h = map(float, parts) if cls >= num_classes: bad_files.append((txt_path, f"类别越界: {cls}")) if not (0 <= x <= 1 and 0 <= y <= 1 and 0 < w <= 1 and 0 < h <= 1): bad_files.append((txt_path, f"坐标越界: {x},{y},{w},{h}")) print(f"问题文件数: {len(bad_files)}") for p, reason in bad_files[:10]: print(p, reason)逻辑说明:遍历所有 txt,逐行拆分,检查字段数、类别索引、坐标范围。空标签文件在目标检测里是合法的负样本,但如果是漏标就要注意。坐标越界通常意味着归一化时除了错误的宽高,或者标注工具导出有问题。
参数说明:num_classes按实际类别数改,这个数据集如果只有直升机就写 1。bad_files[:10]只打印前 10 条,避免刷屏。跑完如果问题文件数为 0,说明标签干净,可以进入训练配置。
3. 训练配置落地:从 data.yaml 到 yolov8 跑通第一个 epoch
3.1 写对 data.yaml 是跑通的前提
YOLO 系列训练都依赖一个 yaml 描述文件,告诉框架图像路径、类别数、类别名。这个数据集已经划分好,常见是train、val两个子目录,或者images/train、images/val。
# data_helicopter.yaml path: ./dataset # 数据集根目录 train: images/train # 训练图像相对路径 val: images/val # 验证图像相对路径 nc: 1 # 类别数,红外直升机只有一类 names: 0: helicopter # 类别名,按实际改逻辑说明:path是根目录,train和val是相对path的路径。YOLO 会自动把images替换成labels去找标签,所以目录命名要规范。nc必须和标签里的最大类别索引加一一致,否则训练时分类头维度对不上。
参数说明:如果数据集结构是train/images和train/labels,那train就写train/images。names的键从 0 开始,和标签里的 class 对应。改完 yaml 先用几行代码验证路径是否存在。
import yaml from pathlib import Path with open("data_helicopter.yaml") as f: cfg = yaml.safe_load(f) root = Path(cfg["path"]) for split in ["train", "val"]: p = root / cfg[split] print(split, p, "存在" if p.exists() else "不存在")逻辑说明:读 yaml,拼路径,检查目录是否存在。这一步能避免训练启动后报No images found这种低级错误。
3.2 用 yolov8 跑通训练并观察红外小目标表现
环境装好 ultralytics 之后,一条命令就能启动。红外图像建议先用较小模型验证链路,别一上来就上大模型。
# 安装 ultralytics,yolov8/yolo11 都用这个包 pip install ultralytics # 启动训练,imgsz 用 640,batch 根据显存调 yolo detect train \ data=data_helicopter.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=16 \ project=runs/helicopter \ name=exp1逻辑说明:model=yolov8n.pt用 nano 版先跑通,红外小目标对模型容量要求没那么高,n 版能快速暴露数据问题。epochs=100对小数据集够用,太多会过拟合。project和name决定输出目录,方便对比多次实验。
参数说明:imgsz=640是常见输入尺寸,红外图像如果原始分辨率低,可以降到 416 或 512。batch=16看显存,8G 显存跑 640 的 n 版一般没问题。如果报显存不足,先降 batch 再降 imgsz。训练日志里重点看mAP50和mAP50-95,红外目标如果 mAP50 长期低于 0.3,多半是标签或增强策略问题。
3.3 验证与推理:确认模型真的学到了直升机
训练完在runs/helicopter/exp1/weights/下会有best.pt和last.pt。用验证集跑一遍,再用单张图看效果。
# 在验证集上评估 yolo detect val \ model=runs/helicopter/exp1/weights/best.pt \ data=data_helicopter.yaml \ imgsz=640 # 单张图像推理并保存结果 yolo detect predict \ model=runs/helicopter/exp1/weights/best.pt \ source=./images/val/img_0697_102.jpg \ save=True \ conf=0.25逻辑说明:val输出各类别 AP,确认模型不是只学会了背景。predict的conf=0.25是置信度阈值,红外目标响应弱,可以适当降到 0.15 看召回,但太低会引入误检。
参数说明:save=True会把带框图像存到runs/detect/predict/。如果框位置明显偏移,回到标签检查那一步。如果框对了但类别错,检查names和标签 class 是否一致。
4. 避坑与排查:红外小目标训练最容易翻车的五件事
4.1 现象:训练 loss 正常下降但 mAP 一直是 0
原因:标签类别索引和data.yaml的names对不上,或者标签文件根本没被读到。YOLO 在找不到标签时会当负样本处理,loss 能降但学不到目标。
解决:用 2.3 的校验脚本扫一遍,再确认labels目录和images目录层级对应。YOLO 找标签的规则是把图像路径里的images替换成labels,扩展名换成.txt,任何一层不对都会静默失败。
4.2 现象:验证集指标忽高忽低,不同 epoch 差异巨大
原因:457 张图像划分后验证集可能只有几十张,样本太少导致指标抖动。红外目标本身对比度低,模型在不同批次间学到的特征不稳定。
解决:用交叉验证或者固定随机种子多跑几次取平均。yolo detect train加seed=42固定种子,deterministic=True减少随机性。如果只是验证链路,不必纠结单次指标。
4.3 现象:推理时框大量重叠或框到背景
原因:红外图像噪声大,默认的 NMS 阈值和置信度阈值不适合。另外训练时用了 mosaic 增强,红外图像拼接后目标更小更难学。
解决:推理时调iou=0.5控制 NMS,conf从 0.25 往上试。训练时对红外数据可以关掉 mosaic,yolo detect train ... mosaic=0.0,让模型看到更多原始尺度目标。
4.4 现象:换到 yolov5 训练报标签格式错误
原因:yolov5 和 yolov8 的目录约定略有差异,yolov5 的data.yaml里train和val通常直接指向图像目录,且对nc和names的写法更严格。
解决:yolov5 的 yaml 写成train: ./images/train、val: ./images/val,nc: 1,names: ['helicopter']。如果还报错,检查 txt 里有没有多余空格或空行,yolov5 对格式更敏感。
4.5 现象:训练到一半显存爆了
原因:batch或imgsz设太大,或者workers太多导致内存泄漏。红外图像虽然小,但 457 张全加载加上增强会占内存。
解决:先降batch到 8 或 4,再降imgsz到 512。workers设成 4 或 8,不要超过 CPU 核数。如果还爆,用cache=False关掉缓存。
5. 进阶技巧:把 457 张红外数据用到极致
小样本红外数据集想提升效果,核心思路是“让每一张图产生更多有效梯度”。我一般会从三个方向下手:增强策略、迁移学习、以及标签格式转换后的多框架验证。
先说增强。红外图像和可见光不同,颜色抖动、HSV 变换基本没用,反而会引入噪声。有效的是随机缩放、平移、水平翻转,以及适度的亮度对比度扰动。在 ultralytics 里可以这样配:
yolo detect train \ data=data_helicopter.yaml \ model=yolov8n.pt \ epochs=150 \ imgsz=640 \ batch=8 \ hsv_h=0.0 hsv_s=0.0 hsv_v=0.2 \ degrees=0.0 translate=0.1 scale=0.5 \ fliplr=0.5 mosaic=0.0 \ project=runs/helicopter \ name=exp2_ir逻辑说明:hsv_h和hsv_s关掉,只留hsv_v=0.2做亮度扰动,模拟红外成像的温差变化。mosaic=0.0关掉拼接,避免小目标被进一步缩小。scale=0.5允许目标在 0.5 到 1.5 倍之间缩放,增加尺度多样性。
参数说明:degrees=0.0不做旋转,红外目标旋转后边缘更糊。translate=0.1小幅平移,防止目标总在中心。这些参数不是绝对的,如果验证集 mAP 有提升就保留,掉了就回退。
再说迁移学习。直接用 COCO 预训练的yolov8n.pt比从头训好,因为底层边缘特征通用。如果红外目标和可见光差异太大,可以先在更大的红外数据集上预训练,再拿这个 457 张微调。没有大红外数据的话,冻结 backbone 前几层训练几轮再解冻,也能稳住。
最后是格式转换验证。这个数据集同时给了 YOLO txt 和 VOC xml,可以写个脚本互转,用同一批图像在不同框架上跑,对比指标。比如把 xml 转成 txt 喂给 yolov5,把 txt 转成 xml 喂给 MMDetection,看哪套链路对这个红外数据更友好。转换时注意 VOC 的xmax/ymax是包含边界的,转 YOLO 时w = (xmax - xmin) / img_w,别多算一个像素。
import xml.etree.ElementTree as ET from PIL import Image def voc_to_yolo(xml_path, img_path, class_map): tree = ET.parse(xml_path) root = tree.getroot() img = Image.open(img_path) iw, ih = img.size lines = [] for obj in root.findall("object"): name = obj.find("name").text cls = class_map[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) xc = (xmin + xmax) / 2 / iw yc = (ymin + ymax) / 2 / ih w = (xmax - xmin) / iw h = (ymax - ymin) / ih lines.append(f"{cls} {xc:.6f} {yc:.6f} {w:.6f} {h:.6f}") return lines逻辑说明:解析 xml,读图像尺寸,把绝对坐标转成归一化中心点加宽高。class_map把类别名映射成索引,保证和data.yaml一致。输出保留 6 位小数,避免精度损失。
参数说明:xmax - xmin就是框宽,不用加一,VOC 的坐标是像素索引,直接相减即可。如果转换后框偏移一个像素,检查图像尺寸是否读对,有些 jpg 带 EXIF 旋转信息,PIL 读出来可能和标注时不一致。
从那以后我每次拿到新数据集,都强制走一遍“数量核对 → 标签校验 → 单张可视化 → 小模型试跑”这四步,确认没问题再上大模型和长训练。红外直升机这个包结构清晰、双格式标签省事,457 张虽然不多,但用来验证 YOLO 训练链路、调增强参数、对比不同版本表现完全够用。希望帮到你。
本文还有配套的精品资源,点击获取