
简介飞机型号识别数据集04面向从事目标检测、图像分类与军机识别的算法研究者与深度学习开发者采集自俄罗斯机场覆盖苏霍伊、米格、安东诺夫、伊尔、雅克、图波列夫等47种军民飞机可用于模型训练、算法对比与迁移学习实验。资源包共2001个文件含1000张1024×768可见光RGB图像、1000个labelimg标注的xml标签文件及1个说明txt压缩包约250.43MB图像与标签一一对应可直接接入YOLO、Faster R-CNN等检测框架。目前已有219人学习下载。该批次与02、03、05等批次采集地点和飞机种类各不相同适合作为多场景数据补充帮助读者快速构建飞机检测与型号分类训练集省去自行采集与标注成本并可通过多批次组合提升模型泛化能力。1. 拆开一批俄罗斯机场拍回来的飞机型号识别数据集47 类、1000 张、XML 标签如果你正在找一份能直接跑目标检测的飞机型号识别数据集又不想从零爬图、标框、清洗那这批 RUS-04 值得先看一眼。它采集自俄罗斯机场可见光 RGB 图像1024×768 分辨率共 1000 张标注用 labelimg 完成输出标准 XMLPascal VOC 格式。分类覆盖 47 种军民飞机苏霍伊、米格、安东诺夫、伊尔、雅克、图波列夫这些系列都在里面。适合做飞机目标检测、军机识别、细粒度分类的算法验证也适合拿来做 YOLO 系列训练的第一份真实数据。注意它只是 04 批采集地点和类别跟 02、03、05 批都不一样别默认能直接合并。2. 先搞懂 XML 标注结构为什么这批数据能直接喂给 YOLO2.1 Pascal VOC XML 的字段含义与飞机检测的对应关系这批数据用的是 labelimg 默认输出每张图对应一个同名 XML。XML 里最关键的几个字段filename是图片名size记录宽高和通道数object下面挂name类别名、pose、truncated、difficult以及bndbox的xmin/ymin/xmax/ymax。对飞机检测来说name就是型号标签bndbox是机体外接矩形truncated和difficult决定了训练时要不要降权或过滤。我一般先抽一张 XML 看结构确认坐标是左上-右下还是别的顺序。飞机在停机坪上经常出现机翼被遮挡、尾翼出画的情况truncated1的框如果直接当正样本模型会学到不完整的机体特征。常见做法是训练时保留但降低损失权重或者评估时单独统计这类样本的召回。annotation folderRUS-04/folder filenameRUS-04-0384.jpg/filename size width1024/width height768/height depth3/depth /size object nameSu-27/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin212/xmin ymin305/ymin xmax689/xmax ymax512/ymax /bndbox /object /annotation上面这段里name是型号字符串bndbox四个值都是像素坐标原点在左上角。depth3说明是 RGB 三通道跟摘要里说的可见光色彩一致。truncated和difficult都是 0表示这个目标完整且不困难。实际跑之前建议先统计一遍这两个字段的分布如果difficult1占比超过 15%就要考虑在数据加载阶段做过滤或重采样。2.2 47 类标签的命名规范与合并策略47 个类别里既有苏霍伊、米格这种系列名也可能出现具体型号如 Su-27、MiG-29。命名不统一是这类多批次数据集的通病。如果你只做“军机 vs 民航”二分类可以把所有标签映射成两个大类如果做型号识别就要保留原始name但得先跑一遍全量标签统计看看有没有拼写变体或大小写不一致。import os import xml.etree.ElementTree as ET from collections import Counter label_dir RUS-04/annotations counter Counter() for xml_file in os.listdir(label_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(label_dir, xml_file)) for obj in tree.findall(object): name obj.find(name).text.strip() counter[name] 1 for name, count in counter.most_common(): print(f{name}: {count})这段脚本遍历所有 XML统计每个类别名出现的次数。ET.parse逐文件解析findall(object)拿到所有目标find(name).text取标签并去空格。跑完你会得到一张类别频次表长尾类别如果少于 20 个框训练时要么做过采样要么直接归并到相近系列。我一般会把频次低于 30 的类别先列出来人工确认是不是标注漏标或拼写错误再决定合并还是保留。3. 把 XML 转成 YOLO 格式转换脚本与四个边界坑3.1 坐标归一化与类别映射的完整转换代码YOLO 训练需要每张图一个.txt每行class_id x_center y_center width height全部归一化到 0~1。转换时最容易翻车的是坐标越界和类别 ID 对不上。下面这个脚本把 XML 转成 YOLO 格式同时生成classes.txt和data.yaml。import os import xml.etree.ElementTree as ET xml_dir RUS-04/annotations img_dir RUS-04/images out_dir RUS-04/labels os.makedirs(out_dir, exist_okTrue) # 先收集所有类别固定顺序 classes sorted({obj.find(name).text.strip() for f in os.listdir(xml_dir) if f.endswith(.xml) for obj in ET.parse(os.path.join(xml_dir, f)).findall(object)}) class_to_id {c: i for i, c in enumerate(classes)} with open(classes.txt, w) as f: f.write(\n.join(classes)) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, xml_file)) root tree.getroot() w int(root.find(size/width).text) h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text.strip() cls_id class_to_id[name] box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 裁剪到图像边界防止越界 xmin, ymin max(0, xmin), max(0, ymin) xmax, ymax min(w, xmax), min(h, ymax) xc (xmin xmax) / 2 / w yc (ymin ymax) / 2 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) txt_name os.path.splitext(xml_file)[0] .txt with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(lines))逻辑上分三步先扫全量 XML 建立类别到 ID 的固定映射保证训练和推理一致再逐图解析宽高和目标框最后做边界裁剪和归一化。max(0, xmin)和min(w, xmax)这两行是后悔药飞机贴边时标注框可能超出图像范围不裁的话 YOLO 会报坐标越界。归一化用.6f保留六位小数足够精度又不会让文件膨胀。3.2 data.yaml 的路径写法与类别数校验转换完标签下一步是写data.yaml。YOLOv5/v8/v11 都认这个格式关键是path、train、val三个路径要写对nc必须等于classes.txt的行数。path: /data/RUS-04 train: images/train val: images/val nc: 47 names: 0: An-2 1: An-24 2: An-26 # ... 其余类别按 classes.txt 顺序补齐path是数据集根目录train和val是相对路径。常见错误是nc写成 46 或 48训练时直接报维度不匹配。跑之前用一行命令校验len(open(classes.txt).readlines())应该等于nc。另外names的顺序必须和转换脚本里class_to_id完全一致否则模型学到的类别会整体错位这种错误在验证集上表现为准确率极低但损失正常下降属于典型的黑匣子问题。3.3 训练集/验证集划分别让同一架飞机同时出现在两边这批数据是机场连续拍摄同一架飞机可能出现在多张图里只是角度或距离不同。如果随机按 8:2 划分训练集和验证集里会有同一架飞机的不同视角验证指标会虚高。我一般按filename前缀或拍摄批次分组划分保证同一组只进一边。import os import random import shutil random.seed(42) img_dir RUS-04/images train_dir RUS-04/images/train val_dir RUS-04/images/val os.makedirs(train_dir, exist_okTrue) os.makedirs(val_dir, exist_okTrue) files sorted([f for f in os.listdir(img_dir) if f.endswith(.jpg)]) # 按文件名前缀分组这里假设前 8 位是拍摄组 groups {} for f in files: key f[:8] groups.setdefault(key, []).append(f) keys list(groups.keys()) random.shuffle(keys) split int(len(keys) * 0.8) train_keys set(keys[:split]) for f in files: dst train_dir if f[:8] in train_keys else val_dir shutil.copy(os.path.join(img_dir, f), os.path.join(dst, f))f[:8]是假设文件名前缀能代表拍摄组实际用之前先看一眼文件名规律。random.seed(42)保证可复现。划分完记得把对应的.txt也复制到labels/train和labels/valYOLO 默认按同名文件找标签。如果验证集 mAP 比训练集低很多先检查是不是划分泄漏而不是急着调模型。4. 避坑与排查飞机检测训练里最容易翻车的五件事4.1 现象训练 loss 正常下降但 mAP 一直为 0原因通常是类别 ID 错位或data.yaml的names顺序和标签文件不一致。解决用classes.txt逐行比对names再抽一个.txt标签确认class_id对应的类别名是否正确。我遇到过nc47但names只写了 46 个的情况YOLO 不报错但训练结果全乱。4.2 现象验证集图片加载报 “corrupt image”这批图是 1024×768 的 JPG正常不会损坏。但如果复制过程中断或者路径里有中文和空格OpenCV 可能读失败。解决用cv2.imread批量扫一遍把返回None的文件列出来重新拷贝。路径统一用英文别在data.yaml里写带空格的绝对路径。4.3 现象小目标飞机召回率极低机场远景图里飞机可能只占几十个像素。YOLO 默认下采样到 32 倍小目标特征容易丢。解决把imgsz从 640 提到 1024 或 1280同时开mosaic增强如果显存不够用rect训练减少填充。另外检查标注框有没有小于 8×8 像素的这种框建议直接过滤。4.4 现象同一型号被拆成多个类别47 类里可能有Su-27和Su-27UB这种细分类标注时不同人写法不一致。解决跑一遍 2.2 的统计脚本把频次低于 30 且名称相近的类别合并。合并后重新生成classes.txt和标签别在训练中途改类别数。4.5 现象GPU 利用率低、训练速度慢常见原因是workers设太小或数据放在机械盘。解决workers设成 CPU 核数的 0.7 倍左右数据放到 SSD。另外 XML 转 YOLO 后标签文件很小但图片是 1024×768如果cache设为ram会吃内存1000 张图大约占 2~3 GB内存不够就用disk。5. 进阶验证用混淆矩阵和单图推理确认 47 类到底学没学会训练跑完不能只看 mAP得落到具体型号上。我一般做两件事一是跑混淆矩阵看哪些系列之间容易混二是抽几张验证集图片做单图推理肉眼确认框和标签。yolo detect val modelruns/detect/train/weights/best.pt datadata.yaml imgsz1024 conf0.25 iou0.5conf0.25是置信度阈值iou0.5是 NMS 的 IoU 阈值。跑完会在runs/detect/val下生成混淆矩阵和 PR 曲线。苏霍伊和米格系列外形接近混淆矩阵里如果这两类互相误判多说明特征区分度不够可以考虑加分类头或换更大的 backbone。单图推理用下面这行yolo detect predict modelruns/detect/train/weights/best.pt sourceRUS-04/images/val/RUS-04-0384.jpg imgsz1024 saveTruesaveTrue会把带框的图存到runs/detect/predict。打开图看框有没有漏、标签有没有错。我习惯抽 10 张不同型号的图逐张核对尤其是truncated1的目标看模型有没有把半个机体也框出来。验证项命令/文件合格标准类别数一致classes.txt行数 vsdata.yaml的nc完全相等标签坐标范围抽查.txt每行后四位全部在 0~1 之间验证集 mAP0.5yolo detect val输出按任务定型号识别一般 0.6混淆矩阵runs/detect/val/confusion_matrix.png主要系列之间不大量互混单图推理yolo detect predict框位置和标签肉眼正确从那以后我每次拿到新一批飞机数据都强制走一遍“统计标签 → 转换 → 校验 nc → 分组划分 → 单图推理”这条链路少一步后面就得花更多时间排查。希望帮到你。本文还有配套的精品资源点击获取