简介:YOLO夜间车辆检测数据集专门面向目标检测学习者与算法工程师,提供真实夜间道路场景下的高质量车辆图像,解决夜间光照不足、标注格式不一等训练痛点。包内共2000个文件,包含1986个XML标签文件、3个Python划分脚本、5个训练列表及6个HTML教程文档,压缩包约209MB;标签涵盖VOC、COCO、YOLO三种格式,可直接接入主流YOLO系列模型训练,图像场景丰富、标注框质量高,可有效缓解夜间样本稀缺与泛化能力不足的问题。另附环境搭建与训练案例教程,覆盖Windows与Linux双平台,并配套训练集、验证集、测试集划分脚本,便于灵活自定义数据切分。已有448人学习下载,适合需要真实夜间数据提升模型鲁棒性的计算机视觉开发者。
1. 夜间车辆检测为什么比白天更难——数据集的出发点
夜间车辆检测在实际项目中远不是把白天模型直接迁移就能用的。路灯交替、车灯眩光、暗部噪点和运动模糊同时出现,目标边界与背景的对比度被大幅压缩,白天表现还不错的YOLO模型在夜间会漏掉大量距离远的车辆,而且车头灯造成的亮斑会被误判成目标。这个数据集包含5000张真实夜间场景的车辆图片,用labelimg逐框标注,同时保留VOC XML、COCO JSON和YOLO TXT三种标签格式,可以不经格式转换直接喂给YOLOv5、YOLOv8以及后续更新的YOLO系列。适合两类人:一是要快速构建夜间车辆检测原型,二是做自动驾驶感知或城市交通监控场景迁移。数据里还附带了环境搭建、训练教程和三个划分脚本,省掉了从零整理数据集的麻烦。
2. 三格式标签并存:VOC XML、COCO JSON 与 YOLO TXT 的字段映射
同一张图只标一次,却同时存在三种标签文件,关键要搞清它们表达的是同一个标注框的不同坐标编码。很多人在拿到这种数据集后直接挑一个文件夹里的标签丢给YOLO,结果发现类别对不上、坐标越界,其实问题都出在格式转换上。
2.1 三种格式的坐标编码差异
VOC XML使用像素绝对坐标,记录xmin、ymin、xmax、ymax四个整数值;COCO JSON的segmentation和bbox也都基于像素,但bbox记录的是左上角x、y和宽度w、高度h;YOLO TXT则是归一化后的中心点坐标,cx、cy、w、h都是0到1之间的小数。以一张1280×720的图片为例,一个左上角在(320,180)、宽640、高360的车辆框,在YOLO txt里会写成0 0.5 0.5 0.5 0.5,第一位是类别ID,后面四个数是除以图片宽高后的归一化结果。三种格式的定位逻辑可以用下面这个表格快速对照:
| 格式 | 文件后缀 | 坐标含义 | 坐标范围 | 类别记录方式 |
|---|---|---|---|---|
| VOC | .xml | 边框左上角xmin/ymin,右下角xmax/ymax | 像素绝对值 | 标签名如car、truck |
| COCO | .json | bbox为[x,y,w,h] | 像素绝对值 | 存在categories数组的id映射 |
| YOLO | .txt | 中心点坐标cx,cy,宽高w,h | 归一化到[0,1] | 类别对应的整数id |
训练YOLO系列时必须用txt,验证mAP时经常需要转回COCO JSON,而做标注审核时看VOC XML最直观。三个格式之间的转换不建议手写,最好用现成脚本统一转换,避免归一化时把边框算出图片边界。尤其要注意YOLO txt中的cx和cy是相对图片宽高的比例,如果训练时用了resize到640而标签依然按原图尺寸归一化,模型会学到错误的坐标分布。
2.2 用Python快速核对三份标签是否一致
实际处理数据集时,我一般会先写一段小脚本把三份标签都读出来,对比同一张图片的标注框数量和坐标值,确认数据集在制作时没有因为中途改格式丢掉标注。下面这段代码可以同时解析三种标签并打印面积和类别:
import json import xml.etree.ElementTree as ET # 解析 YOLO txt:每行是 类别ID cx cy w h,全部为归一化坐标 def load_yolo_txt(txt_path, img_w, img_h): boxes = [] with open(txt_path, 'r', encoding='utf-8') as f: for line in f: parts = line.strip().split() if len(parts) != 5: continue cls_id = int(parts[0]) cx, cy, w, h = map(float, parts[1:]) # 还原为像素坐标,便于和VOC、COCO比较 boxes.append([cls_id, cx * img_w, cy * img_h, w * img_w, h * img_h]) return boxes # 解析 VOC xml:根节点是 annotation,每个 object 里是 bndbox def load_voc_xml(xml_path): tree = ET.parse(xml_path) root = tree.getroot() boxes = [] for obj in root.findall('object'): name = obj.find('name').text bbox = obj.find('bndbox') xmin = int(bbox.find('xmin').text) ymin = int(bbox.find('ymin').text) xmax = int(bbox.find('xmax').text) ymax = int(bbox.find('ymax').text) boxes.append({'name': name, 'xmin': xmin, 'ymin': ymin, 'xmax': xmax, 'ymax': ymax}) return boxes这段代码里,YOLO txt解析时要传入图片宽高才能转回像素坐标;VOC XML解析返回的是每个object的name和bndbox。核对时只需要把同一张图片的三份输出打印出来,看类别和边框数量是否对得上。如果发现某个XML有对象但TXT缺行,说明转换脚本漏框,要和原标注核对。另一个常见问题是COCO JSON里有些标注的bbox是空数组,这种情况多半是标注时不小心画了零宽度的框,需要过滤掉。
COCO JSON的结构相对复杂,需要先建立images数组里图片ID到文件名的映射,再通过annotations里每个标注的image_id找到对应图片:
with open('annotations.json', 'r') as f: coco = json.load(f) img_id_to_name = {img['id']: img['file_name'] for img in coco['images']} for ann in coco['annotations']: if img_id_to_name[ann['image_id']] == target_name: # ann['bbox'] 是 [x, y, w, h],像素坐标 x, y, w, h = ann['bbox']COCO的bbox和VOC的xmin/ymin表达的是同一个左上角,但VOC的右下角要换算成x+w、y+h才能对比。标签目录里三种文件分别放在不同文件夹,文件名与图片名保持了一致,直接按名字拼接路径就能对应上。
2.3 类别定义与标签文件夹的组织方式
labelimg标注时自定义的类别名称会直接写进VOC XML的name节点,而YOLO TXT只存整数ID,同时需要一个classes.txt来确定ID与名称的对应关系。这个数据集的车辆检测场景通常只用vehicle这一类,也可以细分car、truck、bus等,具体看原始数据集的类别定义。拿到数据集后先打开标签文件夹里的classes.txt,或者查看任意一个XML里的name,确认类别顺序再训练。否则一旦类别ID与名称错位,训练的损失看起来正常,实际上模型把卡车和轿车全混成一类。
提示:如果训练时发现验证集mAP异常低,先检查classes.txt里的类别顺序是否和YOLO TXT里的ID对应,这是三格式数据集训练时最容易踩的坑。
3. 训练集/验证集/测试集划分脚本的运行方式与路径约定
数据集自带的三个划分脚本解决的是同一个问题:让图片和标签以相同比例进入不同子集,并生成供训练使用的文件列表。很多项目会忽略测试集的独立性,直接把全部数据用来训练,导致最后上报的精度虚高,这里给的三个脚本恰好能规避这个习惯。
3.1 三个脚本的差异与适用场景
第一个脚本「训练集、验证集、测试集划分脚本(图片标签划分写入新文件夹).py」会把图片和对应标签复制到train/val/test三个目录下,适合直接用于YOLO训练。第二个脚本只划分训练集和验证集,不含测试集,适合先不保留最终测试集、把全部数据投入交叉验证的场景。第三个脚本名字是split_train_val生成ImageSets下txt文件划分脚本.py,它不会复制文件,而是在ImageSets目录下生成train.txt、val.txt、test.txt,每个txt里写的是图片路径或图片名列表,VOC系列的训练代码可以用这种txt组织数据。第三类脚本本质上是为PASCAL VOC训练流程准备的,YOLO官方训练脚本不直接消费它,但你可以把它生成的txt作为train_list.txt的替代。
3.2 改路径参数而不是改代码逻辑
打开脚本后,顶部通常是几个路径常量和一个比例参数。常见做法是直接修改下面的变量再运行:
# 原始图片目录 image_source_dir = 'D:/data/night_vehicle/images' # 标注文件目录,这里存放的是YOLO格式的txt label_source_dir = 'D:/data/night_vehicle/labels' # 输出目录,脚本会在其中创建 train/val/test 子目录 output_root = 'D:/data/night_vehicle/split' # 划分比例,三者之和应为1 train_ratio = 0.7 val_ratio = 0.2 test_ratio = 0.1这段配置里,image_source_dir指向所有原图,label_source_dir指向YOLO TXT标签目录。脚本会遍历图片文件列表,用random.shuffle打乱顺序,再按比例切出三段,同时把图片和同名txt复制到output_root的对应子目录。为了防止图片和标签数量不匹配,脚本内部一般会检查同名文件是否存在,跳过那些没有标签的图片。实际做数据工程时,我会把 train_ratio 从0.7提高到0.8,测试集固定留0.1,验证集0.1,因为夜间车辆场景的负样本和遮挡情况需要在训练阶段给模型足够多帧数。如果训练集图片过少,也可以把测试集临时并回验证集,先跑通完整链路再补数据。
3.3 生成train_list.txt与手动划分的核心逻辑
train_list.txt是训练时用来枚举图片路径的列表文件。许多YOLO训练流程支持把数据参数指向一个txt,其中每行一个图片路径。数据集里提供的train_list.txt应该是从首次划分后导出的,但如果你自己改了划分比例,需要重新生成。可以用下面这段脚本从划分后的目录重建列表:
from pathlib import Path image_dir = Path('D:/data/night_vehicle/split/train/images') txt_path = Path('D:/data/night_vehicle/train_list.txt') # 获取所有jpg,按名排序保证可复现 imgs = sorted(image_dir.glob('*.jpg')) with txt_path.open('w', encoding='utf-8') as f: for img in imgs: # 写入绝对路径,训练时可以跨目录读取 f.write(str(img.resolve()) + '\n') print(f'写入 {len(imgs)} 张训练图片路径')这段脚本遍历split/train/images目录下所有jpg,把绝对路径写入train_list.txt。使用绝对路径可以避免训练时工作目录不一致导致找不到图片。如果你后续要移动整个数据集,推荐改成相对路径,配合训练脚本的root_dir一起使用。验证集列表和测试集列表可以用同样的方式生成,只需把image_dir换成对应目录。注意glob匹配的文件名后缀要和实际图片格式一致,如果图片是png却只匹配jpg,生成的列表会是空的。
三个脚本都没有采用命令行参数,而是直接改顶部配置,这是很多早期标注数据集的做法。运行前建议先复制一份原始数据,避免脚本里用了os.remove清空已有文件时误删原图。我遇到过脚本在Windows下把路径反斜杠处理错的情况,如果报找不到文件,把脚本里的路径统一改成Path对象或使用正斜杠字符串。
4. 从环境搭建到 YOLO 训练启动:Ubuntu/Windows 双路径
YOLO系列在Linux和Windows上的配置思路基本一致,区别主要在PyTorch的CUDA依赖安装方式。数据教程里带了Linux和Windows两套环境搭建说明,说明作者默认受众可能同时接触服务器和本地开发机。先解决环境问题,再谈训练,否则后面参数调了也跑不起来。
4.1 环境搭建:Anaconda + PyTorch + CUDA
在Ubuntu上,先安装显卡驱动和CUDA,再用conda创建独立环境,避免把系统Python搞乱。Windows上优先使用官方安装包安装CUDA和cuDNN,再通过pip安装PyTorch。以YOLOv5为例,Linux下的标准命令如下:
conda create -n yolo python=3.8 -y conda activate yolo # CUDA 11.8 对应的PyTorch安装命令 pip install torch==2.1.1 torchvision==0.16.1 --index-url https://download.pytorch.org/whl/cu118 pip install -r requirements.txt先创建Python 3.8环境,再安装与CUDA版本匹配的PyTorch,最后安装项目运行依赖。--index-url字段指定PyTorch的官方CUDA版本源,如果你使用AMD显卡,在Linux下可以尝试PyTorch的ROCm版,Windows下则通常只能CPU训练。环境搭建的教程里一般会包含nvidia-smi确认驱动版本,以及用下面命令验证CUDA是否对PyTorch可用:
python -c "import torch; print(torch.cuda.is_available())"这一步卡住的概率最高,大多数情况是CUDA版本与PyTorch不匹配。常见错误是torch.cuda.is_available()返回False,但nvidia-smi显示驱动正常,此时需要检查PyTorch的cu版本是否与驱动支持的CUDA版本兼容。如果你不打算用GPU,直接把torch替换成CPU版,训练速度会慢很多,但流程能走通。AMD显卡在Windows下没有官方ROCm支持,常见的做法是使用DirectML版PyTorch,或者把训练任务放到云GPU上。
数据配置部分需要自己新建一个每个项目独立的yaml文件,里面指向划分后的图片目录:
# night_vehicle.yaml train: D:/data/night_vehicle/split/train/images val: D:/data/night_vehicle/split/val/images test: D:/data/night_vehicle/split/test/images nc: 1 names: ['vehicle']train和val指向对应图片文件夹。实际训练时YOLO会按图片名自动找同名的txt标签,因此labels目录必须有与图片一一对应的文件。如果之前用的是VOC XML格式,需要先转成YOLO格式并放在labels目录中,才能让这个yaml生效。这里的nc是类别数,names是类别名称列表,顺序必须与classes.txt里的ID一致。
4.2 训练命令与关键参数
启动训练使用训练脚本自带入口,YOLOv5为train.py,YOLOv8为yolo train。这里以YOLOv5命令为例:
python train.py \ --data night_vehicle.yaml \ --weights yolov5s.pt \ --epochs 300 \ --batch-size 16 \ --imgsz 640 \ --device 0 \ --patience 50--data指向刚才写好的yaml,--weights指定预训练权重,--patience 50表示验证集mAP连续50轮不提升就提前停止。训练期间可以观察到终端输出的box_loss、cls_loss和obj_loss,夜间数据集上obj_loss通常下降最慢,因为这对应目标置信度预测,是漏检和误检的直接来源。常用参数建议汇总如下:
| 参数 | 示例值 | 作用 | 夜间场景建议 |
|---|---|---|---|
| --epochs | 300 | 最大训练轮数 | 5000张图300轮足够,配合早停使用 |
| --batch-size | 16 | 每批图数,受显存限制 | 8GB显存用16,4GB用4 |
| --imgsz | 640 | 训练输入尺寸 | 夜间小目标多,可提到768,显存占用同步上升 |
| --device | 0 | 指定GPU | 多卡用0,1,CPU训练设cpu |
| --patience | 50 | 连续N轮无提升则停止 | 防止过拟合,建议开启 |
| --cache | ram | 图片加载到内存加速 | 显存够时优先ram,小内存用disk |
| --augment | 默认开启 | 训练时数据增强 | 夜间场景降低mosaic强度,关闭mixup |
参数说明:--imgsz决定输入分辨率,夜间远处车辆可能只有几十个像素,从640提升到768能让模型学到更多细节,但显存占用会接近翻倍。--batch-size与--imgsz互相制约,如果出现CUDA out of memory,优先降batch-size而不是降分辨率。--weights使用coco预训练权重可以显著降低夜间小目标的收敛难度,因为模型已经见过丰富的物体边缘特征,迁移到夜间场景时只需要微调分布差异。
训练过程中不要只看loss绝对值,要结合验证集指标判断。如果loss持续下降但mAP长期为0,先查数据配置和标签是否对应。如果某个类别的AP远低于平均,把对应类别的图片数量统计一下,通常是不均衡。训练日志里的P和R是precision和recall,夜间场景漏检多,R偏低;灯光明亮区域误检多,P偏低。两者差距大时,说明模型学到的是亮度特征而不是车辆结构特征。
5. 夜间场景的验证指标与漏检调优技巧
训练结束后用验证命令得到COCO或VOC格式的mAP。以YOLOv5为例:
python val.py --data night_vehicle.yaml --weights runs/train/exp/weights/best.pt --batch-size 16 --conf-thres 0.15 --iou-thres 0.5--conf-thres降低到0.15后能检出一部分置信度偏低的夜间远距离车辆,代价是误检增多,需要结合precision-recall曲线决定。后处理流程中NMS的作用是把重叠框合并,夜间灯光造成的重影会让同一辆车出现多个高IoU框,这时适当提高--iou-thres到0.6可以减少误删,如果两个目标靠很近反而应该降低。验证时建议关闭TTA,否则会引入额外变量。
漏检调优顺序我一般固定为:先看验证集PR曲线,确认召回率上限;再调整confidence阈值,最后才改数据增强。夜间场景不要把mosaic和mixup同时开到最大,这会让本就缺少纹理的目标变得更难学。建议关闭mixup,把mosaic边值从1.0降到0.5,让模型更多看到完整车辆而不是被裁剪的碎片。另一个技巧是给yaml数据配置里增加hsv_h、hsv_s的增强幅度,夜间低饱和度的特点会使模型对亮度更敏感,适度降低HSV增强反而能提升稳定性。
一个很实用的做法:把原图亮度直方图均衡化后加入训练作为额外一个数据源,或者将RGB图转成YUV后取Y通道增强亮度,再与原图拼接输入。这样模型在低照度下更容易提取轮廓。但注意不要对测试集做相同操作,否则验证结果失真。训练时在--hyp参数指向的mosaic增强里将obj_loss的增益调高0.1,可以加快置信度收敛。跑验证时分类别分析,单独看car/truck的AP,夜间卡车被灯照得发白,类别AP往往比轿车低,定位到具体类别后,可以对该类别的标签权重加权或补充gamma随机调整的增强数据。
本文还有配套的精品资源,点击获取