简介:面向无人机视觉与目标检测方向的开发者、算法工程师及高校研究者,这份资源提供了一套真实场景下的车辆检测数据集,可用于无人机航拍车辆识别项目,也可作为通用车辆检测数据的场景补充。数据集共1000张高质量图片,覆盖城市道路行驶、道边停车、停车场、小区及车辆遮挡、严重遮挡等多种情形,类别划分为轿车car、货车van与巴士bus三类,均经labelimg精细标注,并同步提供VOC(xml)、COCO(json)、YOLO(txt)三种主流格式,可直接投入YOLO等算法训练。资源包为1个PDF文件,约2MB,内含数据集基本情况介绍与获取方式,并附赠YOLO11一键训练脚本,支持GPU、CPU及Mac(M芯片)多平台方案,同时给出博主训练结果日志供对照参考。目前已有261人学习下载,适合希望快速验证无人机车辆检测方案、减少数据准备成本的读者。
1. 无人机视角下的车辆检测:1000 张图、三种标签格式与 YOLO11 一键训练到底怎么落地
拿到「无人机场景-目标检测-车辆检测数据集-1000张图-+对应VOC/COCO/YOLO三种格式标签+支持GPU(GPUs)/CPU/Mac三平台YOLO11一键训练脚本」这个标题,多数人第一反应是「数据集+脚本,下载就能跑」。但真正在无人机航拍车辆检测里翻过车的人都知道,坑不在模型,而在数据格式转换、小目标尺度、平台环境这三件事上。无人机视角的车辆检测和地面固定摄像头完全是两个问题:俯视角度让车辆变成几十像素的小目标,光照和运动模糊让标注边界模糊,1000 张图的量级又要求你必须在数据增强和训练策略上精打细算。这篇笔记就按「数据集长什么样 → 三种格式怎么转 → YOLO11 怎么在三平台跑起来 → 哪里最容易翻车」的顺序,把这条链路拆到能直接抄作业的程度。适合手里有无人机航拍素材、想快速验证车辆检测方案,或者想拿这套流程做移动小目标检测预研的工程师。
2. 无人机车辆检测数据集:1000 张图里到底有什么、为什么三种格式都要
2.1 无人机航拍车辆检测的数据特点与选型理由
无人机视角的车辆检测数据集,和 BDD100K 这类车载数据集最大的区别在于成像几何。无人机通常在 50 到 150 米高度作业,俯仰角接近垂直或大倾角,车辆在图像里呈现为矩形或近似矩形的色块,长宽比接近 1:1 到 2:1,而不是车载视角的 3:1 侧面轮廓。这意味着如果你直接拿 COCO 预训练的 YOLO11 权重来微调,模型对「车」的先验是侧面和斜侧面,迁移到俯视小目标时召回率会明显掉一截。
1000 张图的量级属于「小样本验证集」范畴。按 8:1:1 划分,训练集 800 张、验证集 100 张、测试集 100 张。这个量级下,单类车辆检测(car 一类)通常能到 mAP@0.5 0.75 以上,但如果要区分 car/truck/bus/van 多类,每类样本可能只有一两百个实例,就必须靠 mosaic、mixup、copy-paste 这类增强来撑住。我一般会先确认标注里实例总数:1000 张图如果平均每张 8 到 15 辆车,总实例在 1 万左右,这个量级做单类检测是够的,多类就要谨慎。
三种标签格式并存的意义在于工具链兼容。VOC XML 是很多标注工具(LabelImg、CVAT 导出)的原生格式,也是传统检测框架的入口;COCO JSON 是 pycocotools 评测和很多多模态分析管线的标准;YOLO txt 是 Ultralytics 训练直接吃的格式。数据集同时给三种,省掉的是你自己写转换脚本的时间,但转换过程中的坐标精度、类别映射、空标注处理,仍然要自己核对。
2.2 三种格式的结构差异与转换脚本
先把三种格式的目录结构和字段含义对齐,不然后面转换必错。
| 格式 | 单图标签文件 | 坐标表示 | 类别字段 | 典型用途 |
|---|---|---|---|---|
| VOC | 0001.xml | xmin,ymin,xmax,ymax绝对像素 | <name>car</name> | LabelImg、传统框架 |
| COCO | 单个annotations.json | [x,y,w,h]绝对像素 | category_id整数 | pycocotools 评测 |
| YOLO | 0001.txt | cx,cy,w,h归一化 0-1 | 行首类别索引 | Ultralytics 训练 |
从 VOC 转 YOLO 是最常见的一步,下面这个脚本我用了很多次,关键是处理边界框越界和空标注文件。
import os import xml.etree.ElementTree as ET # 类别映射:无人机车辆检测通常先做单类,多类时按实际标注改 CLASS_MAP = {"car": 0, "truck": 1, "bus": 2, "van": 3} def voc_to_yolo(xml_dir, out_dir, img_w, img_h): os.makedirs(out_dir, exist_ok=True) 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() # 从 XML 里读实际尺寸,比外部传参更稳 size = root.find("size") w = int(size.find("width").text) h = int(size.find("height").text) lines = [] for obj in root.findall("object"): name = obj.find("name").text.strip() if name not in CLASS_MAP: continue # 未定义类别直接跳过,避免索引错位 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, ymin = max(0, xmin), max(0, ymin) xmax, ymax = min(w, xmax), min(h, ymax) if xmax <= xmin or ymax <= ymin: continue # 无效框丢弃 cx = (xmin + xmax) / 2.0 / w cy = (ymin + ymax) / 2.0 / h bw = (xmax - xmin) / w bh = (ymax - ymin) / h lines.append(f"{CLASS_MAP[name]} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}") # 即使没有目标也写空文件,YOLO 训练需要图片和标签一一对应 with open(os.path.join(out_dir, xml_file.replace(".xml", ".txt")), "w") as f: f.write("\n".join(lines)) voc_to_yolo("./VOC/Annotations", "./labels/train", 0, 0)逻辑说明:脚本从 XML 内部读宽高而不是外部传参,是因为无人机数据集不同批次的图像分辨率可能不一致,外部传一个固定值会导致归一化坐标全错。类别映射用字典显式声明,遇到未定义类别跳过而不是报错,保证转换不中断。空标注写空文件这一步很多人会漏,YOLO 训练时如果某张图没有对应 txt,Ultralytics 会直接报错或静默跳过,导致实际训练集比预期少。
参数说明:CLASS_MAP必须和后续data.yaml里的names顺序完全一致,索引从 0 开始。cx,cy,w,h保留 6 位小数足够,YOLO 内部会再处理。如果你的数据集是多类,建议先跑一遍统计每类实例数,样本少于 50 的类别考虑合并或丢弃。
COCO 转 YOLO 的逻辑类似,但 COCO 的bbox是[x,y,w,h]绝对像素,且类别在categories数组里,需要先建category_id到连续索引的映射。这一步的坑是 COCO 的category_id往往不连续(比如 1,3,7),直接当 YOLO 索引会越界。
3. YOLO11 三平台训练:GPU、CPU、Mac 的环境配置与一键脚本拆解
3.1 Ultralytics YOLO11 环境配置的三种路径
YOLO11 是 Ultralytics 在 2024 年发布的版本,网络结构上延续了 C3k2 模块和 C2PSA 注意力机制,对移动小目标的检测头做了调整。训练入口统一在ultralytics包,三平台的差异主要在 PyTorch 后端和设备指定上。
GPU 平台(NVIDIA)是最顺的路径。CUDA 版本要和 PyTorch 对应,常见组合是 CUDA 12.1 + PyTorch 2.3+。安装命令:
# GPU 平台:先装对应 CUDA 的 PyTorch,再装 ultralytics pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install ultralytics # 验证 GPU 可见 python -c "import torch; print(torch.cuda.is_available(), torch.cuda.device_count())"CPU 平台适合验证流程和小批量推理,训练 1000 张图会非常慢,但跑通脚本没问题。Mac 平台分 Intel 和 Apple Silicon 两种,Apple Silicon 可以用 MPS 后端加速,比纯 CPU 快不少,但 YOLO11 的某些算子对 MPS 支持不完整,遇到报错就退回 CPU。
# Mac Apple Silicon:用 MPS 加速 pip install ultralytics python -c "import torch; print(torch.backends.mps.is_available())"一键训练脚本的核心是把设备选择、数据路径、超参封装成一个入口。我一般会写成train.py,用argparse区分平台,避免每次改代码。
import argparse from ultralytics import YOLO def pick_device(platform): import torch if platform == "gpu" and torch.cuda.is_available(): return "0" # 多卡写 "0,1" if platform == "mac" and torch.backends.mps.is_available(): return "mps" return "cpu" if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("--platform", default="gpu", choices=["gpu", "cpu", "mac"]) parser.add_argument("--data", default="./data.yaml") parser.add_argument("--epochs", type=int, default=100) parser.add_argument("--imgsz", type=int, default=640) parser.add_argument("--batch", type=int, default=16) args = parser.parse_args() device = pick_device(args.platform) model = YOLO("yolo11n.pt") # n/s/m/l/x 按算力选 model.train( data=args.data, epochs=args.epochs, imgsz=args.imgsz, batch=args.batch, device=device, mosaic=1.0, # 无人机小目标靠 mosaic 撑 scale=0.5, # 尺度抖动,模拟不同飞行高度 fliplr=0.5, patience=20, # 20 轮无提升早停 project="runs/drone_vehicle", )逻辑说明:pick_device把平台判断收在一处,GPU 返回"0"表示第一块卡,Mac 返回"mps",其余回落"cpu"。mosaic=1.0对无人机小目标很关键,四图拼接能显著增加小目标出现频率。scale=0.5模拟无人机不同高度导致的尺度变化。patience=20防止小数据集上过拟合空跑。
参数说明:imgsz=640是默认值,但无人机小目标建议试 960 或 1280,代价是显存和速度。batch在 GPU 上按显存调,8G 显存跑 640 大概能到 16,跑 1280 只能到 4。Mac MPS 的 batch 建议不超过 8,否则容易内存溢出。
3.2 data.yaml 的写法与三平台路径差异
data.yaml是 Ultralytics 的数据入口,写错路径是最常见的翻车点。三平台的路径分隔符和绝对路径处理不同,建议统一用相对路径。
# data.yaml path: ./dataset # 数据集根目录 train: images/train # 相对 path val: images/val test: images/test nc: 1 # 类别数 names: ["car"] # 顺序必须和转换脚本的 CLASS_MAP 一致逻辑说明:path是根,train/val/test相对它。这样整个数据集可以整体移动而不改配置。nc和names长度必须一致,否则训练启动就报错。如果做多类,names的顺序要和 VOC 转换时的CLASS_MAP索引严格对应,错一位整个训练结果就废了。
参数说明:Windows 上路径用正斜杠/也能识别,但不要混用反斜杠。Mac 和 Linux 对大小写敏感,Images和images是两个目录,建议全小写。
3.3 训练启动、日志解读与中断恢复
启动训练后,控制台会输出每轮的 box_loss、cls_loss、dfl_loss 和 mAP。无人机车辆检测里,前 10 轮 box_loss 下降快是正常的,但如果 30 轮后 mAP@0.5 还在 0.3 以下,通常是标注质量问题或学习率过大。
# 启动训练 python train.py --platform gpu --epochs 100 --imgsz 960 --batch 8 # 中断后恢复:Ultralytics 会自动找 last.pt python -c "from ultralytics import YOLO; YOLO('runs/drone_vehicle/train/weights/last.pt').train(resume=True)"逻辑说明:resume=True会从last.pt恢复优化器状态和 epoch 计数,不是简单加载权重。日志里mAP50-95是主指标,无人机小目标通常比mAP50低不少,这是正常的,因为小目标定位精度天然差。
参数说明:如果显存不够,优先降batch而不是imgsz,因为imgsz直接影响小目标能否被检测到。960 是无人机车辆检测的一个平衡点,1280 更好但算力要求翻倍。
4. 无人机车辆检测的避坑与排查:5 个血泪教训
4.1 现象:训练 mAP 一直上不去,验证集却很高
原因:训练集和验证集划分时没有按场景分组,同一段航拍视频的相邻帧被分到了两边,导致验证集泄漏。无人机数据往往是视频抽帧,相邻帧几乎一样。
解决:按飞行架次或视频片段划分,而不是随机按图划分。如果数据集里没有架次信息,至少按时间顺序切分,不要 shuffle 后再切。
4.2 现象:推理时大量车辆漏检,尤其是小目标
原因:imgsz设太小,640 下 30 像素的车在特征图上只剩几个像素,检测头根本激活不了。或者 mosaic 增强关闭了,小目标样本占比不足。
解决:把imgsz提到 960 或 1280,保持mosaic=1.0,并检查标注里最小框的尺寸。如果最小框小于 10 像素,考虑在数据增强里加copy_paste或上采样小目标图片。
4.3 现象:Mac MPS 训练报错NotImplementedError
原因:YOLO11 的某些算子(如某些插值或注意力实现)在 MPS 后端没有实现,PyTorch 回落到 CPU 也失败。
解决:设置环境变量PYTORCH_ENABLE_MPS_FALLBACK=1让不支持的算子自动回 CPU,或者直接用--platform cpu。MPS 适合推理验证,训练还是 GPU 稳。
4.4 现象:VOC 转 YOLO 后类别全变成 0 或索引错位
原因:CLASS_MAP的索引和data.yaml的names顺序不一致,或者 VOC 里出现了CLASS_MAP没有的类别被静默跳过,导致某些图标签为空。
解决:转换后跑一遍统计脚本,检查每类实例数和空标签文件数。空标签文件占比超过 5% 就要回头查标注。
4.5 现象:GPU 显存溢出(OOM),batch 降到 1 还报错
原因:imgsz太大,或者workers设太高导致数据加载占用显存,或者多卡训练时device写法不对。
解决:先降imgsz到 640 确认能跑,再逐步升。workers在 Windows 上设 0 或 2,Linux 上可以设 8。多卡用device="0,1",不要用device=[0,1]。
5. 把 1000 张图用到极致:小目标增强与验证集评估的进阶技巧
1000 张图做无人机车辆检测,数据量是硬约束,所以增强策略和评估方法决定了最终上限。我一般会在标准训练之外做两件事:一是用 SAHI(Slicing Aided Hyper Inference)做切片推理验证,二是用混淆矩阵反查标注质量。
SAHI 的思路是把大图切成重叠小图分别推理再合并,对无人机小目标提升明显。Ultralytics 本身不内置 SAHI,但可以手动实现切片:
import cv2 from ultralytics import YOLO def sliced_inference(model, img_path, slice_size=640, overlap=0.2): img = cv2.imread(img_path) h, w = img.shape[:2] step = int(slice_size * (1 - overlap)) boxes = [] for y in range(0, h, step): for x in range(0, w, step): patch = img[y:y+slice_size, x:x+slice_size] if patch.shape[0] < 32 or patch.shape[1] < 32: continue results = model(patch, verbose=False) for box in results[0].boxes: xyxy = box.xyxy[0].tolist() # 把切片坐标映射回原图 boxes.append([xyxy[0]+x, xyxy[1]+y, xyxy[2]+x, xyxy[3]+y, box.conf[0].item()]) return boxes # 后续用 NMS 合并重叠框逻辑说明:切片推理把 4000x3000 的航拍图切成 640x640 的小块,每块里车辆占比更大,检测头更容易激活。overlap=0.2保证边缘目标不被切断。坐标映射回原图后需要用 NMS 去重,否则同一辆车会被多个切片重复检出。
参数说明:slice_size建议和训练imgsz一致,overlap0.2 到 0.3 之间。切片推理速度是整图推理的数倍,适合离线评估,不适合实时。
验证集评估时,除了看 mAP,一定要导出混淆矩阵和 PR 曲线。无人机车辆检测里最常见的误检是把屋顶、矩形阴影、路面标线识别成车。如果混淆矩阵显示背景误检率高,说明负样本不足,需要往训练集里加不含车的航拍图作为背景负样本。我习惯在训练完后跑一次model.val()并保存confusion_matrix.png,这张图比任何指标都直观。
最后一个习惯:每次改完数据或超参,先跑 10 个 epoch 看 loss 曲线趋势,再决定要不要跑满。1000 张图跑满 100 epoch 在单卡上大概 1 到 2 小时,但方向错了就是白跑。希望帮到你。
本文还有配套的精品资源,点击获取