资讯动态

自动驾驶多类车辆检测数据集:解压、体检与YOLO格式转换实战

发布时间:2026/10/5 5:22:56 来源:尧图企业网站定制
简介面向自动驾驶感知与智能交通领域的YOLO格式多类车辆检测数据集适合目标检测算法研究者、自动驾驶开发者和计算机视觉入门学习者使用。数据共1251张真实道路场景图片覆盖自行车、公交车、轿车、摩托车、卡车五类交通参与者训练集与验证集严格按90%/9%比例划分为模型训练与评估提供标准化基础。压缩包内含2000个文件其中1251个txt标注文件、747张jpg道路图片、1个yaml数据集配置及1个docx说明文档总计68.64MB可无缝接入YOLOv3/v5/v7/v8等主流检测框架。数据集以专业团队标注并验证类别标注准确率达99.2%边界框贴合车辆轮廓兼顾不同光照与角度特征能够支撑碰撞预警、盲区监测、交通流量统计等典型应用开发。已有98人下载学习适合作为车辆检测方向模型验证与实践训练的高质量行业数据来源。1. 自动驾驶多类交通车辆检测数据集先别急着训练先做数据体检一个「自动驾驶多类交通车辆检测数据集.zip」压缩包几乎是每个做车载视觉的工程师都会经手一次的东西。它听起来只是“一堆图片加标注”实际上里面装着 car、truck、bus、motorcycle、bicycle 等类别标注格式可能是 COCO 的 json、VOC 的 xml也可能是 YOLO 的 txt三者的组织方式和坑完全不同。对于刚转自动驾驶感知的算法工程师或者准备用 YOLOv8 训练自己车辆检测模型的开发者来说这个压缩包能不能真正落地取决于你是否愿意在解压后先花半小时做数据体检。一个反直觉的结论是拿到数据集的第一件事不是开训而是查标注质量否则 loss 不收敛时你分不清是模型问题还是数据问题。2. 拆压缩包三种标注格式与类别分布先对齐解压之后先别急着点开图片看先用一条命令看清目录层级。常见的包会是 images/ 与 annotations/ 两套目录前者放 jpg 或 png后者放 json 或 xml 或 txt。这三套东西代表三种完全不同的数据组织思路后面所有的转换、训练、评测都建立在对它们的正确理解上。这个环节如果看走眼后面的格式转换脚本就会写出一个能跑但结果全错的版本这是最花时间的坑。2.1 一套数据三种格式COCO、VOC、YOLO 怎么选多类车辆检测数据集的标注格式跑不出下面这三套。拿到压缩包后第一件事就是确认它属于哪一种再去判断后续怎么做格式转换。格式存储方式坐标形式主要风险COCO一个 instances_*.json 管所有标注绝对值 xywh左上角 宽高image_id 与文件名映射一旦断裂全盘作废VOC每张图配一个同名 xml绝对值 xmin/ymin/xmax/ymax文件数量多目录层级深读起来慢YOLO每张图配一个同名 txt归一化到 [0,1] 的 cx, cy, w, h没有类别名对照表必须另维护 classes.txt如果解压后看到的是单个 json 文件大概率是 COCO 组织方式。它在自动驾驶多类车辆检测里用得最多原因是类别多、实例密集十字路口一张图里同时出现 20 辆车是常态。json 结构可以按 image_id 快速索引到所有目标也方便表达 iscrowd 这类忽略区域——比如密集车流中标注者只标了前排车后排模糊车标成 iscrowd1训练时就可以把这块排除掉不让模型去学那些模糊目标。VOC 适合小规模数据集一张图一个 xml坏一张不影响整体但类别一旦上到 8 类、图片上到几万张文件数量会让你在预处理阶段就烦躁。YOLO 格式则最贴近训练环节YOLOv5/v8 喂进去就能跑但一个 txt 只存数字缺少语义信息一旦需要按类别过滤或做数据清洗还得回头找类别表。这也是为什么我拿到压缩包后第一眼会去看 annotations 目录里的文件后缀。还有一点要注意有的包为了“方便”把 COCO 的 json 和 YOLO 的 txt 同时给你但两份标注可能来自不同版本、坐标对不上。遇到这种情况以图像为准做一次画框体检见 3.2不要相信任何 README 里“已对齐”的描述。数据标注的对齐不是靠声明而是靠可视化验证。像 bdd100k、CCPD 这类公开数据集都有自己的固定格式但压缩包里的数据集往往是二次加工的谁也不能保证加工过程没有改动过类别 id 或坐标参考系。2.2 用脚本统计每类有多少框iscrowd 与长尾类别在决定转格式之前先写一个统计脚本把每类实例数、图片数、iscrowd 数量打出来。这个脚本很便宜但能省掉后面判断类别不均衡的力气。import json from collections import defaultdict def stats_coco(coco_path: str): with open(coco_path) as f: data json.load(f) # category_id 可能从 1 开始甚至带空缺先建一个 id - name 的映射 cat_map {c[id]: c[name] for c in data[categories]} inst defaultdict(int) # 每类的实例总数 imgs defaultdict(set) # 每类出现在多少张图里 crowd defaultdict(int) # 每类的 iscrowd 数量 for ann in data[annotations]: cid ann[category_id] inst[cid] 1 imgs[cid].add(ann[image_id]) if ann.get(iscrowd, 0): crowd[cid] 1 for cid, name in cat_map.items(): print(f{name:12s} id{cid:2d} inst{inst[cid]:6d} images{len(imgs[cid]):4d} crowd{crowd[cid]:4d})这段代码的逻辑是遍历所有 annotation按 category_id 聚合三类信息实例总数、覆盖的图片数、iscrowd 数量。跑完之后你会得到一张类似上面表格的数据分布图。关注的第一个数字是 inst 总量car 类可能有几万个框motorcycle 类也许只有几百个这种长尾分布直接决定了后续训练的采样策略。第二个数字是 crowd 数量如果一个类别的 crowd 占比超过 10%说明这个包里大量标注是“模糊目标”训练时直接把 iscrowd 丢弃会让正样本数量进一步缩水需要重新评估。参数说明cat_map 用 enumerate 重建而不是直接用原始 id 是有原因的。很多二次加工的数据集json 里 categories 的顺序与 id 可能不一致比如 id 为 3 的类别排在数组第一位。直接用原 id 做统计没问题但后面转 YOLO 格式时如果也直接沿用原 idclasses.txt 与训练配置里 names 的对应关系就容易错位。所以这里只用于统计4.1 节的转换脚本里会有一个独立的重映射逻辑。另一个细节是 imgs 用的是 set避免同一张图里 20 个同类目标被重复计入图片数影响你对“这个类别到底有多少张图”的判断。3. 解压与数据体检训练前必做的 3 个检查很多人在解压后直接打开一张图看一眼觉得“挺清楚的”然后就开始写训练脚本。这个习惯在自动驾驶数据集上会翻车因为一张图画得清楚不代表标注框没问题。我一般会对压缩包做三个检查zip 完整性、目录结构、画框体检。这三个检查加起来不超过半小时但能避免后面几天的无效训练。3.1 先验包再解压unzip -t 与中文文件名乱码先做完整性测试再解压再清理垃圾文件。命令行按这个顺序走# 1. 先验证 zip 是否完整-t 会逐个文件做 CRC 校验 unzip -t 自动驾驶多类交通车辆检测数据集.zip # 2. 静默解压到 raw 目录-q 表示安静模式去掉可以看到每个文件 unzip -q 自动驾驶多类交通车辆检测数据集.zip -d raw/ # 3. 只看两层目录看清结构和有没有隐藏垃圾目录 tree -L 2 raw/为什么要先跑 unzip -tzip 文件在网盘或微信传输里被截断的概率比想象中高而 jpg/png 文件一旦被截断看图软件依然能打开前半部分不会给你任何报错。只有 CRC 校验能发现这种“看起来正常实际已损坏”的文件。unzip -t 的输出中只要出现 mismatch 或 CRC error就不要继续用这个压缩包重新获取或比对 SHA-256 哈希。这一步能避免训练到一半突然报 “corrupt JPEG data” 这类让人血压升高的错误。参数说明-d 指定解压目录避免把一堆文件夹直接撒在当前目录tree -L 2 限制层级解压后刷屏反而看不清结构。如果你的压缩包是在 Windows 下打包、包含中文文件名在 Linux 下解压会出现乱码unzip -O GBK 可以处理大多数字符集但 6.0 以下版本可能不支持 -O 选项。这种情况我会改用 7-Zip 的命令行工具7z x 文件名.zip -o raw/ 对中文编码的处理更宽松一些。另外解压完成后大概率会出现 _MACOSX 目录和一堆 .开头的 AppleDouble 文件这是 macOS 打包工具留下的垃圾训练脚本读取目录时它们会混进来干扰标签匹配直接用 rm -rf __MACOSX 清理掉。3.2 画框体检20 张随机图找出标注错位与越界格式确认、统计做完之后画框体检是不可跳过的一步。只看坐标数字你分不清这套标注的坐标系是绝对值还是归一化、框顺序是 xyxy 还是 xywh、类别 id 是否从 0 开始。这些信息画到图上一眼就能看出来。import json import cv2 import os import random def draw_check(json_path: str, img_dir: str, out_dir: str, sample: int 20): os.makedirs(out_dir, exist_okTrue) with open(json_path) as f: data json.load(f) # COCO 里 image_id 不一定是文件名必须通过 images 字段映射 id2file {im[id]: im[file_name] for im in data[images]} anns {} for ann in data[annotations]: # 按 image_id 分组方便一次画完一张图的所有框 anns.setdefault(ann[image_id], []).append(ann) picked random.sample(list(anns.keys()), min(sample, len(anns))) for img_id in picked: path os.path.join(img_dir, id2file[img_id]) img cv2.imread(path) if img is None: print(f[skip] 图像读不出来: {path}) continue h, w img.shape[:2] for ann in anns[img_id]: if ann.get(iscrowd, 0): continue # 忽略区域不画避免干扰判断 x, y, bw, bh ann[bbox] # COCO bbox 是 xywh 绝对值 x2 min(w, int(x bw)) y2 min(h, int(y bh)) # 画框时 clip 到图像边界否则越界框会画出画布外 cv2.rectangle(img, (int(x), int(y)), (x2, y2), (0, 255, 0), 2) cv2.imwrite(os.path.join(out_dir, fcheck_{img_id}.jpg), img)这段脚本做的事情是随机抽 20 张图把每张图的所有目标框用绿色矩形叠加到原图上另存在 out_dir 里。逻辑上先把 annotation 按 image_id 分组避免遍历 5 万条标注时反复搜索然后逐图逐框画矩形跳过 iscrowd 区域。画完后面临的关键判断是如果 20 张图里出现大量框明显偏出车身、框到背景绿化带或路灯、或者类别与框内目标不符比如轿车的框套在一辆卡车身上说明这套标注本身有问题接下来转格式没有意义。如果只是 1-2 个框越界 1 像素属于公开数据集常态clip 后不影响训练。参数说明COCO 的 bbox 是 xywh即左上角 x、左上角 y、宽、高。如果你画出来的框位置是错位 90 度旋转后的效果说明这个 bbox 实际是 xyxy 格式左上角 右下角那是另一个数据组织方式。另外框坐标存在 json 里是 float画图时必须 int()否则 cv2.rectangle 会报类型错误。越界框如果超过 5%就得回去查标注来源而不是靠 clip 硬救。这一步输出的 check_*.jpg 我通常会留到训练结束后再翻一遍黑匣子一样的数据集只有可视化才是唯一可信的检验标准。4. 转成 YOLO 格式并跑通训练从 zip 到第一个 mAP体检没问题之后进入正题把数据转成 YOLOv8 能直接读的格式然后跑通一个最小训练。这个阶段的目标不是刷高 mAP而是验证整条链路跑得通并产出一个可以迭代的 baseline。先转格式再训小模型确认 loss 在降、val 能出框再换大规模长时间训练。4.1 COCO 转 YOLO坐标归一化、iscrowd 过滤与退化框清理YOLOv8 原生吃每张图一个 txt 的格式内容是 class cx cy w h全部归一化到 [0,1]。这一步要做的不只是坐标换算还有三个过滤逻辑iscrowd 丢弃、越界裁剪、退化框过滤。import json import os coco_path annotations/instances_train.json out_dir labels/train os.makedirs(out_dir, exist_okTrue) MIN_WH 0.001 # 归一化后宽或高小于该值视为退化框 MIN_AREA 24 # 可选像素面积过滤小目标多的场景谨慎开启 with open(coco_path) as f: data json.load(f) # 重映射类别 id 到 0..N-1 连续区间避免训练时类别索引跳跃 cat_map {c[id]: i for i, c in enumerate(data[categories])} img_map {im[id]: im for im in data[images]} anns {} for ann in data[annotations]: anns.setdefault(ann[image_id], []).append(ann) for img_id, ann_list in anns.items(): im img_map[img_id] w_img, h_img im[width], im[height] lines [] for ann in ann_list: if ann.get(iscrowd, 0): continue # 模糊区域不参与训练 cid cat_map[ann[category_id]] x, y, bw, bh ann[bbox] area bw * bh if area MIN_AREA: continue # 小于 24 像素的框基本是标注噪声 # 转中心点坐标并归一化 cx (x bw / 2.0) / w_img cy (y bh / 2.0) / h_img nw min(1.0, bw / w_img) nh min(1.0, bh / h_img) # 越界裁剪保证坐标在 [0,1]避免 CIoU 对 log 取数值崩溃 nw max(MIN_WH, nw) nh max(MIN_WH, nh) lines.append(f{cid} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}) base os.path.splitext(im[file_name])[0] with open(os.path.join(out_dir, base .txt), w) as f: f.write(\n.join(lines))这个脚本的逻辑分四段读取 json 并建立 image 索引、遍历所有标注、逐框做坐标换算和过滤、写出与图片同名的 txt。其中值得说明的是 iscrowd 的处理YOLO 没有 ignore 机制把一个 20 辆车密集排布的 iscrowd 区域当正样本或背景都不合适最稳妥的做法是一开始就丢弃而不是留着让模型产生困惑。MIN_AREA 过滤我在这里保留了因为它能有效清掉一批小于 24 像素的极模糊目标。但如果你后续发现小目标漏检特别严重建议把 MIN_WH 和 MIN_AREA 的阈值调低或注释掉回归数据本身看看到底是标注质量问题还是模型能力问题。参数说明cat_map 用 enumerate 重建这是最容易忽略的一步。原始 COCO 的 category_id 可能从 1 开始直接写成 txt 会导致训练时类别索引从 1 起跳与 data.yaml 里的 names 列表错位。越界裁剪这边我特意用 min(1.0, ...) 而不是直接减一半坐标因为很多公开数据集的框会越界 1-2 像素裁剪到 1.0 就能救回来基于中心点的换算方式在大幅越界时会失去意义。最后写的 txt 文件名必须与图片完全同名YOLOv8 是通过后缀名匹配去找标签的任何大小写不一致都会导致训练时检不到标签。4.2 用 YOLOv8 训练data.yaml、imgsz 与先训小模型转换完成后写一个 data.yaml。这个文件是 YOLOv8 读取数据集的入口路径、类别名都必须在里面写清楚。# vehicle_det.yaml path: ./vehicle_det train: images/train val: images/val names: 0: car 1: truck 2: bus 3: motorcycle 4: bicycle 5: van 6: trailernames 的顺序必须与 4.1 里 cat_map 的枚举顺序一致。这里如果写错比如把 bus 写在 3 的位置模型会把摩托车当 bus 训练验证时 mAP 虽然能出来但类别全错。我用过一个数据集原始 json 里 car 的 id 是 3重映射后是 0yaml 里 0 对应 car这才对得上。训练命令用下面的形式起步yolo detect train datavehicle_det.yaml \ modelyolov8n.pt \ imgsz1280 \ batch16 \ epochs100 \ patience15 \ cacheTrue参数建议值理由imgsz1280车辆检测依赖远处小目标640 下远处轿车只有几十像素batch16显存允许时尽量大batch 太小 mAP 抖动明显patience15早停避免平台期空耗时间cacheTrue数据量不大时直接缓存到显存/内存省掉每轮读取磁盘为什么不直接用 640因为车是“分布稀疏但关键”的目标远处一辆摩托车在 640 分辨率下可能只有 20x20 像素卷积下采样之后特征几乎丢失。如果你显存不够跑 1280先降到 960再不行才用 640。imgsz 影响的是模型输入分辨率而不是标注的坐标所以改这个参数不需要重新转换数据它只是改变训练时图像的缩放尺寸。另一个经验是先用 yolov8n 做 smoke test跑 5-10 个 epoch确认 loss 在降、val 能出框再换 yolov8s 或 m。一上来就用 yolov8l 死磕如果数据有问题浪费的时间是按小时算的。n 模型训练速度快10 分钟就能把数据质量问题暴露出来比如文件读不到、类别错位、框异常这些问题在大模型上只会放大。5. 车辆检测数据集的 5 个常见坑现象、原因与解决即使前面的体检都做了训练过程中还是会遇到一堆幺蛾子。下面这几个坑是我在类似数据集上反复遇到的问题现象基本能复现原因也相对一致。每一条按“现象 → 原因 → 解决”展开对照排查比重新搜报错信息有效率得多。5.1 FileNotFoundError解压后图片名与标签名对不上现象训练脚本刚跑第一个 epoch报 FileNotFoundError提示 images/train/xxx.jpg 不存在但你自己点开那个路径文件明明在。原因macOS 打包的 zip 解压后会生成 _MACOSX 目录和 .开头的隐藏文件训练脚本的 glob 或者 ultralytics 的 dataset 加载器在遍历时把 ._xxx.jpg 这类垃圾文件当成图片路径读取时自然找不到。另一个常见情况是图片文件名含有中文或空格Windows 解压时正常Linux 下解压后文件名编码变了。解决解压后先清理垃圾文件再做一个统一的 rename把图片和标签按纯数字重命名。# 清理 macOS 打包残留 find raw/ -type d -name __MACOSX -exec rm -rf {} find raw/ -type f -name ._* -delete # 把 jpg 统一重命名为 6 位数字避免中文/空格文件名干扰 ls images/train/*.jpg | awk {print mv $0 images/train/train_NR.jpg} | bash这种与训练无关的文件系统问题最消耗耐心。我一般会在解压后第一时间跑这两条清理命令而不是等训练脚本报错再去查。重命名之后记得同步 4.1 里 txt 的文件名最好在做格式转换之前就完成重命名这样 txt 输出时自然用新文件名。5.2 loss 中途变 NaN越界框在 CIoU 里引爆 log现象前 2 个 epoch 一切正常loss 从 8 慢慢降到 5第三个 epoch 突然打印出 nan或者 loss 值出现负数后跳变到 inf。原因某些 GT 框在归一化后宽或高为 0或中心点在图像外YOLOv8 的 box loss 用 CIoUCIoU 的宽高比计算里有 log 操作输入为 0 或负数时梯度直接爆炸。这个问题在 fp16 混合精度下尤其明显边界值在浮点转换中更容易溢出。解决在 4.1 的转换脚本里严格做 MIN_WH 过滤和 [0,1] 裁剪训练时如果开了 AMP可以尝试关闭或换用 bf16 再观察。# 快速在训练脚本里加一个保护定位到具体是哪个 batch 出现异常 loss.backward() assert torch.isfinite(loss), floss 异常: {loss}, batch_idx: {batch_idx}添加断言不是长期方案但它能告诉你问题出在训练集的哪一段。如果你发现是某张特定图片导致的把那张图单独拿出来画框检查大概率能看到一个标注框宽高为 0 的异常样例手动修正它比改模型结构划算得多。5.3 验证表里某类 AP 是 0.00类别样本太少现象训练 100 个 epoch 之后val 结果表里 car 和 truck 的 AP 都很正常bus 那一行是 0.00或者根本没有那一行。原因看 2.2 的统计输出bus 整个训练集只有 80 个框、分布在 5 张图里。模型在训练时几乎没见过 bus 的正样本验证时自然检不出。更隐蔽的是如果某个类完全没有出现在验证集中ultralytics 的输出表格里会直接缺失这一行不仔细看还以为只是显示问题。解决在 2.2 统计时就要关注 inst 数低于 200 的类别。样本少的类别有两个处理方向一是合并边界模糊的类比如 bus 和 van 在侧视角下外形接近合并成一个 truck 类可以显著提升稳定性二是对该类做过采样把包含该类的图片在训练时重复几遍或者用 copy-paste 增强把该类的实例粘贴到其他图上。这种问题是数据集本身的资产问题不是靠调参能解决的。如果这个类别在实际应用里很重要比如公交车是自动驾驶必须识别的目标那就老老实实补数据或者从 BDD100K 这类更大的数据集里抽取对应类别的子集补充进来。5.4 两轮车 AP 惨不忍睹小目标与类别不均衡叠加现象car 的 AP50 能到 0.90motorcycle 只有 0.35bicycle 更低到 0.20。原因两轮车在车辆检测数据集里天然少、天然小摩托车在 1280 分辨率下可能只有 30x50 像素卷积多次下采样后特征已经严重退化。同时两轮车的形状差异大骑手姿势变化多比四轮车更难学。解决先把输入分辨率拉到 1280这是代价最小的提升手段然后开启 mosaic 增强让模型在拼接图里接触更多小目标如果还不够从训练集里把所有含两轮车的图片抽出来用 copy-paste 增强生成一批合成样本。注意不要为了提升 mAP 而过滤小目标。在自动驾驶场景里远处一辆摩托车可能就占几十像素但恰恰是需要检出的关键目标。MIN_AREA 过滤只在数据标注质量极差时才用正常情况下一刀切过滤小框会牺牲掉两轮车这种本就不多的类别。5.5 白天训得好夜间翻车场景分布就是数据分布现象在默认验证集上 mAP 0.74效果不错但拿到夜间行车记录仪或者雨天路测视频上一测框开始乱跳、漏检甚至出现连续误检。原因数据分布缺失这个压缩包只覆盖了白天晴天场景夜间和雨天的图像在特征空间里与训练数据差距太大模型没有见过就不会认。这和模型能力无关是数据问题。解决先看解压目录里有没有按场景分的子目录比如 day/、night/、rain/。有些数据包会按采集条件分区。如果没有可以考虑两条路一是自己在真实场景下补拍一段夜间/雨天素材做标注这是最靠谱的二是先用图像增强模拟低光照但增强只能缓解不能替代真实夜间的传感器噪声和曝光差异。不要指望一个模型能无中生有地学会全天候场景。拿到数据集时先看它的场景覆盖再决定是否需要做增量训练。6. 验证技巧按类别看 AP 而不是只看 mAP训练结束后直接跑一次验证把每个类别的 AP 单独拉出来看这一步能暴露 mAP 掩盖的类别问题。from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model.val(datavehicle_det.yaml, splitval) print(类别索引:, results.ap_class_index) print(每类 mAP50-95:, results.maps)results.maps 是一个数组顺序对应 data.yaml 里 names 的顺序。我拿到这个数组后会先看最小值在哪个类别上然后做一次混淆矩阵分析把 bus 和 truck 互相误判的样本单独导出来看一眼。你会发现真正的问题往往不是模型能力不足而是数据标注时对类别边界的定义模糊。自驾场景里侧前方一辆清扫车的轮廓和 bus 非常像如果标注人员在这两类上标准不一致训练完就会输出高置信度的错误类别。验证时还有一个技巧把 val 中两轮车这一类的失败样本全部抽出来按“完全没框”和“框到行人”两类错误分组。前者说明小目标特征丢失需要更高分辨率或更强的增强后者说明类别混淆需要检查标注规范。这两种错误的修法完全不同不分开分析就只能在调参上原地打转。我之前拿到过一个多类车辆检测包解压后直接训mAP 0.72 看着不错就推进到了现场 demo。结果一辆清扫车从侧后方靠近时模型把它识别成 bus触发了一次误制动。查下来是标注阶段对 bus 和 truck 的边界定义模糊侧视角下两者外形几乎一样模型学到的边界就是混乱的。从那以后我拿到任何车辆检测数据集第一件事都是画框体检、打印类别混淆矩阵再决定训练策略。数据集的标注边界归模型管但类别定义这份账得由人来算清。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑