简介面向目标检测算法训练与验证的车辆识别数据集适用于 YOLOv5、YOLOv3、SSD 等主流检测框架基于真实道路环境采集包含白天、夜间及俯视视角等多样场景。数据的光照与角度变化明显能有效检验模型在复杂环境下的泛化能力适合算法学习者、工程师及竞赛团队直接用于训练与评估。包内共 7210 个文件含 2403 张 JPG 图片并配备 2404 个 txt 标签与 2403 个 xml 标签txt 格式可直接供 YOLO 系列加载xml 格式便于转换为 VOC 或对接其他检测模型每个标注文件与对应图片一一配套压缩包整体约 803.77MB。目前已有 1817 人浏览学习。所有图片统一标注为 car无需额外清洗类别省去了自行采集、标注和格式转换的步骤下载解压即可投入实验数据规模与场景分布也能支撑模型效果对比、调参实践和论文复现是快速上手车辆检测任务的一份实用资源。1. 从数据压缩包到落地模型YOLOv5车辆检测的开局方式拿到car_dataset-1.rar时以为数据集到手就万事大吉这是YOLOv5车辆检测项目最常见的第一道坎。压缩包里是成百上千张道路图片和对应标注但YOLOv5不会自动理解这些文件你必须在解压后把目录结构、标注格式、类别映射和训练参数全部对齐才可能跑通一次像样的训练。如果忽略这些前置工作train.py往往能运行但损失不降、mAP为0、预测框全乱最后都指向同一个根因数据没准备对。这篇内容按我处理这类数据集的实际顺序展开从解压、格式核对、数据划分、训练配置讲到边缘端车位管理场景下的部署验证新手能跟着把yolov5训练自己的数据集跑通熟手也能从里面的参数和检查项里对应自己的实操盲区。下面不聊理论直接进入操作。2. 读取car_dataset-1.rar目录结构与标注格式核对2.1 解压后先看四样东西解压这类.rar文件名里带数字编号常见习惯是先建独立目录再把压缩包放进去避免一次性解出几十个文件把当前目录搅乱。mkdir -p car_dataset mv car_dataset-1.rar car_dataset/ cd car_dataset unrar x car_dataset-1.rarunrar没装就先装unrar系统没有unrar命令时可以用7z x car_dataset-1.rar替代。解压完成后用tree -L 2或find . -maxdepth 2 -type d列出目录。许多发布的数据集里图片和标签不放在同一个平级目录而是图片在images/、标注在labels/甚至混在一起。此时最该确认的不是文件多不多而是图片文件和标签文件数量是否对得上。find . -type f \( -name *.jpg -o -name *.png -o -name *.jpeg \) | wc -l find . -type f -name *.txt | wc -l两条命令分别统计图片和标签数量。如果标签数量明显少于图片说明部分图片没有标注训练时它们会被YOLOv5自动跳过实际参与训练的样本就会比预想中少。如果标签是.xml格式第二条命令要改成find . -type f -name *.xml | wc -l。数量一致后再打开任意一个标签文件看前几行进入下一步格式识别。2.2 识别YOLO还是VOC格式决定了预处理起点打开一个标注文件如果每一行是五个数字形如0 0.42 0.53 0.15 0.31这是YOLO格式已经可以直接训练。如果看到的是结构化XML文件名以.xml结尾那是VOC格式需要转换成YOLO。写个小脚本自动识别import glob sample_txt glob.glob(**/*.txt, recursiveTrue) xml_files glob.glob(**/*.xml, recursiveTrue) if sample_txt: with open(sample_txt[0]) as fp: line fp.readline().strip() print(label:, line) if len(line.split()) 5: print(大概率YOLO格式) else: print(发现XML数量:, len(xml_files))这段脚本的作用是抓第一个.txt标签看结构。YOLO格式每行五列依次是类别id、归一化中心点x、中心点y、框宽w、框高h目标数值都落在0到1之间。VOC则是一条矩形框的绝对像素坐标需要手工转换。还要确认有没有classes.txt或obj.names里面写了类别名。车辆检测数据集常见的是单类别car也可能包含truck、bus、motor、person类别顺序决定了给模型用的数字编号混用会直接造成训练出来的模型全乱套。为了直观对照列出两种格式的换算关系项YOLO标注VOC标注坐标位置归一化中心x, y左上角x1, y1第二对坐标归一化框宽高右下角x2, y2类别表达数字索引名称字符串必须的附加文件classes.txt--转换时事先确定类别表例如names [car, truck, bus]并固定下来后续训练和推理都用同一份。最稳妥的方式是写进YAML后面训练章节会用到。2.3 写脚本把VOC转成YOLO并整理目录import os import xml.etree.ElementTree as ET names [car, truck, bus] xml_dir VOC/Annotations img_dir VOC/JPEGImages out_txt_dir VOC/labels os.makedirs(out_txt_dir, exist_okTrue) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(.xml): continue root ET.parse(os.path.join(xml_dir, xml_file)).getroot() img_w int(root.findtext(size/width)) img_h int(root.findtext(size/height)) rows [] for obj in root.iter(object): cls_name obj.findtext(name) if cls_name not in names: continue bbox obj.find(bndbox) x1 float(bbox.findtext(xmin)) y1 float(bbox.findtext(ymin)) x2 float(bbox.findtext(xmax)) y2 float(bbox.findtext(ymax)) cx ((x1 x2) / 2) / img_w cy ((y1 y2) / 2) / img_h bw (x2 - x1) / img_w bh (y2 - y1) / img_h cls_id names.index(cls_name) rows.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) with open(os.path.join(out_txt_dir, os.path.splitext(xml_file)[0] .txt), w) as fp: fp.write(\n.join(rows))脚本按VOC的bndbox取绝对像素坐标先换算成归一化值再写文件。names.index(cls_name)把类别名称映射为编号这就是前面说类别顺序必须固定的原因。注意不是所有出现在标注里的类别都能被转换if cls_name not in names: continue会把名单外的类别直接丢掉。如果数据集里出现bus但你的类别表里没写bus实例会被静默忽略训练类别数就会和真实数据对不上。所以转换前最好统计全部XML里出现过的name和类别表对照一遍。接下来把图片和标签按YOLOv5习惯的目录结构摆好car_dataset/ images/ train/ val/ labels/ train/ val/在Linux下再用一段Shell把数据按9:1划入train和val。mkdir -p car_dataset/{images/{train,val},labels/{train,val}} shuf -esz --random-source(yes 42) images/*.jpg | head -n 10 | xargs -I{} mv {} train/ for f in images/train/*.jpg; do b$(basename $f .jpg); mv VOC/labels/$b.txt labels/train/; done这个划分方式简单但有个问题它只按照片名乱序划分不保证同一个场景的多帧不会同时进入train和val。对车辆检测任务而言同一个路口连拍画面高度相似混入两个集合会让验证结果虚高。更严谨的做法是按拍摄地点或时间段分组后再划分比如用目录名做分组键。这里不展开但至少不要把全量数据直接训到最终评估集上。2.4 训练前用一条命令检查类别分布cut -d -f1 car_dataset/labels/train/*.txt | sort | uniq -c | sort -nr该命令统计每个类别出现的框数量。如果数字差异极大比如car有3万框而truck只有200框训练时YOLOv5的数据增强会生硬地采样小类别的mAP通常很难看。车辆检测场景里最常见的是白天样本多、夜间样本少只看框数量还不够还应该统计每张图里的标注框数量检查有没有大量图片只有一两个框。这些检查很繁琐但比训练到一半再回头改数据省时间。格式确认、类别对齐、目录整理全部通过后才能进入训练配置这一关。3. yolov5训练自己的数据集数据yaml、超参数与训练命令3.1 数据集YAML的第一优先级YOLOv5项目目录下新建data/car_dataset.yaml。文件名随意关键是里面的train、val、nc、names四个字段别写错。train: ../car_dataset/images/train val: ../car_dataset/images/val nc: 1 names: 0: car路径是相对于运行train.py的YOLOv5根目录。如果根目录是/home/user/yolov5数据集放在/home/user/car_dataset那么写法就是../car_dataset/images/train注意不要多写一个datasets/。nc是类别数量单类别写1与标签文件里最大编号加1要一致。names里顺序和2.3节转换时用的类别表保持一致否则训练时loss正常但推理出来的框全对应到错误类别上。YAML里缩进不能用Tab这是YAML解析中最常见的报错。3.2 预训练权重怎么选yolov5s、yolov5m还是yolov5l在自定义车辆数据集上训练不推荐从随机初始化开始。COCO预训练权重里包含car类别网络已经学会基本纹理和边缘特征直接拿来做迁移学习能显著加速收敛。YOLOv5的s/m/l系列不是训练技巧而是同一套yolov5网络结构通过depth_multiple和width_multiple系数缩放出来的变体。选择哪一档主要看部署目标。模型参数量级适合场景yolov5s7M左右常规边缘设备、实时视频流yolov5m21M左右精度优先、GPU显存充足yolov5l46M左右离线分析或专用推理卡如果训练机器只有4G显存yolov5l按batch 16很容易OOM就用yolov5s起步。如果项目最终要上Jetson、RK3588这类带NPU的边缘设备一般也选yolov5s再量化。而对边缘端这种场景yolov5s是稳妥起点准确率不够再换yolov5m不要一开始就把模型选到最大。3.3 训练命令与必调超参数进入YOLOv5目录执行python train.py --data data/car_dataset.yaml --weights yolov5s.pt --img 640 \ --batch 16 --epochs 100 --device 0 --cache ram \ --hyp hyp.scratch-low.yaml--data指向刚才写的YAML--weights给出预训练权重路径首次运行会自动下载--img是训练输入尺寸640是YOLOv5的标准值内部会做letterbox缩放--batch受显存限制批量过大出现CUDA out of memory时先调到8或4--epochs对几千张以内的车流照片100轮足够收敛--cache ram能把图片加载进内存数据集不大时可以明显缩短训练时间--hyp指定超参数文件。超参数文件中lr0控制初始学习率。默认的hyp.scratch-low.yaml适合普通小数据集如果发现训练前期loss一直不降先把lr0从0.01调到0.005。mosaic、mixup这类数据增强对车辆目标有效但对夜间小目标过于激进时可以关掉mosaic或调低hsv_h减少合成样本和真实分布的偏差。每个参数都直接影响最终mAP但最需要优先调整的还是img、batch、lr0三件套其他增强选项先保持默认跑通一轮再看训练日志。训练日志中box_loss、cls_loss、dfl_loss对单类车辆检测通常cls_loss很低因为它只需要区分背景和前景如果cls_loss很高多半是data YAML里的nc和标签实际类别数不一致。box_loss占主要部分下降慢是正常现象看整体趋势即可。训练结束后的结果在runs/train/exp/目录中里面有results.png、weights/best.pt和weights/last.pt评估时用best.pt而不是last.pt。3.4 训练日志异常排查如果跑完一轮results.png里loss完全水平多数不是超参数问题而是标签没被模型读到。这时要确认YAML里train路径下的图片确实有对应标签并且标签文件里的类别编号小于nc。可以临时用只有一个类别的10张图片按--epochs 3跑一下如果loss出现下降说明数据集路径和格式没问题。另一个隐蔽点是YOLOv5对标签文件有严格格式校验标签文件为空文件时训练时会把该样本当作背景车全漏检。用find labels/train -size 0 -name *.txt可以找到空标签并剔除对应图片。4. 评估与推理用val和detect验证车辆检测模型4.1 用val.py拿到mAP和混淆矩阵训练完先不要急着detect用验证集评估一下泛化能力。执行python val.py --data data/car_dataset.yaml --weights runs/train/exp/weights/best.pt --img 640 --batch 16输出里有两个指标最值得关注mAP50表示IOU阈值为0.5时的平均精度mAP50-95是在0.5到0.95之间取不同阈值算平均更严格也更能区分模型好坏。对车辆检测mAP50能达到0.9以上是常见的优秀水平。val.py还会生成PR_curve.png和R_curve.png可以观察召回率上升时误检的变化。如果验证集来自car_dataset中与训练集同场景的连拍参考意义会打折扣需要在下一小节换一组外部图片做交叉验证。4.2 调整置信度阈值和NMS参数用训练好的权重跑图片或视频python detect.py --weights runs/train/exp/weights/best.pt --source car.mp4 --img 640 \ --conf 0.4 --iou 0.5 --save-txt --save-conf--conf是置信度阈值小于该值的框会被丢弃--iou是NMS的IOU阈值阈值越高则越容忍重叠框。在交通卡口场景远处车辆小且模糊把--conf降到0.25可以提高召回率但也会带来更多误检如果是识别车位是否被占目标通常很大且清晰干脆把--conf调到0.6以上误检率能压得比较低。--save-txt --save-conf会把每个框的类别、坐标和置信度存到runs/detect/exp/labels/下便于后续脚本统计。--source除了支持图片视频还可以传摄像头编号如0方便现场快速验证。4.3 外部验证从car_dataset里分一份盲测集数据划分混乱是所有公开数据集最容易踩的坑。我常用一种简单但有效的方法把训练期间完全没见过的图片放进images/blind/目录额外写一个对应YAML保持nc和names与训练集完全一致。用detect.py跑一遍blind目录肉眼检查输出框是否对齐车体、有没有把路牌或阴影当车。这种方法无法算mAP但能快速暴露过拟合到特定场景的问题。如果模型只对训练集中出现的颜色敏感先不要急着加数据先检查数据集本身是不是现场拍摄重复度过高。5. 从car_dataset到车位管理交付前必做的稳定性验证5.1 导出ONNX并在目标设备上跑一遍边缘端yolov5车辆检测模型最常用的交付形式是ONNX。在YOLOv5目录执行python export.py --weights runs/train/exp/weights/best.pt --include onnx --opset 12ONNX导出后用之前跑过的同一个视频再做一次推理对比原PyTorch权重和ONNX Runtime版本输出框的差异。导入ONNX时模型只输出原始anchor预测NMS后处理需要自己接在后端。如果目标是带NPU的板子转成TensorRT或RKNN时导出分辨率要固定动态输入会增加推理侧复杂度。5.2 用迟滞判定消除车位状态抖动即使模型mAP很高视频流里检测框依然可能短暂丢失原因是车辆反光、行人遮挡或帧间闪烁。如果车位管理系统直接根据当前帧有没有检测到车来切换占用状态同一辆车泊车的过程可能被误判成“进去又出来”。常见做法是增加一个状态滤波器连续N帧都认为车位被占才切换状态。class StallDetector: def __init__(self, stable_frames5): self.occupied False self.counter 0 self.stable stable_frames def update(self, detect_results): current bool(detect_results) # 检测框集合非空视为占用 if current self.occupied: self.counter 0 else: self.counter 1 if self.counter self.stable: self.occupied current self.counter 0 return self.occupiedstable_frames通常按帧率设定视频流25帧每秒时取5到10帧即0.2到0.4秒内稳定才翻转状态既不会卡顿也不会闪烁。这个滤波器直接消费detect.py输出也可以把检测结果通过串口发给STM32让MCU只处理最终占用状态。这也是基于stm32的边缘端yolov5车辆检测与车位管理系统最常见的架构边缘设备跑检测STM32只接收最终结果并控制LED或屏显。5.3 用拥堵视频做回归测试最后一步不针对训练集而是录一段至少10分钟的车流拥堵视频包含多车并行、车辆阴影、行人穿插三种情况。跑一遍detect.py统计输出置信度分布如果大量框的置信度落在0.3到0.5之间说明输入分辨率太低或夜间增强不够如果某一段视频里连续几十帧漏检则多半是模型在小目标上召回不足此时应把--img从640提高到1280验证并配合5.2的状态机补帧。将这些调整落成固定参数后就可以将best.pt和对应的后处理参数一并提交完成一次从car_dataset到可用系统的闭环。本文还有配套的精品资源点击获取