简介:这份目标检测数据集面向从事深度学习图像识别的研究者与开发者,聚焦俯拍视角下道路交通工具与行人的检测任务,可用于智能交通监控、自动驾驶辅助系统等场景的算法训练与验证。资源包共2000个文件,以1999个txt标注文件和1个Python脚本为主,txt文件对应每张图片的YOLO格式标签,脚本可用于数据查看与处理,压缩包整体约463MB。数据集包含训练集、验证集及对应标签,图片已做旋转、缩放、裁剪、颜色变化等数据增强,类别共10类,涵盖汽车、摩托车、行人、卡车等常见道路目标,具体类别可参考class文本文件。所有数据已处理为YOLO格式,兼容YOLOv3、YOLOv4等YOLO系列网络,可直接投入训练。目前已有1614人学习下载,适合希望节省图像采集与标注成本、快速搭建并测试目标检测算法的个人或团队使用。
1. 俯拍道路数据集:为什么你的 YOLOv8 模型在无人机视角下集体翻车
去年帮一个做道路巡检的团队调模型,他们用 COCO 预训练权重直接微调,mAP 卡在 0.42 死活上不去。我把验证集的可视化结果拉出来一看就明白了——模型把俯拍画面里的电动车识别成了摩托车,把远处的人识别成了消防栓。问题不在网络结构,在数据分布。COCO 里 99% 的行人都是平视或微俯视角,而俯拍道路场景下,人的成像只有几十个像素,长宽比从 1:3 变成接近 1:1,模型学到的先验完全失效。
这就是俯拍道路交通工具与行人检测数据集要解决的核心问题。它提供超过 3000 张从高处向下拍摄的道路图像,标注了车辆、行人等目标,专门用来训练和微调在无人机、高位监控、路侧杆件视角下工作的检测模型。如果你正在做遥感图像目标检测、自动驾驶数据集补充、或者城市交通流量分析,这个方向的数据比通用数据集更对路。适合已经跑通过 YOLOv5 或 YOLOv8 训练流程、想解决俯拍场景精度掉点的从业者,新手也能跟着后面的步骤走通全流程。
2. 俯拍数据集的目标分布与标注格式:先看懂再动手
2.1 俯拍视角下四类目标的成像特征
俯拍道路场景的目标分布和常规视角差异很大。行人从直立矩形变成近似圆形或短矩形,头部和肩部占据主要像素;两轮车(电动车、自行车)的骑行者与车体在俯拍下几乎重叠,标注框容易画成一个大框;轿车和 SUV 的俯拍轮廓接近矩形,但车顶颜色受光照影响大;卡车和公交车因为长度大,在图像边缘容易被截断。
这四类目标的尺度分布也值得注意。3000 张图里,行人目标的像素面积中位数大约在 20×30 到 40×60 之间,属于小目标检测的典型范围。车辆目标稍大,但远端的车辆同样会缩到 30 像素以下。这意味着你在设置 anchor 或使用 anchor-free 头时,要针对小目标做优化,而不是直接套用 COCO 的默认配置。
标注格式常见的是 YOLO 格式(每张图对应一个 txt,每行class_id x_center y_center width height,坐标归一化到 0-1)和 VOC 格式(每张图对应一个 xml,包含 bndbox 的绝对坐标)。这个数据集如果以 YOLO 训练为主要用途,大概率是 YOLO txt 格式。拿到手第一件事不是急着训练,而是先统计类别分布和框的尺寸分布。
2.2 用脚本统计类别分布与框尺寸
下面这段代码读取 YOLO 格式的标签目录,输出每个类别的实例数量和边界框宽高的统计信息。你需要把labels_dir换成实际的标签文件夹路径,class_names换成数据集对应的类别名列表。
import os import numpy as np from collections import defaultdict labels_dir = "path/to/labels/train" class_names = ["person", "bicycle", "car", "truck"] # 按实际类别顺序修改 class_counts = defaultdict(int) box_widths = defaultdict(list) box_heights = defaultdict(list) for txt_file in os.listdir(labels_dir): if not txt_file.endswith(".txt"): continue with open(os.path.join(labels_dir, txt_file), "r") as f: for line in f: parts = line.strip().split() if len(parts) != 5: continue cls_id = int(parts[0]) w = float(parts[3]) h = float(parts[4]) class_counts[cls_id] += 1 box_widths[cls_id].append(w) box_heights[cls_id].append(h) for cls_id in sorted(class_counts.keys()): name = class_names[cls_id] if cls_id < len(class_names) else f"class_{cls_id}" ws = np.array(box_widths[cls_id]) * 1920 # 假设图像宽度 1920,按实际修改 hs = np.array(box_heights[cls_id]) * 1080 # 假设图像高度 1080,按实际修改 print(f"{name}: 实例数={class_counts[cls_id]}, " f"宽度中位数={np.median(ws):.1f}px, " f"高度中位数={np.median(hs):.1f}px, " f"面积小于32x32的比例={np.mean((ws < 32) & (hs < 32)):.2%}")逻辑说明:脚本遍历标签目录下所有 txt 文件,逐行解析 YOLO 格式的五个字段。class_counts累计每个类别的实例总数,box_widths和box_heights分别收集归一化的宽高。最后乘以假设的图像分辨率还原为像素值,计算中位数和小目标占比。
参数说明:labels_dir指向训练集标签目录,如果数据集划分了 train/val,建议分别统计。class_names的顺序必须和标注时的类别索引一致,否则统计结果会张冠李戴。图像宽高按数据集实际分辨率修改,常见俯拍数据集有 1920×1080、3840×2160 等。如果小目标占比超过 60%,后续训练必须开启小目标增强策略。
2.3 标签格式转换:VOC 转 YOLO 的四个边界坑
如果拿到的数据集是 VOC xml 格式,需要转成 YOLO txt 才能直接喂给 YOLOv8。转换逻辑本身不复杂,但有几个边界情况容易翻车。
第一个坑是坐标越界。VOC 的 bndbox 可能因为标注工具的问题出现 xmin 小于 0 或 xmax 大于图像宽度的情况,直接归一化会得到负值或大于 1 的值,YOLO 训练时虽然不会报错,但会引入噪声。第二个坑是宽高为零。标注框的 xmax 等于 xmin 时,归一化宽度为 0,训练时计算 IoU 会出问题。第三个坑是类别名大小写不一致,同一个类别在不同 xml 里写成 “Car” 和 “car”,转换后会变成两个类别。第四个坑是图像文件和标注文件不匹配,有 xml 没图片或有图片没 xml,训练时直接报 FileNotFoundError。
import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, img_w, img_h, class_map): tree = ET.parse(xml_path) root = tree.getroot() lines = [] for obj in root.findall("object"): cls_name = obj.find("name").text.strip().lower() if cls_name not in class_map: continue cls_id = class_map[cls_name] bbox = obj.find("bndbox") xmin = max(0, float(bbox.find("xmin").text)) ymin = max(0, float(bbox.find("ymin").text)) xmax = min(img_w, float(bbox.find("xmax").text)) ymax = min(img_h, float(bbox.find("ymax").text)) 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"{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") return lines逻辑说明:函数解析单个 xml 文件,遍历所有 object 节点。类别名统一转小写后查表,不在映射表里的类别直接跳过。坐标用 max 和 min 做截断,保证不越界。宽高为零的框直接丢弃。最后按 YOLO 格式拼接字符串返回。
参数说明:img_w和img_h必须和实际图像分辨率一致,不能硬编码。class_map是类别名到索引的字典,建议在转换前先扫描所有 xml 收集唯一类别名,人工确认后再生成映射。转换完成后,建议随机抽 20 张图用可视化脚本画框检查,确认没有明显偏移。
3. 用 YOLOv8 在俯拍数据集上跑通训练:从环境到第一组权重
3.1 环境搭建与数据目录组织
YOLOv8 的训练环境用 ultralytics 包最省事。Python 版本建议 3.8 到 3.10,PyTorch 按显卡驱动选对应版本。如果你用的是 30 系或 40 系显卡,装 CUDA 11.8 或 12.1 对应的 PyTorch 即可。
pip install ultralytics==8.1.0 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118安装完成后,用yolo checks确认环境状态。数据目录按 YOLOv8 的要求组织成 images 和 labels 平行结构,train 和 val 各自独立。
dataset/ images/ train/ (约 2400 张 jpg) val/ (约 600 张 jpg) labels/ train/ (对应 txt) val/ (对应 txt)如果数据集原始划分不是 8:2,建议按 8:2 重新划分。俯拍场景下,同一路段连续帧的相似度很高,随机划分会导致验证集和训练集高度重叠,mAP 虚高。更稳妥的做法是按路段或按时间段划分,确保验证集里的场景在训练集中没出现过。
3.2 data.yaml 的五个必填字段与常见写错
YOLOv8 训练依赖一个 data.yaml 描述数据集路径和类别。这个文件写错一个字段,训练直接中断。
path: /home/user/dataset train: images/train val: images/val nc: 4 names: 0: person 1: bicycle 2: car 3: truckpath是数据集根目录的绝对路径,train和val是相对于 path 的子路径。nc是类别数量,必须和 names 的长度一致。names 可以用列表或字典形式,字典形式更直观。常见错误包括:path 用了相对路径导致找不到文件;train 写成了绝对路径但 path 也写了绝对路径,拼接后路径重复;nc 写成了 5 但 names 只有 4 个,训练时索引越界。
注意:names 的顺序必须和标签里的 class_id 严格对应。如果标签里 person 是 0,names 里 person 也必须排在第一个。顺序错了模型学到的类别会整体错位,mAP 看起来正常但预测结果全错。
3.3 训练命令与六个关键参数
启动训练的命令本身很短,但参数决定了模型能不能收敛到可用精度。
yolo detect train \ data=dataset/data.yaml \ model=yolov8s.pt \ epochs=150 \ imgsz=1024 \ batch=8 \ lr0=0.001 \ patience=30 \ augment=True \ mosaic=1.0 \ scale=0.5 \ project=runs/detect \ name=road_aerial_v1model=yolov8s.pt选 small 版本是因为俯拍数据集只有 3000 张,n 版本容量太小容易欠拟合,m 或 l 版本参数量大容易过拟合。imgsz=1024比默认的 640 大,目的是保留小目标的像素信息,如果显存不够可以降到 768。batch=8是 1024 分辨率下 8G 显存的保守值,显存充足可以加到 16。lr0=0.001是初始学习率,微调预训练权重时这个值比较稳,从零训练可以调到 0.01。patience=30表示 30 个 epoch 验证集 mAP 不提升就早停,避免浪费时间。mosaic=1.0开启马赛克增强,对小目标检测帮助明显,但最后 10 个 epoch 建议关掉,让模型适应真实分布。
训练过程中重点看三个指标:metrics/mAP50看整体检测能力,metrics/mAP50-95看框的定位精度,train/box_loss和val/box_loss的差距看是否过拟合。如果 val 的 box_loss 在 50 epoch 后开始上升而 train 还在下降,说明过拟合了,需要加数据增强或减模型容量。
3.4 训练完成后的验证与可视化检查
训练结束后,用验证集跑一次评估,导出混淆矩阵和 PR 曲线。
yolo detect val \ model=runs/detect/road_aerial_v1/weights/best.pt \ data=dataset/data.yaml \ imgsz=1024 \ conf=0.25 \ iou=0.5conf=0.25是置信度阈值,低于这个值的预测框不参与评估。iou=0.5是 NMS 的 IoU 阈值。评估结果里重点关注每个类别的 AP,如果行人 AP 明显低于车辆,说明小目标问题还没解决,需要回头检查 imgsz 是否够大、mosaic 增强是否生效。
可视化检查用yolo detect predict在验证集图片上跑推理,把结果图拉出来看。重点看三类错误:漏检(行人密集区域有没有框)、误检(路边的广告牌有没有被识别成车)、定位偏差(框有没有偏到目标外面)。如果误检集中在某个特定背景(比如树荫、水面反光),说明数据里这类负样本不够,需要补充。
4. 俯拍检测的避坑与排查:五条血泪经验
4.1 现象:mAP 在 0.5 附近震荡不上升,原因:学习率与 batch 不匹配
训练日志里 mAP50 在 0.48 到 0.52 之间来回跳,loss 也不降。最常见的原因是学习率相对 batch size 偏大。YOLOv8 的默认学习率是按 batch=16 调的,如果你用 batch=8,等效学习率翻倍,优化器在损失面上来回横跳。解决办法是把 lr0 降到 0.0005,或者把 batch 加到 16(显存不够就降 imgsz)。另一个可能是数据增强太激进,mosaic 和 mixup 同时开到最大,模型看到的图和人眼看到的差异太大,学不到稳定特征。先把 mosaic 降到 0.5 试试。
4.2 现象:验证集 mAP 很高但实际推理漏检严重,原因:验证集与训练集场景重叠
前面提过,俯拍数据集如果按随机帧划分,相邻帧的相似度极高,验证集里的目标在训练集里几乎出现过。模型记住了这些特定目标而不是学会了检测。解决办法是按路段或按时间段重新划分,确保验证集里的道路场景在训练集中完全没出现。如果数据集本身没有路段信息,可以用图像哈希或聚类的方法把相似帧分到同一组,再按组划分。
4.3 现象:小目标行人漏检率超过 40%,原因:特征图下采样过多
YOLOv8 的 P3 特征图 stride 是 8,对于 20×30 像素的行人,在 P3 上只有 2×3 个格子,特征信息非常少。如果 imgsz 还是 640,行人缩到 10×15 像素,P3 上只剩 1×2 个格子,基本检测不到。解决办法是把 imgsz 提到 1024 或 1280,让行人在 P3 上有足够的响应区域。另一个办法是修改模型结构,增加 P2 检测头(stride=4),但 YOLOv8 官方没有直接开放这个配置,需要改源码。更实用的做法是在数据增强里加copy_paste,把小目标复制粘贴到不同位置,增加小目标的训练密度。
4.4 现象:训练到 80 epoch 后 val loss 突然飙升,原因:学习率调度与数据分布突变
YOLOv8 默认用余弦退火调度学习率,如果训练后期学习率降得太低,模型对当前数据分布的拟合已经饱和,突然遇到一个难样本批次就会产生大梯度,loss 飙升。解决办法是开cos_lr=True并设置warmup_epochs=5,让学习率在前 5 个 epoch 从低到高预热,避免初期震荡。如果飙升发生在某个特定 epoch,检查那一轮的数据里有没有异常样本(比如标注框全图覆盖、类别标错),把异常样本剔除后重新训练。
4.5 现象:模型把电动车和摩托车混为一类,原因:俯拍下两轮车特征重叠
俯拍视角下,电动车和摩托车的骑行者遮挡了车体的大部分,模型只能看到骑行者的头盔和肩膀,两类车的视觉差异极小。如果数据集里这两类的标注边界本身就不清晰(有的标注员把电动车标成摩托车),模型更学不明白。解决办法有两个:一是合并类别,把电动车和摩托车统一标为 “two_wheeler”,减少类间混淆;二是如果必须区分,在标注规范里明确电动车有脚踏板、摩托车有后视镜等俯拍可见特征,并补充这两类的困难样本。
5. 俯拍数据集的进阶用法:从单帧检测到多帧关联与模型微调策略
单帧检测跑通之后,如果你做的是交通流量统计或轨迹分析,下一步是把连续帧的检测结果关联起来。俯拍场景下目标运动方向一致、遮挡少,用简单的 IoU 匹配加卡尔曼滤波就能得到不错的跟踪效果。具体做法是:对每一帧跑 YOLOv8 推理,得到检测框;用 SORT 或 ByteTrack 做帧间匹配;对匹配上的轨迹统计过线次数。这里的关键参数是track_thresh和match_thresh,俯拍场景下目标位移小,match_thresh可以设到 0.8 以上,减少 ID 切换。
另一个进阶方向是用这个数据集做预训练,再迁移到你的特定场景。比如你手头只有 500 张某个园区的俯拍图,直接训练肯定过拟合。用这 3000 张道路俯拍图先训一个 base 模型,再在你的 500 张图上微调,mAP 通常比直接从 COCO 微调高 5 到 10 个点。微调时的学习率要降到 0.0001,epoch 控制在 50 以内,冻结 backbone 的前几层效果更好。
验证模型有没有真正学到俯拍特征,我常用的一个技巧是:把验证集图片上下翻转或旋转 90 度,再跑一次评估。如果 mAP 掉得很厉害,说明模型学到的是方向相关的纹理而不是目标的本质特征。俯拍场景下目标方向相对固定,这个测试能帮你判断模型是否过拟合到了特定朝向。如果掉点严重,在训练时加degrees=90的旋转增强,让模型见过各种朝向的目标。
我自己踩过最深的坑是急着上模型,没花时间看数据分布。3000 张图里如果 80% 是白天晴天,模型到了阴天或傍晚就废了。后来我养成的习惯是:拿到任何数据集,先花半天做统计和可视化,把类别分布、尺度分布、光照分布、场景分布都过一遍,再决定训练策略。这个习惯帮我省下了至少三次无效训练的时间。希望帮到你。
本文还有配套的精品资源,点击获取