ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

无人机车辆检测实战:1000张图、三种标签格式与YOLO11跨平台训练

无人机车辆检测实战:1000张图、三种标签格式与YOLO11跨平台训练 简介这份资源面向无人机视觉与目标检测方向的开发者、研究生及算法工程师提供一套真实场景下的车辆检测数据集可用于无人机航拍车辆识别项目也可作为通用车辆检测数据的场景补充。数据集共1000张高质量图片覆盖城市道路行驶车辆、道边停车、停车场、小区车辆以及车辆遮挡与严重遮挡等多种情形类别划分为轿车car、货车van和巴士bus三类均经labelimg精细标注并同步提供VOC(xml)、COCO(json)、YOLO(txt)三种主流格式可直接投入YOLO等算法训练。资源包为1个PDF文件约2MB内含数据集基本情况介绍与获取方式因数据本体较大故托管于网盘。随附YOLO11一键训练脚本支持GPU、CPU及MacM芯片多平台方案并给出博主训练结果日志供参考。目前已有261人学习下载适合希望快速验证无人机车辆检测方案、减少数据准备成本的读者。1. 无人机视角下的车辆检测1000 张图、三种标签格式与 YOLO11 一键训练到底能不能落地拿到这个标题多数人第一反应是「数据集 训练脚本」的常规组合但真正卡住工程进度的往往不是模型本身而是标签格式转换和跨平台环境这三件脏活。无人机航拍车辆检测和地面固定摄像头完全是两个问题视角俯仰变化大、车辆像素占比小、运动模糊和光照突变频繁公开的车辆检测数据集 bdd100 这类车载视角数据迁移过来会明显掉点。这个方案给的是 1000 张无人机视角图配 VOC、COCO、YOLO 三种格式标签外加支持 GPU、CPU、Mac 三平台的 YOLO11 一键训练脚本。它适合两类人一是想快速验证无人机视觉感知链路是否跑得通的算法工程师二是手头有少量自有航拍图、需要一个能直接改的基线工程的学生或独立开发者。1000 张不算多但作为迁移学习的起点和格式转换的模板够用。2. 三种标签格式的差异与转换VOC、COCO、YOLO 到底该用哪个2.1 三种格式的坐标系与文件组织差异VOC 格式的核心是 XML 文件每张图对应一个同名.xml边界框用xmin/ymin/xmax/ymax四个绝对像素值表示坐标原点在左上角。它的好处是可读性强、工具链老牌LabelImg 默认就输出这个。缺点是文件数量翻倍1000 张图就是 1000 个 XML批量处理时 IO 压力不小。COCO 格式把所有标注塞进一个 JSON 文件结构分images、annotations、categories三段边界框用[x, y, width, height]表示同样是绝对像素但id映射关系必须严格对应错一个 id 整批数据就废了。它适合做多类别、多任务检测 分割 关键点的统一管理但手写容易出错。YOLO 格式最简洁每张图一个.txt每行class_id x_center y_center width height全部是归一化到 0~1 的相对值。它没有冗余信息训练时读取最快但可读性差脱离图片根本看不出框在哪。格式单图标注文件坐标类型类别表示典型工具VOC.xml绝对像素标签名LabelImgCOCO单一 .json绝对像素数字 id 名称映射Labelme、CVATYOLO.txt归一化相对值数字 idLabelImg、Roboflow选哪个取决于你的下游任务。只跑 YOLO11 训练直接用 YOLO 格式最省事要做多模型对比或接入 MMDetectionCOCO 更通用VOC 适合作为中间交换格式因为转换脚本最多、容错性最好。2.2 VOC 转 YOLO 的完整脚本与四个边界坑下面这个脚本是我常用的 VOC 转 YOLO 版本处理 1000 张图大约几秒跑完。关键点在于归一化时的除零保护和类别映射的一致性。import os import xml.etree.ElementTree as ET # 类别映射必须与 data.yaml 中的 names 顺序一致 CLASS_MAP {car: 0, truck: 1, bus: 2, van: 3} def voc_to_yolo(xml_dir, img_dir, out_dir): 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() # 读取图片宽高用于归一化 size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) if img_w 0 or img_h 0: print(fskip zero size: {xml_file}) continue lines [] for obj in root.findall(object): cls_name obj.find(name).text.strip() if cls_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 max(0, min(xmin, img_w)) xmax max(0, min(xmax, img_w)) ymin max(0, min(ymin, img_h)) ymax max(0, min(ymax, img_h)) if xmax xmin or ymax ymin: continue x_center (xmin xmax) / 2.0 / img_w y_center (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{CLASS_MAP[cls_name]} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) out_path os.path.join(out_dir, xml_file.replace(.xml, .txt)) with open(out_path, w) as f: f.write(\n.join(lines)) voc_to_yolo(./annotations_xml, ./images, ./labels_yolo)逻辑说明先解析 XML 拿到图片宽高再把每个 object 的绝对坐标转成归一化中心点加宽高。参数方面CLASS_MAP必须和训练时data.yaml的names列表顺序完全一致否则模型学到的类别会整体错位。四个容易翻车的边界坑一是xmin可能为负或超过图宽无人机图边缘截断车辆很常见必须裁剪二是xmax xmin的退化框要直接丢弃否则归一化后宽高为负训练时 loss 直接 NaN三是类别名大小写和空格car和Car 会被当成两个类四是 XML 里size字段偶尔缺失需要加异常捕获或从图片实际尺寸读取。2.3 COCO 与 YOLO 互转时 id 映射的坑COCO 转 YOLO 时annotations里的category_id往往不是从 0 连续开始的比如 COCO 官方 80 类里person是 1但你的数据集可能只有 4 类且 id 是 1、3、7、9。直接拿category_id当 YOLO 的class_id会导致类别索引越界或空洞。正确做法是建一个category_id - 连续索引的映射表再写入 txt。反过来 YOLO 转 COCO 时image_id和annotation_id必须全局唯一1000 张图如果每张平均 5 个框就是 5000 个 annotationid 重复会让评估脚本报错。我一般用递增计数器生成不用图片名哈希避免碰撞。3. YOLO11 在 GPU、CPU、Mac 三平台的训练脚本拆解3.1 一键脚本的目录结构与参数入口一个能跨三平台跑的脚本核心是把设备检测和路径处理做成自动的而不是写死device0。下面是我常用的train.py骨架配合data.yaml使用。import os import torch from ultralytics import YOLO def pick_device(): if torch.cuda.is_available(): return 0 # 单卡 GPU if torch.backends.mps.is_available(): return mps # Apple Silicon return cpu def main(): device pick_device() print(fusing device: {device}) model YOLO(yolo11n.pt) # 从预训练权重起步 model.train( dataos.path.abspath(./data.yaml), epochs100, imgsz640, batch16 if device ! cpu else 4, devicedevice, workers4 if device ! cpu else 0, project./runs, namedrone_vehicle, patience20, cacheFalse, ) if __name__ __main__: main()逻辑说明pick_device按 CUDA、MPS、CPU 的优先级返回设备字符串Ultralytics 内部会自动解析。参数上imgsz640是无人机小目标检测的常用起点再小会丢车辆细节再大 CPU 和 Mac 显存扛不住。batch在 CPU 上必须降到 4 甚至 2否则内存直接爆。workers在 Mac 和 Windows 上设 0 可以避免多进程 dataloader 的玄学卡死。patience20表示 20 轮无提升就早停1000 张图通常 60~80 轮就收敛。data.yaml的内容如下路径建议用绝对路径相对路径在不同平台的工作目录下容易翻车path: /abs/path/to/dataset train: images/train val: images/val names: 0: car 1: truck 2: bus 3: van3.2 GPU、CPU、Mac 三平台的实测差异与参数调整GPU 平台以单卡 8G 显存为例batch16、imgsz640下显存占用约 5~6G100 轮大约 40 分钟。如果显存只有 4G把batch降到 8同时开ampTrue默认开启用混合精度省显存。注意cacheTrue会把 1000 张图全部读进内存GPU 机器内存够的话能提速 20% 左右但内存小于 16G 别开。CPU 平台这是最容易被低估的场景。batch4、imgsz640下1000 张图 100 轮可能要跑 6~10 小时取决于 CPU 核心数。建议把imgsz降到 512epochs降到 50先验证链路通不通。workers设 0 避免进程调度开销。CPU 训练时torch的线程数可以用torch.set_num_threads(os.cpu_count())显式设置默认有时只用一个核。MacApple SiliconMPS 后端对 YOLO11 的支持已经比较稳定但有几个已知问题。一是某些算子会回退到 CPU导致速度不如预期可以在训练日志里看mps和cpu的切换频率。二是batch超过 16 容易触发内存不足建议 8。三是 MPS 上amp混合精度支持不完整遇到 NaN 就把ampFalse关掉。M 系列芯片跑 1000 张图 100 轮大约 1.5~3 小时比 CPU 快但远慢于 GPU。提示三平台切换时runs目录下的权重文件不通用GPU 训练的.pt可以在 CPU 和 Mac 上推理但反过来 MPS 训练的权重在 CUDA 上加载偶尔会报设备不匹配建议推理时统一用model.to(cpu)再加载。3.3 训练前必须检查的数据集划分与缓存1000 张图按 8:1:1 划分训练 800、验证 100、测试 100。划分脚本要保证同一场景的连续帧不会同时出现在训练和验证集里否则验证指标虚高。无人机航拍如果是视频抽帧相邻帧几乎一样随机划分会让验证集泄漏。我一般按拍摄批次或时间戳分组划分。import os, random, shutil def split_dataset(img_dir, label_dir, out_root, ratios(0.8, 0.1, 0.1)): imgs sorted([f for f in os.listdir(img_dir) if f.endswith((.jpg, .png))]) random.seed(42) random.shuffle(imgs) n len(imgs) n_train int(n * ratios[0]) n_val int(n * ratios[1]) splits { train: imgs[:n_train], val: imgs[n_train:n_train n_val], test: imgs[n_train n_val:], } for split, files in splits.items(): img_out os.path.join(out_root, images, split) lbl_out os.path.join(out_root, labels, split) os.makedirs(img_out, exist_okTrue) os.makedirs(lbl_out, exist_okTrue) for f in files: shutil.copy(os.path.join(img_dir, f), os.path.join(img_out, f)) lbl f.rsplit(., 1)[0] .txt src_lbl os.path.join(label_dir, lbl) if os.path.exists(src_lbl): shutil.copy(src_lbl, os.path.join(lbl_out, lbl)) split_dataset(./images, ./labels_yolo, ./dataset)逻辑说明random.seed(42)保证可复现shutil.copy保留原文件不动。参数ratios可以按数据量调整1000 张用 8:1:1 合适如果只有 300 张建议 7:2:1 给验证集多一点。划分后检查labels/train和images/train的文件名是否一一对应缺 label 的图会被 Ultralytics 自动跳过但不会报错容易漏掉。4. 无人机车辆检测的避坑与排查从 loss 不降到框全偏4.1 训练 loss 不下降或震荡现象前 10 轮box_loss和cls_loss几乎不动或者来回跳。原因通常是学习率过大或数据标签有问题。先检查data.yaml的names数量和标签里的class_id最大值是否一致不一致会静默忽略越界类别。再确认图片路径没有中文和空格Ultralytics 在某些版本对中文路径支持不好。解决把lr0从默认 0.01 降到 0.001batch调小先用 10 张图过拟合测试如果 10 张都学不会一定是标签或路径问题不是模型问题。4.2 验证集 mAP 正常但推理框全偏现象训练日志里mAP50有 0.6 以上但拿单张图推理时框位置明显偏移或尺寸不对。原因多半是推理时的imgsz和训练不一致或者图片在预处理时被 letterbox 填充后坐标没还原。解决推理时显式指定imgsz640和训练保持一致。如果用的是自己写的后处理检查 letterbox 的缩放比例和 padding 偏移有没有正确逆变换。另一个常见原因是验证集和测试集的图片方向EXIF不同手机或无人机拍的图带旋转信息PIL 读取时可能自动旋转而 OpenCV 不会导致坐标错位。4.3 Mac 上 MPS 报错或速度异常慢现象训练几轮后报MPS backend out of memory或Placeholder storage has not been allocated。原因是 MPS 的内存管理和 CUDA 不同缓存不会自动释放。解决把batch降到 4 或 8imgsz降到 512关掉cache。如果报算子不支持设置环境变量PYTORCH_ENABLE_MPS_FALLBACK1让不支持的算子回退 CPU但速度会掉。速度异常慢时检查是否误用了devicecpuMPS 设备字符串是mps不是gpu。4.4 小目标漏检严重现象大车能检出远处小车几乎全漏。原因是 640 分辨率下无人机 100 米高度拍的车辆可能只有 10~20 像素YOLO11 的 P3 特征图下采样 8 倍后只剩 1~2 个像素。解决把imgsz提到 1280 做对比实验或者用切片推理SAHI把大图切小块分别检测再合并。另一个方向是改模型结构在 YOLO11 里增加 P2 检测头但 1000 张图训 P2 容易过拟合建议先试切片推理。4.5 类别不平衡导致 bus 和 van 几乎检不出现象car 的 AP 有 0.7bus 和 van 只有 0.1。原因是 1000 张图里 car 占 80% 以上bus 和 van 样本太少。解决先用cls_pw类别权重Ultralytics 默认开启但效果有限。更直接的是对少数类做过采样把含 bus 和 van 的图复制多份或者用 mosaic 和 mixup 增强时提高少数类参与概率。如果 bus 和 van 加起来不到 50 个框建议合并成一个large_vehicle类先保证检出不漏再考虑细分。5. 用 1000 张图把 YOLO11 微调到可用的进阶技巧1000 张图做无人机车辆检测如果直接从头训mAP50 大概在 0.4~0.5 徘徊。我的习惯是分两阶段第一阶段用 COCO 预训练的yolo11s.pt冻结 backbone 训 30 轮让检测头先适配车辆类别第二阶段解冻全部层用余弦退火学习率训 70 轮。冻结阶段lr00.001解冻后lr00.0005lrf0.01。这样比直接端到端训收敛更稳最终 mAP50 通常能到 0.65~0.75取决于标注质量。验证时不要只看mAP50无人机场景要单独统计小目标面积小于 32x32的AP_small。Ultralytics 的验证输出里默认不细分尺寸可以用model.val(splittest)后手动按框面积过滤统计。另一个实用技巧是导出 ONNX 后用onnxruntime测单图延迟GPU 上 YOLO11n 在 640 分辨率大约 5~8msCPU 上 80~150msMac MPS 上 20~40ms。这些数字决定你能不能上机载实时推理。最后说个我踩过的坑有次训完发现验证集 mAP 很高但实际飞的时候框全在车后面拖一截。查了两天才发现是标注时用了视频抽帧的上一帧坐标标签和图片错位了一帧。1000 张图里如果有几十张这种错位模型就会学出系统性偏移。所以拿到数据集第一件事不是训是随机抽 20 张把框画到图上肉眼过一遍。这个习惯帮我省了无数次后悔药。希望帮到你。本文还有配套的精品资源点击获取
返回列表