资讯动态

飞机起落架检测数据集:1144张VOC/YOLO双格式与YOLO训练全流程

发布时间:2026/10/3 5:52:00 来源:尧图企业网站定制
飞机起落架是航空器上少数几个零容错的机械部件之一它承担着起飞、着陆、滑行全过程中最剧烈的冲击载荷也是地面视觉检测环节里最容易被漏检、误检的目标。我最近在整理一个专门针对起落架目标的检测数据集规模是1144张标注格式同时提供VOC和YOLO两套类别只有一个——起落架。这个体量听起来不大但对于一个单类别、强结构、强场景约束的检测任务来说1144张精标图已经足够跑通一条从训练到部署的完整链路。下面我把这个数据集的构成逻辑、格式转换细节、训练调参思路以及实际踩过的坑完整地拆一遍适合正在做航空地面检测、单类别目标检测或者想拿一个干净数据集练手YOLO全流程的人参考。1. 为什么单类别起落架检测值得单独做一个数据集1.1 起落架检测和通用目标检测的本质差异通用目标检测数据集比如COCO、VOC里飞机是一个大类起落架只是飞机内部的一个子结构标注时往往被合并进airplane这个框里根本不会单独框出来。这就导致一个很现实的问题如果你直接拿通用数据集训练一个模型去检测起落架模型学到的特征是机翼机身发动机起落架的混合纹理它对起落架本身的几何结构并不敏感。一旦画面里出现遮挡、起落架收起、或者只露出局部模型就很容易失效。起落架这个目标的特殊性在于三点。第一它的形状高度结构化支柱、机轮、液压作动筒、舱门边缘构成了非常固定的几何关系这种强结构特征其实对检测是有利的。第二它的尺度变化极大远距离停机坪画面里可能只有十几个像素近距离地面检查画面里可能占据半张图。第三它的背景极其单一要么是停机坪水泥地要么是机腹阴影要么是天空背景干扰少反而意味着模型容易过拟合到背景纹理上。所以单独做一个单类别起落架数据集核心价值不是多了一个数据集而是把检测任务从识别飞机收敛到识别一个具有强几何先验的机械结构这会让整个训练目标和评估标准都变得清晰。1.2 1144张这个量级到底够不够很多人一看到1144张就觉得少。我实际跑下来的结论是对于单类别、背景相对可控、目标结构固定的任务1144张精标图配合合理的增强策略完全能训出一个可用的模型。判断依据不是绝对数量而是有效样本多样性。我大致统计过这批图的分布覆盖了以下几个维度不同机型窄体、宽体、支线机都有前起落架和主起落架都包含不同光照白天顺光、逆光、阴天、黄昏、机库内人工照明不同拍摄距离远距离全景、中距离特写、近距离局部不同遮挡程度完全无遮挡、部分被地面设备遮挡、被机腹阴影部分覆盖不同角度正前方、侧方、斜下方仰拍这五个维度交叉之后1144张的实际信息量是够的。真正会导致不够的情况是1144张全部来自同一个机场、同一个机型、同一个时间段那多样性就崩了这时候数量再多也没用。所以拿到任何数据集第一件事不是看数量是看分布。1.3 VOC和YOLO双格式同时提供的实际意义这个数据集同时给VOC和YOLO两套标注这不是简单的格式冗余而是对应了两条不同的工作流。VOC格式XML保留了图像的宽高、目标的绝对像素坐标xmin, ymin, xmax, ymax以及可扩展的字段。它的优势在于信息完整、可读性强、方便做二次加工。比如你要统计所有起落架框的宽高比分布直接解析XML就行不需要做任何坐标反算。YOLO格式TXT是归一化的中心点坐标加宽高cx, cy, w, h全部除以图像宽高取值范围0到1。它的优势是直接喂给YOLO系列训练脚本不需要额外转换而且归一化之后和图像分辨率解耦。两套格式同时存在意味着你可以用VOC做数据分析和可视化校验用YOLO直接开训中间省掉一次容易出错的转换步骤。这一点在实际项目里非常关键因为格式转换是标注环节最容易引入静默错误的地方。2. 数据集目录结构与标注文件的组织方式2.1 推荐的目录树虽然原始数据集可能只给了图片和标注文件但落到实际训练时目录结构必须重新组织。我习惯用下面这套结构兼容YOLOv5到YOLOv8以及大部分主流训练框架landing_gear_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── annotations_voc/ │ ├── train/ │ ├── val/ │ └── test/ ├── classes.txt └── data.yaml这里有个细节要注意images和labels下面的文件名必须严格一一对应只是扩展名不同。比如images/train/001.jpg对应labels/train/001.txt。很多训练脚本是靠文件名匹配的一旦对不上会出现图片有但标签找不到的情况而YOLO默认行为是跳过这些图不会报错结果就是你训了半天发现实际用的样本比预期少。2.2 classes.txt和data.yaml的写法单类别数据集的classes.txt只有一行landing_gear对应的data.yamlpath: ./landing_gear_dataset train: images/train val: images/val test: images/test nc: 1 names: 0: landing_gear这里最容易踩的坑是nc和names的对应关系。nc是类别数量names是类别名列表索引从0开始。单类别时nc1names里只有索引0。如果你从别的多类别数据集复制配置过来忘了改nc训练时不会立刻报错但损失计算会出问题表现为loss一直不下降或者出现nan。2.3 训练集、验证集、测试集的划分比例对于1144张这个量级我建议的划分是子集比例数量约用途train70%800模型参数学习val20%229训练中监控、调参test10%115最终评估训练全程不碰为什么不建议用80/20的两分法因为单类别任务里验证集的作用是帮你判断过拟合和选checkpoint测试集的作用是给你一个无偏的性能估计。如果只有验证集你反复根据验证集调参验证集就泄漏了最后报出来的指标会偏乐观。留出10%的测试集哪怕只有115张也能给你一个相对诚实的mAP。划分时还有一个关键点要按场景分层抽样不能纯随机。比如你随机分完之后发现所有逆光样本都进了训练集验证集全是顺光那验证指标就会虚高。我的做法是先按光照、距离、机型打标签然后在每个标签内部随机抽保证三个子集的分布尽量一致。3. VOC与YOLO格式互转的完整实现与校验3.1 两种格式的坐标定义差异先把定义说清楚这是所有转换错误的根源。VOC的XML里一个目标长这样object namelanding_gear/name bndbox xmin112/xmin ymin204/ymin xmax356/xmax ymax489/ymax /bndbox /objectxmin、ymin、xmax、ymax是绝对像素坐标原点在左上角。YOLO的TXT里同一目标长这样0 0.204545 0.302083 0.213068 0.248958五个字段分别是类别索引、中心点x归一化、中心点y归一化、宽归一化、高归一化。转换公式cx (xmin xmax) / 2 / W cy (ymin ymax) / 2 / H w (xmax - xmin) / W h (ymax - ymin) / H其中W和H是图像的实际宽高。这里必须强调W和H一定要从图片文件真实读取不能从XML里猜也不能用固定值。我见过有人图省事直接写死1920和1080结果遇到一批1280×720的图所有框全部错位。3.2 转换脚本与边界处理下面是我常用的VOC转YOLO脚本加了边界裁剪和越界检查import os import xml.etree.ElementTree as ET from PIL import Image def voc_to_yolo(xml_dir, img_dir, out_dir, class_map): os.makedirs(out_dir, exist_okTrue) 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() img_name root.find(filename).text img_path os.path.join(img_dir, img_name) W, H Image.open(img_path).size lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_map: continue cls_id 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) # 边界裁剪防止越界 xmin max(0, min(xmin, W - 1)) ymin max(0, min(ymin, H - 1)) xmax max(0, min(xmax, W - 1)) ymax max(0, min(ymax, H - 1)) if xmax xmin or ymax ymin: continue cx (xmin xmax) / 2.0 / W cy (ymin ymax) / 2.0 / H w (xmax - xmin) / W h (ymax - ymin) / H lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) out_file os.path.join(out_dir, xml_file.replace(.xml, .txt)) with open(out_file, w) as f: f.write(\n.join(lines))这段代码里有三个我特意加的保护一是坐标裁剪到图像范围内二是过滤掉宽高为负或为零的退化框三是类别不在映射表里就跳过。这三点在真实数据里都会遇到尤其是标注员手抖把xmax标得比xmin小的情况。3.3 转换后的可视化校验转换完绝对不能直接开训必须做可视化校验。我的做法是随机抽20张把YOLO格式的框反算回像素坐标画到图上人眼过一遍。import cv2 import numpy as np def visualize_yolo(img_path, label_path, save_path): img cv2.imread(img_path) H, W img.shape[:2] with open(label_path) as f: for line in f: cls, cx, cy, w, h map(float, line.split()) x1 int((cx - w / 2) * W) y1 int((cy - h / 2) * H) x2 int((cx w / 2) * W) y2 int((cy h / 2) * H) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(save_path, img)校验时重点看三件事框是否贴合起落架本体、有没有框跑到图像外面、有没有明显的漏标。如果发现系统性偏移八成是W和H读错了如果发现框整体缩小或放大可能是归一化时用了错误的尺寸。提示可视化校验这一步不要省。我见过太多人转换完直接开训训了几轮发现mAP异常低回头查才发现是坐标转换时把宽高弄反了白白浪费几个小时。4. 基于YOLO训练起落架检测模型的关键参数4.1 输入分辨率的选择逻辑起落架目标在小尺度下可能只有20到30像素输入分辨率直接决定了这些目标能不能被网络看到。YOLO默认的640×640对远距离小目标是不够的我建议至少上到960如果显存允许1280效果更稳。这里有个计算假设原图是1920×1080起落架框宽约100像素。缩放到640时框宽变成100×640/1920≈33像素经过5次下采样后在最小特征图上只剩约1像素基本就丢了。缩放到1280时框宽约67像素下采样后还有2像素勉强能保留。所以分辨率不是随便设的要按目标尺度反推。显存和分辨率的对应关系大致如下以YOLOv8为例batch16输入尺寸显存占用约小目标召回6408GB偏低96014GB中等128022GB较高如果显存不够可以降batch而不是降分辨率因为分辨率对单类别小目标的影响远大于batch。4.2 数据增强策略的取舍单类别数据集最容易犯的错是增强开太猛。YOLO默认的增强里Mosaic和MixUp对小目标检测有帮助但对起落架这种强结构目标要谨慎。我的实际配置是Mosaic开启但close_mosaic设为最后10个epoch关闭让模型在训练末期见到真实分布MixUp关闭。起落架和背景混合会产生不真实的纹理反而干扰学习HSV增强开启hsv_h0.015hsv_s0.7hsv_v0.4。光照变化是真实场景的主要变量这个必须开翻转水平翻转开启垂直翻转关闭。起落架在图像里基本不会上下颠倒垂直翻转是无效增强缩放scale0.5允许0.5到1.5倍缩放覆盖不同距离旋转degrees0。起落架在正常拍摄下不会有大幅旋转开了反而引入噪声这套配置的核心思路是只增强真实场景中会出现的变量不引入物理上不可能的变化。4.3 损失函数与正负样本分配YOLOv8用的是TaskAlignedAssigner做正负样本分配分类损失是BCE回归损失是CIoU加DFL。单类别情况下分类分支的压力很小因为只有是起落架和不是起落架两种判断模型的主要学习压力在回归分支上。这意味着两件事。第一分类损失的权重可以适当降低让模型把更多容量放在框的定位精度上。第二评估指标里mAP50会很快饱和真正有区分度的是mAP50-95因为它对框的精度要求更高。我在训练时主要盯mAP50-95mAP50只作为参考。如果发现mAP50很高但mAP50-95上不去说明模型能找对位置但框不准这时候可以考虑调大回归损失的权重或者检查标注框是否本身就不够精确。4.4 训练轮次与早停1144张图单类别我一般设epochs200patience50。实际跑下来通常在120到160轮之间收敛。判断收敛的信号是验证集mAP50-95连续多轮不再提升且训练损失和验证损失之间的gap稳定。这里要提醒一点单类别数据集很容易过拟合因为类别信息太单一模型会去记背景纹理。如果验证损失开始上升而训练损失还在降就是过拟合的典型信号这时候早停比继续训更明智。5. 实测中暴露的问题与排查链路5.1 验证集mAP虚高的排查过程我第一次跑完这个数据集时验证集mAP50到了0.96当时觉得效果很好。但拿测试集一跑只有0.81差了15个点。这个gap不正常我开始排查。第一步检查验证集和测试集的分布。统计之后发现验证集里近距离样本占比65%而测试集里近距离只占40%远距离样本测试集明显更多。模型在近距离上表现好远距离上差所以验证集虚高。第二步检查是否有图像重复。用感知哈希pHash对全部1144张图做去重发现验证集里有7张图和训练集里的图高度相似可能是同一场景连拍。这7张图贡献了虚高的部分。第三步重新按场景分层划分数据集保证三个子集的近距离、中距离、远距离比例一致并且做严格的图像去重。重新划分后验证集mAP50降到0.89测试集0.85gap缩小到4个点这个才是可信的。这个排查链路说明一个道理数据集指标异常好的时候先怀疑数据划分再怀疑模型。5.2 小目标漏检的定位方法远距离起落架漏检是最常见的问题。定位方法不是靠猜而是把验证集的漏检样本全部导出来按目标框面积排序看漏检集中在哪个尺度区间。我的做法是写一个脚本遍历验证集对每张图比较预测框和真实框把IoU低于0.3的真实框标记为漏检然后统计这些漏检框的像素面积分布。结果发现面积小于32×32的框漏检率高达40%而大于64×64的框漏检率只有5%。针对这个结果我做了两件事。一是把输入分辨率从960提到1280二是把数据增强里的scale下限从0.5调到0.7避免小目标被进一步缩小。调整后小目标漏检率降到18%整体mAP50-95提升了3个点。5.3 标注质量问题的识别标注质量是数据集的生命线。1144张图里我抽查了100张发现了几类典型问题问题类型表现影响框过松框比起落架大一圈回归目标模糊定位精度下降框过紧只框住机轮漏掉支柱模型学不到完整结构漏标画面里有起落架但没框被当作负样本压制召回类别拼写不一致landing_gear和landinggear混用转换时被过滤样本丢失其中漏标和拼写不一致最隐蔽。漏标会让模型学到这个位置不该有目标的错误信号拼写不一致会导致转换脚本静默丢弃样本。我的处理方式是先用脚本统计所有XML里的name字段取值确认只有一种拼写然后对每张图做一次预测把高置信度但无标注的区域人工复核找出漏标。5.4 训练中loss出现nan的处理训练到第30轮左右时loss突然变成nan。这种情况在单类别小数据集上不算罕见原因通常有三个学习率过大、某批数据里有退化框、混合精度训练溢出。我的排查顺序是先把混合精度关掉ampFalse重跑如果nan消失说明是精度溢出把学习率降一半再开amp。如果还nan就检查数据里有没有宽或高为0的框这种框在计算IoU时会产生除零。最后才是调学习率。实际这次是退化框导致的有3个标注框的xmax等于xmin。清理之后训练稳定跑完。6. 从训练完成到实际可用的最后几步6.1 模型导出与推理速度权衡训练完的.pt文件不能直接上生产需要导出。YOLOv8支持导出ONNX、TensorRT、OpenVINO等格式。选择依据是部署环境如果跑在NVIDIA GPU上TensorRT的FP16推理速度最快大约是PyTorch的2到3倍如果跑在CPU上OpenVINO对Intel平台优化最好如果需要跨平台ONNX是最通用的选择导出命令很简单yolo export modelbest.pt formatonnx imgsz1280但要注意导出时的imgsz必须和训练时一致否则精度会掉。我见过有人训练用1280导出用640结果mAP掉了8个点。6.2 置信度阈值的实际标定默认的conf阈值是0.25但这个值不能直接用。正确的做法是在验证集上画PR曲线找到recall和precision的平衡点。对于起落架检测如果应用场景是辅助人工检查可以容忍一定的误检conf设低一点比如0.2保证召回。如果是自动告警误检代价高conf设到0.5以上保证精度。这个阈值没有标准答案取决于业务对漏检和误检的容忍度。6.3 持续迭代的数据回流思路模型上线之后真正的挑战才开始。实际场景里会出现训练集没覆盖的情况比如新型号的起落架、特殊涂装、极端天气。这些样本要回流到数据集里定期重训。我的做法是建立一个难例池把线上推理中置信度在0.3到0.6之间的样本自动存下来人工复核后加入训练集。这样迭代几轮之后模型的泛化能力会明显提升。对于这个1144张的起点每轮回流200到300张难例重训一次通常能带来2到5个点的mAP提升。我个人在实际操作中的体会是单类别数据集的价值不在于数量堆砌而在于分布覆盖和标注一致性。1144张起落架图只要场景维度铺开、标注干净、格式转换经过校验配合合理的分辨率和增强策略完全能训出一个在真实场景里稳定可用的检测模型。真正决定成败的往往不是模型结构有多新而是数据这一层有没有把该做的校验做到位。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑