尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

YOLO车辆检测数据集全流程指南:从解压、校验到训练部署

YOLO车辆检测数据集全流程指南:从解压、校验到训练部署 简介这套YOLO车辆检测数据集包含1254张已标注图像及对应的txt标签文件车辆类别覆盖Ambulance、Bus、Car、Motorcycle、Truck五类可满足救护车、公交车、小汽车、摩托车、卡车等常见车辆的检测需求直接用于YOLO系列模型训练与验证。资源面向计算机、电子信息工程、数学等专业学生适用于课程设计、期末大作业和毕业设计等场景也可作为目标检测入门练习或算法效果对比的基准数据。压缩包共2513个文件除jpg原始图片和txt标注文件外还提供1个yaml配置文件其中定义了类别名称与ID对应关系另有2个cache缓存文件可加速数据加载整体大小38.48MB文件组织结构简洁便于快速开展训练实验。目前已有9180人学习/下载使用者可省去自行采集图像和手工标注的繁琐过程将更多时间投入模型调参与性能优化是一份低门槛、可直接上手的车辆检测数据集。1. 先搞清楚你拿到的到底是什么YOLO车辆检测数据集的构成与适用范围一个 .rar 压缩包写着“1254张图像对应已标注文件”下载后最忌讳的就是解压后直接往训练脚本里塞。YOLO 目标检测流程中数据链路的格式要求很具体图像、标签、类别文件、数据集配置文件四样东西各就各位才能开训少一个目录层级都会在训练时报错。这个标题里的数据集属于“中等规模、单一任务、已标注”的典型资源1254 张对车辆检测来说不算大但足够把 YOLOv5/YOLOv8 的完整流程跑通也适合做迁移学习的起点。适合谁刚入门目标检测的学生、需要快速出基线的工程师、以及想在边缘端设备比如基于 STM32 的车辆检测与车位管理系统上部署轻量模型的开发者。用它之前先回答三个问题标注是 YOLO txt 还是 VOC XML类别只有 car 还是包含 truck/bus图像和标注文件能否一一对应下面按“看得懂、验得了、训得起来、用得上”的顺序把这条链路完整走一遍。2. 从 .rar 到可用数据集解压、文件结构体检与 YOLO 标注格式核对2.1 先做解压与文件树体检不要直接开训拿到 .rar 先不要双击解压到桌面就完事。服务器上的常见做法是装 unrar 或 unar 来解压既能处理中文文件名也能保留目录嵌套Windows 上用 WinRAR 解开通常没问题但解包后第一件事不是翻图片而是看目录结构。sudo apt install unrar # Debian/Ubuntu 安装解压工具 unrar x 车辆检测数据集.rar ./vehicle_dataset/ cd vehicle_dataset find . -maxdepth 2 -type d | sortunrar x会保留压缩包里的目录结构不会把所有文件摊平到当前目录。后面的find只列出两层目录输出不至于被几百个文件刷屏。一个标准的 YOLO 车辆检测数据集解压后通常会看到images/和labels/两个平级目录图像与标注文件同名不同扩展名。如果解出来是一堆 jpg 和 txt 混在一起或者目录多套了一层就需要先把结构整理成 YOLO 默认认识的形态。接下来统计图像数量和标签数量这是体检的第一步find images -type f \( -name *.jpg -o -name *.jpeg -o -name *.png \) | wc -l find labels -type f -name *.txt | wc -l如果图像数和 txt 数不一致不要慌。有些数据集会额外放 README.txt、classes.txt这些文件也会被统计进来所以更可靠的对齐方式是检查同名关系。下面的脚本遍历所有图像到labels/里找同名 txt找不到就输出缺失信息for img in $(find images -type f); do base$(basename $img | sed s/\.[^.]*$//) if [ ! -f labels/$base.txt ]; then echo missing label: $base fi done脚本先把图像文件名去掉扩展名得到和标签共用的 base 名再判断对应 txt 是否存在。如果这种 missing 输出超过几十条说明这个数据集的标注并不完整不能直接拿来训练。如果解压出来的图像和标签混在同一目录最好先整理成images/与labels/。以 .txt 是 YOLO 标签为前提把非 README 的 txt 移动到 labels 目录mkdir -p images labels for f in *.jpg *.png; do [ -f $f ] mv $f images/; done for f in *.txt; do case $f in README*) continue;; esac [ -f $f ] mv $f labels/ done这里用case跳过 README避免把说明文件混进标签目录。移动完再跑一遍前面的同名校验基本就能确认目录结构没有大问题。2.2 校验标注文件是否真的是 YOLO 格式目录结构只是外壳标注内容才是核心。YOLO 标签每行五个数字class x_center y_center width height后四个值是归一化坐标范围 0~1。随机看一个 labels 下的 txtcat labels/000125.txt如果输出是0 0.521875 0.463333 0.183333 0.206667那就是 YOLO 格式如果出现car 100 200 300 400或者0.5,0.5,0.2,0.3就要警惕了。前者是 KITTI 风格的文本标注后者是 CSV都不能直接给 YOLO 训。很多标注好的车辆数据集其实是从 KITTI 转出来的标题说“已标注可以直接使用”但转换是否做对要自己验证。KITTI 原始 txt 中类别之后是一串数字bbox 是像素坐标。KITTI 标注转 YOLO 的公式固定如下def kitti_to_yolo(cls, xmin, ymin, xmax, ymax, img_w, img_h): x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h width (xmax - xmin) / img_w height (ymax - ymin) / img_h return f{cls} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}函数里的除法是必须的YOLO 训练时会在letterbox之后按归一化坐标缩放如果给的是像素值框的位置会完全错掉。KITTI 原图尺寸是 1242x375很多网上的数据集被 resize 后没有同步更新标注那就算公式正确也白搭。所以每次拿到数据集都要用真实图像尺寸重算一遍不能直接信任压缩包里的标注。快速校验整个 labels 目录可以用这段 Pythonimport os label_dir labels bad_count 0 valid_count 0 for f in os.listdir(label_dir): if not f.endswith(.txt): continue for line in open(os.path.join(label_dir, f)): parts line.strip().split() if len(parts) ! 5: print(field error, f, line) bad_count 1 continue try: vals [float(v) for v in parts[1:]] if not all(0.0 v 1.0 for v in vals): print(range error, f, line) bad_count 1 except ValueError: print(not float, f, line) bad_count 1 valid_count 1 print(valid lines:, valid_count, bad lines:, bad_count)这段代码检查三件事列数是否为 5、后四列能否转成 float、数值是否在 0~1。只要坏行占比超过 1%就应该怀疑“已标注”这个描述先修复再训练。2.3 这份数据集里最常见的三种坑第一种是类别文件缺失或类别 ID 对不上。压缩包里只有 images 和 labels没有 classes.txt那 0 号类别是 car 还是 truck 就只能靠猜。如果标签里出现 ID 2但你的类别文件只有 0 和 1训练时会直接报class 2 out of range。第二种是文件名大小写不一致。Windows 解压不区分大小写Linux 下img_001.JPG和labels/img_001.txt对不上前面那个同名校验脚本就会输出一堆 missing。第三类是图像损坏或混入非车辆图片。一张全黑的 jpg 也能被 OpenCV 读出来但训练时会给模型注入完全无意义的梯度。遇到这三种情况处理优先级是先补类别文件再统一文件名最后清洗坏图像。顺序反过来会浪费时间复检。3. 把标注画回图像可视化校验与常见标注错误排查3.1 用 OpenCV 把 YOLO 标签还原到图上格式检查通过不等于标注可用。五个数字都合法框也可能画在树上、车道上甚至图像外沿。数据校验最直接的方式是把每个标签框还原到原图上人工抽样看 20~50 张。写一个可复用的可视化函数import cv2 def draw_yolo_label(img_path, label_path, out_path, class_namesNone): img cv2.imread(img_path) if img is None: print(cannot read:, img_path) return h, w img.shape[:2] with open(label_path) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue cls, xc, yc, bw, bh map(float, parts) x1 int((xc - bw / 2) * w) y1 int((yc - bh / 2) * h) x2 int((xc bw / 2) * w) y2 int((yc bh / 2) * h) color (0, 255, 0) if int(cls) 0 else (0, 0, 255) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) label class_names[int(cls)] if class_names else str(int(cls)) cv2.putText(img, label, (x1, max(0, y1 - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2) cv2.imwrite(out_path, img) draw_yolo_label(images/000125.jpg, labels/000125.txt, check.jpg)这段代码把归一化中心点换算成左上角和右下角x1 (xc - bw/2) * w是最容易写错的一行少一个括号框就会偏移一倍。绘制文字时max(0, y1 - 5)防止目标靠近图像顶部时文字跑出画面。类别名用数组传入建议和后续 data.yaml 里的 names 保持一致这样可视化出来的名字和训练时的类别一一对应。对 1254 张图的车辆数据集人工逐张看没必要但一定要看边界情况。我会优先挑这几类图视角从车尾拍的大巴车、多辆小车挤在一帧的拥堵路况、远处只有几十像素的摩托车。这些图最能暴露标注质量比随机翻图高效得多。3.2 越界、空标签、类别漂移的批量排查可视化能发现问题但难以发现全部问题。程序化检查应该覆盖这张表检查项判定条件常见原因越界x1 0 或 x2 w 或 y1 0 或 y2 hresize 后没同步缩放标注空标签txt 文件没有任何有效行漏标、转换脚本 bug宽高异常box 宽或高小于图像尺寸的 1%误点产生的短线目标类别漂移类别 ID 超出 classes.txt 范围多源数据合并时未重映射 ID越界问题要分情况处理。框出界 1~2 个像素可能是标注时的贴边操作无伤大雅如果出界超过图像宽高的 10%往往是图像被压缩过而标注没有跟着变。空标签在 YOLO 训练中不算致命模型会直接忽略这些图像但验证集里空标签太多会拉低召回率导致指标失真。类别漂移是最隐蔽的坑。有些车辆数据集来自多个公开源合并A 源里 0 是 carB 源里 0 是 pedestrian合并后没有重映射ID 语义就乱了。先统计所有标签里出现的类别 IDimport os from collections import Counter counter Counter() for f in sorted(os.listdir(labels)): if not f.endswith(.txt): continue for line in open(os.path.join(labels, f)): parts line.strip().split() if parts: counter[parts[0]] 1 print(counter.most_common())输出结果要和classes.txt比对。如果classes.txt里只有car和truck但统计结果出现2这个 ID说明有一个标签写了不存在的类别。更隐蔽的情况是 ID 都在范围内但语义反了这时只能靠 3.1 节的可视化来兜底。对车辆检测而言比较理想的类别统计是所有类别样本数都在三位数以上如果某个类别只有几十个样本模型对该类的 AP 会非常不稳定需要额外做样本复制或针对性增强。3.3 标注问题批量过滤与清洗如果可视化发现大量标注错误不要一张张手动改。先把不达标的标签挑出来放进黑名单import os def is_suspect(line, img_w, img_h): parts line.strip().split() if len(parts) ! 5: return True cls, xc, yc, bw, bh map(float, parts) x1 (xc - bw / 2) * img_w x2 (xc bw / 2) * img_w y1 (yc - bh / 2) * img_h y2 (yc bh / 2) * img_h return bw 0.01 or bh 0.01 or x2 0 or x1 img_w or y2 0 or y1 img_h blacklist [] for f in os.listdir(labels): if not f.endswith(.txt): continue path os.path.join(labels, f) lines open(path).readlines() bad [ln for ln in lines if is_suspect(ln, 1920, 1080)] if bad and len(bad) len(lines): blacklist.append(f)这里用了固定的 1920x1080 作为参考尺寸实际使用时要改为从对应图像读取宽高。黑名单里的标签文件对应整张图报废可以移到blacklist/目录而不是直接删除后续如果找到正确的标注还能恢复。清洗之后重新跑一遍第 2 节的同名校验和格式校验确认数据本身没有引入新的问题再进入训练阶段。4. 用自己的车辆数据集训练 YOLOv8数据集划分、配置文件与训练命令4.1 按 8:1:1 划分 train/val/test 并生成路径清单标注检查完下一步就是划分数据集。1254 张图像对车辆检测来说规模不大按 8:1:1 切分能得到约 1003 张训练图、126 张验证图、125 张测试图。划分前先建立目录结构mkdir -p images/{train,val,test} labels/{train,val,test}YOLO 默认在同名目录下寻找标注所以images/train/0001.jpg必须对应labels/train/0001.txt。用 Python 做一次随机划分并移动文件import os import random import shutil random.seed(42) imgs [f for f in os.listdir(images) if f.lower().endswith((.jpg, .jpeg, .png))] random.shuffle(imgs) n len(imgs) splits { train: imgs[: int(n * 0.8)], val: imgs[int(n * 0.8): int(n * 0.9)], test: imgs[int(n * 0.9):], } for split, names in splits.items(): for name in names: shutil.move(os.path.join(images, name), os.path.join(images, split, name)) label os.path.splitext(name)[0] .txt if os.path.exists(os.path.join(labels, label)): shutil.move(os.path.join(labels, label), os.path.join(labels, split, label))随机种子固定为 42保证别人拿到同一份数据、跑同一个脚本得到完全一致的划分结果。移动标签时使用了if os.path.exists这是为标签缺失的数据集准备的容错如果第 2 章的同名校验已经通过这里其实不会触发但保留判断可以让脚本更安全。注意所有移动操作都在同一个磁盘分区内进行不会复制图像省时间。划分完成后检查每个子目录下的类别分布。如果truck在 train 里有 50 个标注val 里只有 3 个那验证时 truck 的 mAP 就会忽高忽低。简单做法是打印每个分割集的类别频率如果偏差超过 30%就把随机种子换一个或者手动把一个 truck 较多的文件切到验证集。对车辆检测这种类别形态差异明显的任务类别均衡比总样本数更值得在意。4.2 写一个最少可用的 data.yamlYOLOv8 训练时需要一个描述数据集结构的 YAML 文件。train/val/test 路径可以写绝对路径或基于path的相对路径最稳妥的是显式写绝对路径避免从不同工作目录启动命令时路径失效。path: /home/user/vehicle_dataset train: images/train val: images/val test: images/test nc: 3 names: 0: car 1: truck 2: busnc必须与names列表长度一致这是训练启动前最容易报错的地方。如果数据集中只有 car 一类就把 nc 改成 1names 写成0: car。路径指向的目录需要同时包含images/train/和labels/train/YOLOv8 会按照 images 的路径自动推导 labels 路径推导规则是文件名不变、目录名从 images 换成 labels。如果压缩包里的标注目录叫annotations而不是labels建立软链接是最省力的修法ln -s /home/user/vehicle_dataset/annotations /home/user/vehicle_dataset/labels软链接在 Linux 下可以免去修改 YOLO 源码的麻烦Windows 下则建议直接把目录重命名。data.yaml 写好后可以用一个命令验证路径和标注数量是否匹配yolo checks datavehicle_dataset.yamlyolo checks会打印数据集的图像数、类别数和标注数。如果这里报告的类别数和你的classes.txt不一致说明第 2.3 节的类别漂移检查还没做干净先回去修数据。4.3 训练命令与 3 个最值得调的参数安装 ultralytics 之后训练命令可以这样写yolo train datavehicle_dataset.yaml modelyolov8s.pt epochs100 imgsz640 batch16 device0modelyolov8s.pt表示加载 COCO 预训练权重继续训练。1254 张图像不足以让模型从随机权重学出稳定的车辆特征迁移学习是必须的。imgsz640是训练输入尺寸车辆检测目标通常较大640 够用如果应用场景中有大量远处小目标可以提到 736 或 768但显存占用和训练时间会随之上升。batch16在 8G 显存下比较稳妥16G 显存可以开到 32。训练时最值得调的三个参数如下参数默认值建议值调参理由mosaic1.00.5 或 0.0车辆外形相对固定mosaic 过强会引入大量被截断的车身patience5020数据集小过拟合会早到早停能省一半时间close_mosaic105最后几个 epoch 关闭 mosaic让模型在正常构图下收敛mosaic是 YOLOv8 的默认数据增强把四张图随机裁剪拼成一张。对提高泛化能力有帮助但车辆检测任务里车辆形体比较规范mosaic 拼图容易把车从中间切断导致模型学到不完整的特征。先按mosaic0.5跑一版如果验证集 mAP 不理想再试 0.0 对比。patience表示连续多少个 epoch 验证损失不下降就提前终止1254 张图通常 40~60 个 epoch 就收敛50 的默认值偏保守。训练过程中主要盯两个损失曲线box_loss和cls_loss。YOLOv8 的损失函数由定位损失、分类损失和分布损失组成前两者是最直观的信号。正常情况下它们前 10 个 epoch 快速下降之后平缓波动。如果box_loss一直抖动下不去先回想第 2、3 章有没有漏掉标签问题不要浪费时间调学习率。5. 从 best.pt 到可用的车辆检测验证指标、导出模型与一段检测脚本5.1 训练完先看混淆矩阵和 PR 曲线再决定要不要调参训练结束后不要急着部署先用验证集做一次完整评估yolo val modelruns/detect/train/weights/best.pt datavehicle_dataset.yaml重点看三个数mAP50、mAP50-95和每类 AP。1254 张车辆数据训练的模型mAP50 在 0.75 以上属于正常如果只有 0.5先打开runs/detect/train/confusion_matrix.png。混淆矩阵里非对角线的亮块能告诉你模型到底是把 bus 看成 truck还是漏掉了整类车。PR 曲线用来选推理时的置信度阈值满足漏检率要求的最小的置信度就是部署时要用的conf。5.2 导出为 ONNX 或 TensorRT 的最小步骤PyTorch 权重不能直接跑在 C 部署环境或边缘设备上先导出成通用格式yolo export modelruns/detect/train/weights/best.pt formatonnx imgsz640导出后得到best.onnx。如果目标是 Jetson 或 TensorRT 推理框架可以继续yolo export modelbest.pt formatengine device0TensorRT 的导出会做层融合和量化第一次时间较长。要特别注意导出时的imgsz必须和训练时一致否则预处理尺寸不同检测框会出现整体偏移。5.3 把模型接进一小段车辆检测代码最后放一段最简可用推理代码统计一张图里的车辆数量from ultralytics import YOLO model YOLO(best.pt) results model.predict(traffic.jpg, conf0.25, iou0.45) vehicle_ids {0, 1, 2} vehicles 0 for r in results: for cls in r.boxes.cls.int().tolist(): if cls in vehicle_ids: vehicles 1 r.save(traffic_out.jpg) print(vehicle count:, vehicles)conf0.25控制检出框的置信度门槛iou0.45是 NMS 去重阈值。如果统计结果里误报多把 conf 提到 0.4如果漏检多降到 0.15。推理帧率要求高时先把图像按 640 尺寸 letterbox 再喂给 ONNX Runtime比直接用原始分辨率推理快很多。归档时用md5sum best.pt best.onnx记录哈希避免不同实验的权重混用。本文还有配套的精品资源点击获取
返回列表