简介:这份飞机型号识别数据集(05)面向从事目标检测、图像分类与军机识别研究的算法工程师、高校师生及竞赛选手,采集自俄罗斯机场,覆盖苏霍伊、米格、安东诺夫、伊尔、雅克、图波列夫等34类军民飞机,可用于训练与验证飞机型号分类及目标检测模型。资源包共2001个文件,包含1000张jpg可见光RGB图像、1000个xml标注文件及1个说明txt,图像尺寸统一为1024x768,标注由labelimg工具生成,压缩包约174.46MB,目录结构清晰,便于直接接入YOLO、Faster R-CNN等主流框架。目前已有593人学习下载。读者可借此获得一批地域与机型分布明确的真实机场样本,用于模型训练、类别平衡分析与跨批次泛化对比;xml标签可直接转换为VOC或COCO格式,节省标注成本。需注意该系列各批次采集地点与机型不同,如需更多样本可下载02、03、04等批次,本数据仅限算法研究使用。
1. 从一批俄罗斯机场实拍图说起:这套飞机型号识别数据集到底能干什么
如果你正在做目标检测或者细粒度分类,手里却没有一批像样的飞机数据,大概率会卡在同一个地方:公开数据集要么类别太粗(只有“飞机”一个大类),要么场景太单一(全是蓝天背景的客机),模型训出来换个机场就崩。这套飞机型号识别数据集(05)解决的就是这个问题——它是一批采集自俄罗斯机场的可见光实拍图,共1000张,尺寸统一为1024×768,覆盖34种军民机型,从苏霍伊、米格到安东诺夫、伊尔、雅克、图波列夫都有。标签用labelimg标注,格式为xml,可以直接喂给YOLO、Faster R-CNN、DETR这类主流检测框架做训练或微调。适合两类人:一是做军机识别、飞机型号分类的算法工程师,需要真实场景数据验证模型泛化能力;二是学生或研究者,想找一个类别丰富、标注规范的检测数据集跑通全流程。注意,这批数据采集地点固定,和其他批次不重叠,类别也可能不同,下载前先确认你的任务需求。
2. 拆开数据包:34类机型、1000张图与xml标签的对应关系
2.1 目录结构与文件命名逻辑
拿到压缩包解压后,你看到的不会是按类别分好的文件夹,而是一堆平铺的jpg和同名xml。文件名形如RUS-05-0319.jpg,前缀RUS代表采集区域,05是批次号,后四位是序号。这种命名方式的好处是全局唯一,坏处是你没法从文件名直接看出机型。机型信息全部藏在xml的<name>字段里。我一般会先跑一个统计脚本,把每个xml里的类别名抽出来,看看34类到底长什么样、每类有多少张。这一步不做,后面划分训练集时很容易出现某类只有两三张图的情况,模型直接学废。
import os import xml.etree.ElementTree as ET from collections import Counter # 指向解压后的数据目录 data_dir = "./RUS-05" counter = Counter() for f in os.listdir(data_dir): if f.endswith(".xml"): tree = ET.parse(os.path.join(data_dir, f)) root = tree.getroot() for obj in root.findall("object"): name = obj.find("name").text.strip() counter[name] += 1 # 打印每类目标数量,按降序排列 for cls, cnt in counter.most_common(): print(f"{cls}: {cnt}")这段脚本遍历所有xml,统计每个类别名出现的次数。ET.parse负责解析xml,findall("object")拿到所有标注框,find("name").text就是类别字符串。跑完你会得到一张类别分布表。如果发现某些类样本极少,比如个位数,建议要么合并到相近大类,要么在划分时单独处理,别直接随机切分。
2.2 xml标签字段解读与格式转换
labelimg生成的xml遵循PASCAL VOC格式,核心字段就几个:<size>里的width和height是图像尺寸,<object>里的<name>是类别,<bndbox>里的xmin/ymin/xmax/ymax是左上角和右下角坐标。这里有个容易翻车的点:坐标是绝对像素值,不是归一化值。如果你直接拿去做YOLO训练,需要转成归一化的cx cy w h。转换逻辑不复杂,但边界处理要小心——xmax不能等于width,否则归一化后等于1,某些框架会报错。
import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, img_w, img_h): tree = ET.parse(xml_path) root = tree.getroot() lines = [] for obj in root.findall("object"): cls_name = obj.find("name").text.strip() bndbox = obj.find("bndbox") xmin = float(bndbox.find("xmin").text) ymin = float(bndbox.find("ymin").text) xmax = float(bndbox.find("xmax").text) ymax = float(bndbox.find("ymax").text) # 防止坐标越界,留一个像素的余量 xmax = min(xmax, img_w - 1) ymax = min(ymax, img_h - 1) cx = (xmin + xmax) / 2.0 / img_w cy = (ymin + ymax) / 2.0 / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h lines.append(f"{cls_name} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}") return linesimg_w和img_h从xml的<size>里读,或者直接用OpenCV读图获取。min(xmax, img_w - 1)这行是血泪经验,有些标注框会贴着图像边缘,不处理的话转换后宽度可能为0。类别名建议统一映射成数字id,别直接用中文字符串,否则训练时还得额外维护一个字典。
2.3 训练集/验证集划分的坑
1000张图、34类,平均每类不到30张。这种量级下,随机划分很容易让某些类在验证集里一张都没有。我一般用分层抽样,按类别分组后再切分。如果懒得写分层逻辑,至少跑三次随机种子,看看每次验证集类别覆盖是否完整。另外,同一架飞机的多张照片可能被分到训练集和验证集,导致验证指标虚高。如果xml里有<pose>或<truncated>字段能区分拍摄角度,可以按角度分组划分,没有的话就接受这个局限,心里有数就行。
3. 把xml喂给YOLO:从VOC格式转换到训练配置的完整链路
3.1 转换脚本的工程化写法
上面那段voc_to_yolo只是核心逻辑,实际用的时候要批量处理、生成train.txt和val.txt、建立类别映射表。我习惯把类别名按字母序排好,生成classes.txt,然后转换时用索引代替字符串。这样YOLO的data.yaml里直接写nc: 34和names: [...]就行。批量转换时注意文件编码,有些xml里可能有BOM头,ET.parse会报错,用codecs.open指定utf-8能绕过。
# 目录结构建议 # dataset/ # images/ # 所有jpg # labels/ # 转换后的txt # classes.txt # 每行一个类别名 # train.txt # 训练集图片路径列表 # val.txt # 验证集图片路径列表转换完先别急着训练,用labelImg或者cv2可视化几张图,确认框的位置和类别都对。我见过有人把xmin和xmax写反,训练loss直接爆炸。
3.2 YOLOv8训练配置与参数含义
YOLOv8的配置文件data.yaml长这样:
path: ./dataset train: train.txt val: val.txt nc: 34 names: ['A', 'B', 'C', ...] # 按classes.txt顺序填训练命令:
yolo detect train data=data.yaml model=yolov8n.pt epochs=100 imgsz=1024 batch=8imgsz=1024是因为原图就是1024×768,直接resize到640会丢失小目标细节。batch=8取决于显存,8G显存跑1024尺寸大概能到8。epochs=100是起步,34类细粒度任务通常要150以上才收敛。如果显存不够,把imgsz降到768,但别低于640,否则机翼上的小标记根本看不见。
3.3 类别不平衡的应对策略
34类里肯定有几类样本特别多、几类特别少。YOLOv8默认的损失函数对不平衡不算敏感,但如果某类只有5张图,模型基本学不会。常见做法是:要么在data.yaml里给每类设weight,要么用过采样把少样本类复制几份。我一般先跑一轮看混淆矩阵,如果某类recall低于0.3,再针对性补数据或调权重。别一上来就改损失函数,先确认标注没问题。
4. 避坑与排查:标注、坐标、类别映射里最容易翻车的五件事
4.1 现象:训练loss正常下降但mAP极低
原因:类别映射错位。classes.txt的顺序和data.yaml里names的顺序不一致,模型学的是“第0类”,但评估时按名字对,全错。解决:生成classes.txt和data.yaml用同一个脚本,确保顺序完全一致。
4.2 现象:某些图训练时报“invalid bbox”
原因:xml里xmax等于或小于xmin,或者坐标超出图像尺寸。labelimg偶尔会保存这种脏数据。解决:转换前加校验,过滤掉宽高小于2像素的框,或者把坐标clip到[0, width-1]。
4.3 现象:验证集mAP高但实际推理漏检严重
原因:训练集和验证集有同一架飞机的不同角度图,数据泄漏。解决:按文件名前缀分组划分,同一前缀的图只出现在一个集合里。如果前缀区分度不够,就接受这个现实,别把验证指标当最终性能。
4.4 现象:模型把苏-27和米格-29搞混
原因:这两类外形确实像,34类细粒度任务本身就有难度。解决:增大输入分辨率到1280,或者在backbone后加注意力模块。更实际的做法是接受一定混淆,重点看整体mAP,别死磕单类。
4.5 现象:xml解析报“not well-formed”
原因:文件里有非法字符或编码问题。解决:用codecs.open(path, 'r', 'utf-8')读入字符串,replace掉&等特殊字符后再ET.fromstring。批量处理时加try-except,把报错文件单独列出来手动修。
5. 进阶技巧:用预训练权重和TTA把34类细粒度识别再提几个点
如果你已经跑通基础训练,想再压榨一点精度,有两个方向值得试。一是用COCO预训练的YOLOv8m或YOLOv8l,别用nano,细粒度任务上大模型优势明显。加载方式很简单:model=yolov8m.pt,其他参数不变。二是推理时开TTA(Test Time Augmentation),YOLOv8自带augment=True参数,在val或predict时加上,会对每张图做翻转、缩放再融合结果,mAP通常能涨1到3个点,代价是推理速度慢一倍。
yolo detect val data=data.yaml model=runs/detect/train/weights/best.pt imgsz=1024 augment=True还有一个容易被忽略的点:这批数据是可见光RGB,如果你手头有其他批次的红外或SAR图像,别直接混在一起训。模态差异太大,模型会学崩。正确做法是分别训,然后做决策级融合。另外,34类里军民混编,如果下游任务只关心军机,可以在评估时只统计军机类的mAP,别被客机类的高分拉高整体指标。
从那以后我每次拿到新数据集,都强制先跑一遍类别统计和可视化,确认没有脏标注和类别错位再开训。希望帮到你。
本文还有配套的精品资源,点击获取