简介这份资源面向无人机视觉与目标检测方向的开发者、学生及科研人员提供一套真实场景下的车辆检测数据集可用于无人机航拍车辆识别项目也可作为通用检测数据集的场景补充。数据覆盖城市道路行驶车辆、道边停车、停车场、小区车辆以及车辆遮挡、严重遮挡等多种情形类别划分为轿车car、货车van和巴士bus三类标注由labelimg完成质量较高。资源包内含1个PDF文件约2MB主要说明数据集基本情况与获取方式并配套VOC(xml)、COCO(json)、YOLO(txt)三种主流格式标签可直接接入YOLO等算法训练。此外还附赠YOLO11一键训练脚本支持GPU(GPUs)、CPU及Mac芯片多平台方案并提供博主训练结果日志供参考。目前已有261人学习适合希望快速搭建无人机车辆检测基线、验证模型效果并减少数据准备成本的读者。1. 无人机视角下的车辆检测1000 张图、三种标签格式与 YOLO11 一键训练到底能跑多快无人机航拍做车辆检测最劝退新手的从来不是模型结构而是数据这一关。你手里可能有一段航拍视频想切帧、标框、转格式、配环境、开训每一步都能卡住半天。这个标题讲的正是把这套流程压成一条链路1000 张无人机视角车辆图配 VOC、COCO、YOLO 三种标签格式再用一份脚本在 GPU、CPU、Mac 三平台上把 YOLO11 跑起来。它解决的是「有数据但跑不通」和「想复现但格式对不上」这两类问题适合做无人机视觉感知、遥感图像目标检测、边缘部署预研的从业者和研究生。下面我按自己踩过的顺序把选型理由、目录结构、格式转换、训练参数和翻车点一次讲清。2. 先想清楚无人机车辆检测的数据集该怎么选、怎么切、怎么标2.1 为什么无人机车辆检测不能直接拿 BDD100K 凑合很多人的第一反应是去下 BDD100K 或 COCO 里的 car 类觉得数据量大、标注全。但无人机视角和车载视角的成像差异是结构性的车载是低角度、近地、透视强车辆在画面里占的像素多、遮挡关系简单无人机是俯视或斜俯视车辆变成几十像素的小目标密集停车场景下框与框贴在一起背景里还有大量相似纹理车顶、路面标线、阴影。直接拿车载数据训出来的权重换到航拍图上召回率会明显掉尤其是小目标增强模块没开的时候。我一般会先确认三件事拍摄高度是否集中在 50 到 200 米、车辆像素尺度是否落在 16 到 64 像素区间、是否存在大量静止车辆。这三点决定了你要不要专门做小目标增强、要不要按尺度分层采样。1000 张图不算多所以切分策略比模型选择更关键通常按 8:1:1 分训练、验证、测试并且保证同一段视频的帧不要跨集合否则验证集精度会虚高。2.2 1000 张图的目录结构与三种格式的对应关系数据集到手后先别急着转格式把目录理清楚。常见做法是保留一份原始标注再派生出三套格式互不覆盖。下面这个结构我用了很久好处是转换脚本可以幂等重跑uav_vehicle_dataset/ ├── images/ # 全部原图jpg/png 混放也行 │ ├── 000001.jpg │ └── ... ├── annotations_voc/ # VOC每张图一个 xml │ ├── 000001.xml │ └── ... ├── annotations_coco/ # COCO单个 json │ └── instances.json ├── labels_yolo/ # YOLO每张图一个 txt │ ├── 000001.txt │ └── ... └── splits/ ├── train.txt # 每行一个图片绝对/相对路径 ├── val.txt └── test.txtVOC 的 xml 里size记录宽高、object记录name和bndboxCOCO 的 json 用images、annotations、categories三张表组织YOLO 的 txt 每行是class cx cy w h全部归一化到 0 到 1。三者信息等价差别只在组织方式。转换时最容易丢的是difficult标志和图片宽高前者影响评测口径后者一旦写错YOLO 的归一化坐标会整体偏移。2.3 标注工具与类别定义别把 car 和 truck 混成一个类标注工具用 LabelImg 出 VOC、用 CVAT 或 Roboflow 出 COCO 都行关键是类别定义要一次定死。无人机车辆检测里我建议至少区分 car、truck、bus 三类如果业务只关心「有没有车」那就只留 vehicle 一类但不要中途改。类别数变了YOLO11 的检测头输出维度就变了旧权重不能直接续训。标注时注意两个细节一是截断车辆画面边缘只露一半要不要标我一般标但会在转换时按可见比例过滤二是密集停车时框不要重叠过多IoU 超过 0.7 的重复框要在清洗阶段去掉否则训练时正样本会打架。1000 张图如果人工标按每张 30 到 60 个目标算大概需要 8 到 15 人时建议先标 100 张跑通全流程再批量标避免返工。3. 三种标签格式互转脚本、参数与四个必查边界3.1 VOC 转 YOLO归一化坐标和类别映射VOC 的bndbox是左上角和右下角的绝对像素YOLO 要的是中心点加宽高再归一化。转换脚本本身不长但类别映射表必须和data.yaml里的names顺序完全一致import os, xml.etree.ElementTree as ET # 类别顺序必须与 data.yaml 的 names 一致否则标签全错 CLASSES [car, truck, bus] CLS2ID {c: i for i, c in enumerate(CLASSES)} def voc_to_yolo(xml_dir, out_dir, img_dir): os.makedirs(out_dir, exist_okTrue) for fn in os.listdir(xml_dir): if not fn.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, fn)) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in CLS2ID: # 未定义类别直接跳过避免静默错标 continue bb obj.find(bndbox) x1 float(bb.find(xmin).text) y1 float(bb.find(ymin).text) x2 float(bb.find(xmax).text) y2 float(bb.find(ymax).text) # 裁剪到图像范围内防止标注越界导致归一化出负数 x1, y1 max(0, x1), max(0, y1) x2, y2 min(w, x2), min(h, y2) cx (x1 x2) / 2 / w cy (y1 y2) / 2 / h bw (x2 - x1) / w bh (y2 - y1) / h lines.append(f{CLS2ID[name]} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) with open(os.path.join(out_dir, fn.replace(.xml, .txt)), w) as f: f.write(\n.join(lines))逻辑说明先读size拿宽高再逐 object 取框裁剪到图像边界后做归一化。参数上CLASSES的顺序就是最终类别 id:.6f保留六位小数足够YOLO 读取时不会因为精度丢框。跑完一定要抽查随便挑一张图用cx*w反算回像素和原 xml 对比误差应在 1 像素内。3.2 COCO 与 YOLO 互转json 结构里的三个坑COCO 的 json 里bbox是[x, y, w, h]绝对像素且category_id常常从 1 开始而 YOLO 从 0 开始。转换时最容易翻车的就是这个偏移import json, os def coco_to_yolo(json_path, out_dir, img_dir): os.makedirs(out_dir, exist_okTrue) data json.load(open(json_path)) # COCO 的 category_id 可能不连续先建立 id - 连续索引 的映射 cats sorted(data[categories], keylambda x: x[id]) cat_map {c[id]: i for i, c in enumerate(cats)} img_info {im[id]: im for im in data[images]} per_img {} for ann in data[annotations]: if ann.get(iscrowd, 0): # crowd 区域不参与训练 continue im img_info[ann[image_id]] w, h im[width], im[height] x, y, bw, bh ann[bbox] cx, cy (x bw / 2) / w, (y bh / 2) / h per_img.setdefault(im[file_name], []).append( f{cat_map[ann[category_id]]} {cx:.6f} {cy:.6f} {bw/w:.6f} {bh/h:.6f}) for fname, lines in per_img.items(): stem os.path.splitext(fname)[0] with open(os.path.join(out_dir, stem .txt), w) as f: f.write(\n.join(lines))逻辑说明cat_map把原始 category_id 重映射成从 0 开始的连续索引这一步不做训练时类别会错位。iscrowd为 1 的标注要跳过否则密集区域会被当成单个大框。参数上bbox的宽高是绝对像素除以图像宽高即得归一化值。转完用wc -l统计 txt 行数和 json 里非 crowd 标注数对比数量应一致。3.3 转换后必查的四个边界第一图片宽高是否和标注一致尤其是有 EXIF 旋转的 jpg读出来的宽高可能和标注时相反。第二空标签文件要不要保留YOLO 训练时全背景图可以留但要在data.yaml里确认不会被当成损坏样本。第三类别 id 是否连续且从 0 开始中间断号会让模型输出维度对不上。第四坐标是否越界归一化后出现负数或大于 1 的值训练时会被裁掉或报错。这四条我每次转完都跑一遍比训到一半发现标签错要省事得多。4. YOLO11 一键训练脚本三平台环境、参数与显存控制4.1 GPU、CPU、Mac 三平台的环境差异YOLO11 基于 Ultralytics 框架三平台的核心差异在推理后端。GPU 走 CUDA需要装对应版本的 PyTorchCPU 走默认后端速度慢但兼容性最好Mac 走 MPSApple Silicon 上能吃到统一内存的红利但部分算子支持不全。我一般用 conda 建独立环境避免和系统 Python 打架# GPU 机器以 CUDA 12.1 为例具体版本按显卡驱动选 conda create -n yolo11 python3.10 -y conda activate yolo11 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install ultralytics # MacApple Silicon conda create -n yolo11 python3.10 -y conda activate yolo11 pip install torch torchvision # 默认带 MPS 支持 pip install ultralytics参数说明Python 选 3.10 是因为 3.12 上部分依赖轮子还不全--index-url指定 CUDA 版本装错会出现torch.cuda.is_available()返回 False。装完先验证import torch print(torch.__version__, torch.cuda.is_available()) # GPU 机器应为 True print(torch.backends.mps.is_available()) # Mac 应为 True4.2 data.yaml 与一键训练脚本data.yaml是训练入口路径写错是最常见的失败原因。我习惯用绝对路径避免工作目录变化导致找不到图path: /data/uav_vehicle_dataset train: splits/train.txt val: splits/val.txt test: splits/test.txt nc: 3 names: [car, truck, bus]一键训练脚本把设备判断、参数和日志串起来三平台共用一份from ultralytics import YOLO import torch def pick_device(): if torch.cuda.is_available(): return 0 # 单卡 GPU if torch.backends.mps.is_available(): return mps # Apple Silicon return cpu if __name__ __main__: model YOLO(yolo11n.pt) # n 版最轻适合 1000 张图起步 model.train( datadata.yaml, epochs100, imgsz640, # 无人机小目标可提到 960但显存翻倍 batch16, # CPU/Mac 建议降到 4 或 8 devicepick_device(), workers4, projectruns/uav_vehicle, nameexp1, patience20, # 20 轮无提升就早停 cacheTrue, # 1000 张图可全缓存进内存 )逻辑说明pick_device按可用性依次选 GPU、MPS、CPU避免手动改代码。imgsz是输入分辨率无人机小目标建议 960但显存占用约为 640 的 2.25 倍8G 显存卡上 batch 要相应降到 8。patience设 20 能省下大量无效训练时间。cacheTrue对 1000 张图很划算首次读盘后后续 epoch 不再 IO 等待。4.3 关键参数怎么调从 batch 到小目标增强batch和imgsz是一对联动参数显存不够时优先降 batch再考虑降 imgsz因为分辨率直接决定小目标能否被检出。学习率默认 0.011000 张图这种小数据集建议降到 0.001 到 0.005否则前期 loss 震荡明显。workers在 Windows 上设太高会卡死4 到 8 比较稳。如果车辆普遍小于 32 像素可以开 YOLO11 的小目标增强相关配置或者把imgsz提到 1280 并配合 mosaic 增强但要注意标注框在缩放后是否仍然准确。训练启动后重点看三个信号box_loss是否稳定下降、mAP50是否在 30 轮后开始爬升、验证集 loss 是否早于训练集反弹。如果 mAP 一直不动先查标签而不是调模型十有八九是类别映射或路径问题。5. 避坑与排查训练跑不通时先看这五条5.1 现象训练一开始就报找不到图片原因data.yaml里的path和train拼接后路径不对或者 txt 里写的是相对路径但工作目录变了。解决把train.txt里的路径改成绝对路径或者统一用path加相对路径的写法跑之前用head splits/train.txt确认路径真实存在。5.2 现象mAP 始终为 0 或极低原因类别 id 错位或者 VOC 转 YOLO 时CLASSES顺序和names不一致。解决抽一张图把 txt 里的类别 id 反查names看是否和图上目标对得上再检查nc是否等于len(names)。这个坑我踩过不止一次标签对不上时模型学到的全是噪声。5.3 现象GPU 显存溢出CUDA out of memory原因imgsz或batch太大或者cacheTrue把全部图片缓存进显存。解决先把 batch 减半再考虑降 imgszcache改成disk或 False。Mac 上如果 MPS 报算子不支持退回 CPU 跑通流程再换设备。5.4 现象CPU 训练慢到无法接受原因CPU 上 640 分辨率、1000 张图、100 epoch 可能要跑十几个小时。解决先用yolo11n加imgsz416、epochs30跑一个基线确认流程通了再上 GPU 全量训。CPU 只适合验证脚本正确性不适合出最终权重。5.5 现象验证集精度高但实测漏检严重原因切分时同一段视频的帧跨了训练和验证集导致验证集泄漏。解决按视频源或拍摄架次切分而不是随机切帧。另外检查测试集是否包含不同光照和高度1000 张图如果全是一个场景泛化能力本身就有限别指望模型能跨场景直接可用。6. 把 1000 张图用出 10000 张的效果增强、验证与迭代习惯数据量固定时提升空间主要在增强策略和验证方法上。我一般先跑一个不做额外增强的基线记录 mAP50 和各类别 AP再逐步加 mosaic、mixup、随机缩放。无人机视角下随机缩放和随机裁剪对小目标帮助最大但裁剪比例不要超过 0.3否则车辆被裁碎反而伤召回。mosaic 能提升小目标但训练后期建议关掉让模型在真实分布上收敛。验证时别只看 mAP要分尺度看。把测试集按目标像素面积分成小小于 32²、中、大三档分别统计召回率。无人机车辆检测的瓶颈几乎总在小目标档如果小目标召回低于 0.4优先提imgsz或加小目标增强而不是换更大的模型。下面这张表是我常用的验证记录模板指标基线加 mosaic加缩放提 imgsz 到 960mAP500.520.580.610.67小目标召回0.310.380.420.55推理耗时GPU8ms8ms8ms15ms迭代习惯上我坚持每次只改一个变量并把runs/下的结果目录按实验名归档避免「上次那个好结果找不到了」。1000 张图训到 mAP50 0.6 以上是合理预期再往上要么补数据要么做针对性增强。最后一句血泪经验先把标签和切分做对再谈模型和参数顺序反了调多久都是玄学。希望帮到你。本文还有配套的精品资源点击获取