飞机数据集2986张VOC+YOLO格式:从格式转换到YOLO训练全流程

发布时间:2026/10/11 0:23:34
飞机数据集2986张VOC+YOLO格式:从格式转换到YOLO训练全流程
简介这是一份面向目标检测初学者与算法工程师的飞机识别数据集采用Pascal VOC与YOLO双格式标注可直接用于YOLO系列、Faster R-CNN等模型的训练与验证省去格式转换的繁琐步骤。资源包共2000个文件以1999个xml标注文件和1个说明txt为主另含2986张jpg原图及对应的yolo格式txt标签压缩包约379.91MB标注工具为labelImg统一以矩形框标出airplane一类目标共5129个标注框类别单一、标注规范适合单类检测任务的快速上手与迁移学习。目前已有737人学习下载可作为课程设计、毕业项目或算法对比实验的基础数据。需要说明的是数据集仅提供准确合理的标注不对训练所得模型或权重文件的精度作任何保证使用者需结合自身网络结构与训练策略进行调优。1. 飞机数据集2986张VOCYOLO格式一份能直接开训的检测数据到底长什么样拿到一份标注好的飞机数据集最怕的不是数量少而是格式对不上、标签错位、训练时 mAP 死活上不去。这份 2986 张的飞机数据集同时提供 VOC 和 YOLO 两种格式解决的正是「下载完还要自己转格式、转完还要核对坐标」这段最耗时的脏活。它适合三类人刚入门 yolo 目标检测、想跑通第一个自定义数据集的新手需要快速验证模型结构或损失函数改动、不想在数据准备上耗时间的算法工程师以及在边缘设备上做飞机识别、想把数据集先跑通再谈部署的开发者。VOC 格式保留原始 XML 标注方便做数据审查和二次加工YOLO 格式的 txt 标签可以直接喂给 ultralytics 系列训练脚本。两种格式并存意味着你既能用 labelImg 这类工具回看标注质量又能一行命令启动训练不用在格式转换上反复翻车。2. 先搞懂 VOC 与 YOLO 的坐标差异为什么同一张图两套标签不能混用2.1 VOC 的 XML 结构与字段含义VOC 格式的标注是一个图像对应一个 XML 文件核心信息都在object节点里。一份典型的飞机标注长这样annotation folderimages/folder filenameplane_0001.jpg/filename size width1024/width height768/height depth3/depth /size object nameplane/name poseUnspecified/pose truncated0/truncated difficult0/difficult bndbox xmin212/xmin ymin98/ymin xmax640/xmax ymax430/ymax /bndbox /object /annotationsize里的宽高是原图尺寸bndbox用的是绝对像素坐标左上角(xmin, ymin)、右下角(xmax, ymax)。difficult字段在评估时会被 VOC 官方指标忽略但很多训练框架默认不读它所以如果你的数据集里 difficult1 的样本很多训练时它们照样参与 loss 计算这点要心里有数。truncated表示目标是否被截断飞机数据集里停机坪边缘的飞机经常出现这种情况。2.2 YOLO 的 txt 格式与归一化规则YOLO 格式每张图对应一个同名 txt每行一个目标格式是class_id x_center y_center width height五个值全部是归一化到 0~1 的浮点数x_center、y_center是框中心点相对整图宽高的比例width、height是框宽高相对整图宽高的比例。换算关系是x_center (xmin xmax) / 2 / img_width y_center (ymin ymax) / 2 / img_height width (xmax - xmin) / img_width height (ymax - ymin) / img_height这里最容易踩的坑是归一化用的除数必须是这张图自己的宽高而不是数据集统一尺寸。飞机数据集里如果混了不同分辨率的图用固定值去除会直接导致框偏移。另外 YOLO 的class_id从 0 开始而 VOC 的name是字符串中间必须有一份类别映射表通常是classes.txt行号即 class_id。2.3 两套格式的目录组织与对应关系VOC 常见目录结构是Annotations/放 XML、JPEGImages/放原图、ImageSets/Main/放 train/val 划分文件。YOLO 则是images/和labels/平行放置文件名一一对应。这份飞机数据集两种格式都给了意味着你可以直接用 YOLO 目录开训同时用 VOC 的 XML 做标注复核。判断一份数据集是否「干净」我一般会抽查 5% 的样本把 XML 的框画回原图再和 YOLO 的 txt 画出来的框叠一起如果两者重合说明转换没丢精度。3. 用 Python 把 VOC 转成 YOLO转换脚本与四个边界坑3.1 转换脚本的完整实现虽然数据集已经给了 YOLO 格式但实际项目里你总会遇到只有 VOC 的情况或者需要重新划分类别。下面这个脚本是我常用的版本处理了空标注、越界坐标和类别映射import os import xml.etree.ElementTree as ET from pathlib import Path # 类别列表顺序即 class_id CLASSES [plane] def convert_bbox(size, box): VOC绝对坐标 - YOLO归一化中心坐标 dw, dh 1.0 / size[0], 1.0 / size[1] xmin, xmax, ymin, ymax box # 裁剪越界坐标防止归一化后超出0~1 xmin, xmax max(0, xmin), min(size[0], xmax) ymin, ymax max(0, ymin), min(size[1], ymax) x (xmin xmax) / 2.0 * dw y (ymin ymax) / 2.0 * dh w (xmax - xmin) * dw h (ymax - ymin) * dh return x, y, w, h def convert_annotation(xml_path, out_dir): tree ET.parse(xml_path) root tree.getroot() size root.find(size) w, h int(size.find(width).text), int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in CLASSES: continue cls_id CLASSES.index(name) bndbox obj.find(bndbox) box (float(bndbox.find(xmin).text), float(bndbox.find(xmax).text), float(bndbox.find(ymin).text), float(bndbox.find(ymax).text)) # 注意上面顺序是 xmin,xmax,ymin,ymax传入前要调整 box (box[0], box[2], box[1], box[3]) bb convert_bbox((w, h), box) lines.append(f{cls_id} { .join(f{v:.6f} for v in bb)}) out_path Path(out_dir) / (Path(xml_path).stem .txt) out_path.write_text(\n.join(lines), encodingutf-8) if __name__ __main__: xml_dir Annotations out_dir labels os.makedirs(out_dir, exist_okTrue) for f in os.listdir(xml_dir): if f.endswith(.xml): convert_annotation(os.path.join(xml_dir, f), out_dir)逻辑上分三步解析 XML 拿到原图宽高和每个 object 的绝对坐标把坐标裁剪到图像范围内再归一化按 YOLO 格式写 txt。convert_bbox里先裁剪再计算是关键飞机数据集里如果有标注框超出图像边界的样本不裁剪会得到大于 1 的归一化值训练时直接报错或产生异常梯度。3.2 参数说明与常见改法CLASSES列表决定 class_id 的分配顺序必须和训练时的data.yaml里names完全一致否则模型学到的类别会错位。f{v:.6f}保留 6 位小数YOLO 官方脚本用的是 6 位精度足够且不会让文件过大。如果你的数据集有多个类别比如飞机、直升机、无人机把CLASSES改成对应列表即可cls_id会自动按索引分配。convert_bbox里的裁剪逻辑用的是max(0, xmin)和min(size[0], xmax)这是防止标注员手抖画出界。有些转换脚本不做这步遇到越界框会生成负的宽高YOLO 训练时表现为 loss 突然变 NaN排查起来很费时间。3.3 转换后的校验方法转完不要直接开训先做两件事。第一统计每个 txt 的行数如果某张图应该有飞机但 txt 是空的说明类别名没匹配上。第二随机抽 20 张图用 OpenCV 把 YOLO 框画回去import cv2 def draw_yolo(img_path, label_path): img cv2.imread(img_path) h, w img.shape[:2] with open(label_path) as f: for line in f: c, x, y, bw, bh map(float, line.split()) x1 int((x - bw / 2) * w) y1 int((y - bh / 2) * h) x2 int((x bw / 2) * w) y2 int((y bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.imwrite(check.jpg, img)画出来的框如果紧贴飞机轮廓说明转换正确如果整体偏移或大小不对多半是宽高用错了图。这个校验步骤花不了几分钟但能省下几小时排查训练异常的时间。4. 拿这份数据集跑通第一个 yolo 训练环境、配置与启动命令4.1 环境准备与 ultralytics 安装现在跑 yolo 最省事的是 ultralytics 包一条命令装完pip install ultralytics如果你用 PyCharm直接在项目解释器里装也行但要注意 PyCharm 默认可能建的是虚拟环境装完在终端里yolo checks验证一下。GPU 环境需要先装好对应 CUDA 版本的 PyTorchultralytics 会自动检测。在 AGX Orin 这类边缘设备上搭环境常见做法是先刷好 JetPack再用系统自带的 PyTorch 轮子不要盲目 pip 装最新版版本不匹配是玄学报错的主要来源。4.2 data.yaml 的写法与路径陷阱YOLO 训练靠一份 yaml 描述数据位置和类别path: /data/plane_dataset train: images/train val: images/val names: 0: planepath是数据集根目录train和val是相对路径。这里最常见的翻车是路径写错但程序不报错只是训练时找不到图表现为 loss 一直是 0 或者 mAP 为 0。判断方法很简单训练启动后看日志里train: Scanning...那行如果扫到的图片数是 0就是路径问题。另外names的键必须从 0 开始连续跳号会导致类别索引对不上。4.3 启动训练与关键参数一条最小启动命令yolo detect train datadata.yaml modelyolov8n.pt epochs100 imgsz640 batch16modelyolov8n.pt用的是预训练权重小数据集上迁移学习比从头训收敛快得多。imgsz640是输入尺寸飞机数据集如果原图分辨率很高可以调到 1280但显存占用会翻倍。batch16在 8G 显存上跑 640 尺寸基本够用爆显存就降到 8。epochs100对 2986 张图来说通常够收敛如果验证集 mAP 在 50 轮后还在涨可以加到 200。训练过程中重点看三个指标box_loss应该稳步下降如果震荡剧烈可能是学习率太大mAP50是 IoU 0.5 时的平均精度飞机这种形状规整的目标通常能到 0.9 以上mAP50-95更严格能反映框的贴合程度。如果mAP50高但mAP50-95低说明框的位置不够准可能是标注质量或数据增强过强。4.4 训练完的验证与导出训完用yolo detect val在验证集上跑一遍确认指标和训练日志一致。导出 ONNX 用于部署yolo export modelruns/detect/train/weights/best.pt formatonnx opset12opset12兼容性较好导出后在 ONNX Runtime 里跑一张图对比输出确认没有精度损失。如果要做实例分割这份检测数据集不够用需要分割掩码标注但检测框可以作为分割标注的初始参考。5. 训练飞机检测模型时最容易踩的五个坑5.1 现象mAP 一直为 0loss 不下降原因通常是类别映射错位。VOC 里name是plane但data.yaml里写成了airplane或者CLASSES列表顺序和 yaml 不一致导致模型学的是错误标签。解决方法是打印一份 txt 标签确认 class_id 和 yaml 里的 names 对应再检查转换脚本里的CLASSES是否和 yaml 完全一致。5.2 现象训练报错「negative width/height」这是 VOC 转 YOLO 时没做坐标裁剪标注框的 xmax 小于 xmin 或超出图像边界。解决方法是回到转换脚本在归一化前加max(0, ...)和min(size, ...)裁剪重新生成标签。如果数据集本身标注就有问题用画框脚本抽查把异常样本挑出来重新标。5.3 现象验证集指标远低于训练集典型过拟合2986 张图对检测任务来说不算多。解决手段有三个开数据增强ultralytics 默认已经开了 mosaic 和翻转可以再加scale0.5用更小的模型如 yolov8n加早停patience20。如果验证集本身和训练集分布差异大比如训练集都是白天、验证集有夜间那需要补充对应场景的数据光调参救不回来。5.4 现象显存溢出batch 调小后训练变慢imgsz和batch是显存的两个主要消耗项。640 尺寸下 batch 16 爆显存先降到 8如果还爆就把imgsz降到 416。但尺寸降太多小目标会漏检飞机在图像里占比小的时候尤其明显。折中方案是用batch4配合梯度累积ultralytics 里通过nbs64间接控制实际 batch 小但等效 batch 大训练稳定性更好。5.5 现象导出的 ONNX 推理结果和 PyTorch 不一致多半是预处理没对齐。PyTorch 推理时 ultralytics 会自动做 letterbox 缩放和归一化导出 ONNX 后这些预处理不在模型里需要自己实现。解决方法是导出时加dynamicTrue并在推理端复现 letterbox或者直接用 ultralytics 的predict接口做对比测试确认输入输出一致后再部署。6. 把这份数据集用出更高价值从检测到多模态分析的衔接技巧跑通基础检测只是起点。这份飞机数据集真正的价值在于它能作为更复杂系统的数据底座。比如做机场场面监控检测框出来之后可以接一个多模态分析模块把飞机位置和塔台语音、航班信息做关联判断是否有滑行冲突。这时候检测模型的输出不只是框还需要稳定的 ID 跟踪可以在 YOLO 后面接 ByteTrack用yolo track命令直接跑。另一个方向是模型轻量化。飞机检测在边缘设备上部署时yolov8n 在 AGX Orin 上能跑到实时但如果要同时跑多路视频就需要量化。导出 ONNX 后用 TensorRT 做 FP16 或 INT8 量化INT8 需要校准集从这份数据集的验证集里抽 200 张就够了。量化后 mAP 通常会掉 1~3 个点如果掉太多检查校准集是否覆盖了所有场景。还有一个容易被忽略的技巧用检测框做弱监督分割。飞机形状规整检测框内的像素用 GrabCut 或 SAM 做前景提取能得到近似分割掩码再人工修一下边界比从零标分割快得多。这样一份检测数据集就能衍生出分割数据喂给 yolo 实例分割模型。我自己踩过最深的坑是早期拿到数据集直接开训没做标签校验训了两天才发现有一批图的框整体偏移了十几个像素原因是转换时用了错误的原图尺寸。从那以后我养成了一个习惯任何数据集到手先抽 20 张画框叠图确认标注和图像对齐再开训。这个动作花 10 分钟能省下的是按天算的返工时间。希望帮到你。本文还有配套的精品资源点击获取