YOLOV5雾天行人车辆目标检测:数据集目录规范与训练排错全解析
2026/9/15 0:13:56 网站建设 项目流程

简介:这套目标检测数据集面向雾天场景下的行人、车辆识别任务,按YOLOV5标准目录格式整理,包含人、轿车、公交车、自行车、摩托车五类标注,适合训练雾天环境下的目标检测模型,也可用于自动驾驶、智能交通等相关研究。包体为zip压缩包,共2000个文件,其中1999个为txt标注文件(含类别信息与边界框坐标),另附1个可视化py脚本,可直接运行并绘制检测框,压缩包整体约123.5MB。数据划分为训练集4320张图片及对应标签、验证集100张图片及对应标签,图像分辨率为400~1000的RGB图片,无需额外处理即可直接接入YOLOv5训练流程。已有405人浏览学习,适合需要雾天场景数据扩充或快速搭建检测实验的研究者与开发者使用,配套脚本还能帮助直观核查标注效果。

1. 雾天数据集是一道“送分题”,但多数人栽在目录格式上

做目标检测的都知道,模型在晴天数据上跑得很好,一到雨雾天气就掉点严重。雾天意味着低对比度、细节退化、远处目标基本模糊成一团,行人车辆这类目标又往往是安全监控和自动驾驶的核心对象。所以“雾天下的行人、车辆目标检测数据集”看着是个细分方向,其实是很多落地项目躲不开的硬需求。这类数据集通常按 YOLOV5 目录格式组织,5 个类别常见的是行人、骑行者、小轿车、公交车、卡车之类。但很多人下载了数据集,第一反应是打开图片看内容,却忽略了目录结构、label 格式和 yaml 配置。实际上,YOLOV5 对数据集的读取完全依赖目录规范和标签文件的数值格式,一个文件夹放错位,训练直接报错或者类别全乱。这篇文章就从目录格式说起,把雾天数据集从准备到训练的完整链路走一遍,新手能照做,老手也能看看边界和坑。

2. YOLOV5 目录格式拆解:5 类别数据集必须严格遵守的结构

2.1 标准目录树与 images/labels 的强对应关系

拿到一个号称 YOLOV5 格式的数据集,先不要急着训练,第一步是核对目录结构。YOLOV5 官方数据集的通用布局长这样:

fog_dataset/ ├── images/ │ ├── train/ │ │ ├── fog_001.jpg │ │ └── ... │ ├── val/ │ │ └── ... │ └── test/ # 可选,通常不配 test 也可以 └── labels/ ├── train/ │ ├── fog_001.txt │ └── ... ├── val/ │ └── ... └── test/

每个 images 下的图片,必须在 labels 下对应同名、同子目录的 txt 文件。比如images/train/fog_001.jpg对应labels/train/fog_001.txt。文件名完全一致,只是扩展名不同。这个对应关系是硬性的,YOLOV5 通过路径前缀替换来找 label,如果缺少 label,训练时会输出WARNING: No labels found然后跳过该图。

雾天行人车辆数据集最常见的问题是有的人把原始图片和标注混放在一个大目录里,或者 labels 里放了 PASCAL VOC 的 xml,这都不是 YOLOV5 能直接吃的格式。5 类别数据集的目录规范没有特殊之处,只是你需要在 yaml 里明确 5 个类别的顺序,且这个顺序必须和所有 txt 标签里的类别编号保持一致。

2.2 label txt 文件格式:每行 5 个数的顺序不能错

label txt 每一行代表一个目标,格式是:

class_id x_center y_center width height

注意是归一化坐标,数值范围 0~1。计算方式是像素坐标除以图片宽高。例如图片宽 1280、高 720,某个行人的边界框左上角 (320, 180),右下角 (640, 540),那么:

x_center = (320 + 640) / 2 / 1280 = 0.375 y_center = (180 + 540) / 2 / 720 = 0.5 width = (640 - 320) / 1280 = 0.25 height = (540 - 180) / 720 = 0.5

对应行就是0 0.375 0.5 0.25 0.5

这里有两个高频错误:一是类别 id 从 1 开始而不是从 0 开始,二是忘记归一化直接写像素坐标。YOLOV5 训练时不会报错,但 loss 会直接爆炸或 mAP 为 0。5 类别的数据集,class_id 应该是 0 到 4,顺序要和 data.yaml 的 names 列表一致。

2.3 data.yaml 配置:5 类别名称与路径

在 YOLOV5 项目根目录下,自己的数据集需要一个 yaml 文件,典型写法:

# fog_pedestrian_vehicle.yaml train: ./fog_dataset/images/train val: ./fog_dataset/images/val nc: 5 names: ['pedestrian', 'cyclist', 'car', 'bus', 'truck']

注意 train 和 val 指向的是 images 目录,不是根目录,也不是 labels 目录。YOLOV5 会自动把images替换成labels去找标注文件。nc是类别数量,必须和 names 长度一致。名称顺序一旦固定,不要随意调整,否则训练出来的权重应用到推断时,类别会错位。

这里我给一个快速校验脚本,训练前先跑一遍,能省大量排错时间:

import os from pathlib import Path img_dir = Path('./fog_dataset/images/val') label_dir = Path('./fog_dataset/labels/val') img_files = list(img_dir.glob('*.jpg')) + list(img_dir.glob('*.png')) missing = [] for img in img_files: label = label_dir / (img.stem + '.txt') if not label.exists(): missing.append(img.name) print(f'Total images: {len(img_files)}, missing labels: {len(missing)}') if missing: print('First 10 missing:', missing[:10])

脚本遍历 val 图片,检查同名 label 是否存在。正常情况 missing 应为空。如果漏标比较多,建议直接补标或删除对应图片,而不是让 YOLOV5 内部忽略它们。

3. 雾天下行人车辆数据集的构建路径:采集、合成与标注

3.1 真实雾数据不足时的替代方案:大气散射模型合成雾

真实雾天图像的采集成本高、时段受限,想凑齐 5 类目标且数量均衡非常难。业界常用做法是拿清晰图像做雾霾合成,用的大气散射模型:

import cv2 import numpy as np def add_fog(image, beta=0.6, A=200): """ 大气散射模型合成雾 image: BGR 图像 beta: 雾浓度系数,越大雾越浓 A: 大气光值,0~255 """ h, w = image.shape[:2] # 生成与图像同尺寸的深度图,模拟远近景差异 depth = np.ones((h, w), dtype=np.float32) depth[:, w//2:] = 0.6 # 右半边距离更远,雾更浓 depth = cv2.GaussianBlur(depth, (31, 31), 0) t = np.exp(-beta * depth) # 透射率 fog = A * (1 - t) # 大气光散射项 fog_image = image * t[:, :, np.newaxis] + fog[:, :, np.newaxis] fog_image = np.clip(fog_image, 0, 255).astype(np.uint8) return fog_image img = cv2.imread('clear_car.jpg') fog = add_fog(img, beta=0.8, A=180) cv2.imwrite('fog_car.jpg', fog)

这个模型里beta决定雾气浓度,A是环境光强度。调整 beta 可以从薄雾到浓雾,丰富训练样本。注意这里的 depth 是随意模拟的,实际使用时可以利用图像分割或深度估计得到更真实的深度关系。生成雾图后,原图对应的 label 坐标完全不变,可以直接复用,这对 5 类别标注数据来说是低成本扩充样本的好办法。

3.2 5 类别的标注规范:边界框定义与漏标问题

雾天数据集的目标往往边界模糊,标注员容易漏标后续帧或只标亮处的目标。5 类别人车混合场景下,我一般建议按以下规则执行:

  • pedestrian:行人,包含走路、站立、奔跑,不含骑自行车的人。
  • cyclist:骑自行车/电动车的人,人和车作为一个整体框。
  • car:小轿车、SUV、面包车这类小型乘用车。
  • bus:公交车、大巴。
  • truck:卡车、货车。

边界框要框住目标的最小外接矩形,雾中目标如果只露出一部分,只要可辨识就标,完全看不清的跳过。使用 LabelImg 或 LabelStudio 导出 YOLO 格式即可,但导出时一定要确认类别 id 顺序。标注完成后要用脚本统计类别分布。

3.3 类别不平衡的应对:不只为指标,更要为有效训练

真实雾天场景里行人数量往往远少于车辆,5 类样本极不均衡。先统计:

python -c " from collections import Counter import glob c = Counter() for f in glob.glob('fog_dataset/labels/train/*.txt'): for line in open(f): c[int(line.split()[0])] += 1 print(c) "

这个命令统计 train 标签里每个类别的目标总数。如果 car 有 12000 个而 cyclist 只有 400 个,有两种常用策略:一是对 minority 类做 oversampling,复制包含该类别的图片到训练目录;二是设置 YOLOV5 的cls损失权重,但这需要修改 loss 代码,对新手不友好。最直接的是通过图像增强增加少数类样本,例如对包含行人和骑手的图片做水平翻转、随机裁剪、亮度扰动,这比数据本身更可控。

4. 用 YOLOV5 训练雾天行人车辆模型:命令、参数与排错

4.1 环境配置与数据划分准备

训练前先确认 YOLOV5 运行环境,通常需要 PyTorch 和 CUDA。推荐用官方仓库:

git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt

数据划分建议使用脚本按比例拆分,手动拖拽容易出错。下面这个脚本把图片和标签同步划分到 train/val:

import random from pathlib import Path import shutil random.seed(42) root = Path('./fog_all') train_ratio = 0.8 imgs = list((root / 'images').glob('*.jpg')) random.shuffle(imgs) split = int(len(imgs) * train_ratio) for i, img in enumerate(imgs): sub = 'train' if i < split else 'val' dest_img = root / 'images' / sub / img.name shutil.move(str(img), dest_img) src_label = root / 'labels' / (img.stem + '.txt') shutil.move(str(src_label), root / 'labels' / sub / (img.stem + '.txt'))

脚本会创建 train/val 子目录并移动文件。注意root/'images'是原始图片目录,移动后你需要保留 train/val 子目录结构。实际操作中我会先建好目录再移动,生产级脚本还要处理重复同名文件,这里不再展开。

4.2 训练命令与最重要的 4 个参数

一切就绪后,最简单的训练命令:

python train.py --data fog_pedestrian_vehicle.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --name fog_run1

各参数含义:

  • --data指定我们刚才写的 yaml。
  • --weights使用 COCO 预训练权重,迁移学习能显著加速收敛,尤其适合雾天这种边缘场景。如果从零训练写--weights ''
  • --img训练分辨率,雾天小目标多,建议 640 起步,显存够用可以上 1280,但会加倍耗时。
  • --batch根据显卡显存调整,报 CUDA out of memory 就减半。
  • --epochs100 轮是常见设置,模型在 60 轮后基本收敛。

有一个容易被忽略的参数是--cache,它可以把图片缓存到内存,加快数据读取。当数据集数千张时,效果明显:

python train.py --data fog_pedestrian_vehicle.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --cache

4.3 训练失败的高频原因:路径、隐藏字符与类别数

根据维护数据集的经历,最常遇到的报错是:

assert labels.shape[-1] == 5, f'labeled boxes should have 5 values, but got {labels.shape[-1]}'

这个断言出错,九成原因是 label 文件每行不足 5 个数,要么是漏了最后一个 height,要么是行尾有多余空格导致读取异常。检查方式是写个小脚本逐个文件数行内容长度。

另一个坑是下载的数据集在 Windows 下解压,目录名带了隐藏空格或全角字符,YOLOV5 在 Linux 服务器上跑时找不到路径。用ls -la仔细看目录名,或用find . -name "*.txt" | head确认实际路径。

还有类别数问题:有的压缩包里 label 有 6 类,虽然 yaml 只写了 5,但 label 中出现了 id=5,训练过程不会在开头报错,而是在计算 loss 时索引越界。所以训练前要检查所有 txt 中出现的最大类别 id:

python -c " import glob max_id = 0 for f in glob.glob('fog_dataset/labels/train/*.txt'): for line in open(f): if line.strip(): max_id = max(max_id, int(line.split()[0])) print('max class id:', max_id) "

如果输出的最大 id 大于等于 nc,那么不是少了标注就是 nc 配错了。

5. 在雾天验证集上评估模型,并针对低对比度场景做最后调优

5.1 用 val 数据算 mAP,别只看最后的训练曲线

训练结束后,YOLOV5 会在runs/train/fog_run1下生成results.png,里面包含 mAP 曲线。但训练曲线有波动,可靠的做法是单独跑验证:

python val.py --data fog_pedestrian_vehicle.yaml --weights runs/train/fog_run1/weights/best.pt --img 640 --task val

输出会给出各类别的 P、R、mAP@0.5 和 mAP@0.5:0.95。对于雾天场景,行人这类小目标通常 mAP 偏低,不要只看整体的 0.7 就觉得完事,要逐类看。

我把常见的评估表列一下:

类别样本数PRmAP@0.5
pedestrian12000.720.680.71
cyclist4500.610.550.58
car32000.850.820.86
bus3000.880.900.91
truck8000.800.790.81

cyclist 低是常见的,因为雾天骑行者目标小、边缘模糊,且有遮挡。如果 cyclist 只有几百个样本,第一优先是补数据,而不是调超参数。

5.2 最后一招:针对雾天的预处理和多尺度测试

模型已经训练完,如果还想提升雾天表现,最有效的不是加大模型,而是在推理时加入预处理。一种常用方法是先做去雾再做检测,但去雾算法可能引入噪声;更稳妥的是在测试时做多尺度预测,把原图缩小再放大,分别推理后合并结果:

python detect.py --weights runs/train/fog_run1/weights/best.pt --img 640 --source fog_test/ --augment

--augment会启用测试时增强,包括翻转和多尺度,对模糊目标有一定增益。另外,如果训练时用的是--img 640,评估时不要突然用--img 1280期待变好,这会让模型产生尺度偏移。除非你从一开始就用多尺度训练,保持输入一致性比所谓“高分辨率更准”更重要。

最后要提的是自适应锚框。雾天目标尺寸分布和 COCO 不同,比如公交车长宽比接近 2:1,而行人接近 1:2。训练时可以加--noautoanchor关闭自适应,或直接让 YOLOV5 重新计算:

python train.py --data fog_pedestrian_vehicle.yaml --weights yolov5s.pt --img 640 --batch 16 --epochs 100 --noautoanchor

去掉--noautoanchor就是自动计算,日志里会打印新锚框。如果你的验证集 mAP 卡在一些特定尺寸上,检查锚框是否覆盖了对应宽高。雾天数据集的全流程做到这里,剩下的就是跑通、看数据、迭代,没有别的捷径。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询