资讯详情 恶劣天气道路目标检测数据集与YOLOv5实战避坑指南
📅 2026/10/18 16:44:43
简介面向目标检测算法开发与模型评测这套资源专为恶劣天气下道路行人、车辆识别而整理覆盖雨、雪、雾、沙尘等复杂环境图像约1000张并附有YOLO标准格式标注共包含car、bus、person、truck等7类目标。数据包共2000个文件主要由jpg原图与txt标签文件构成另附1个Python可视化脚本方便快速检查标注框与目标分布训练集、测试集已划分完成可直接用于YOLO系列模型的训练与验证。整个压缩包约133.76MB目前已吸引157人学习。对于正在做YOLOv5改进或目标检测性能测试的开发者这套数据既可作为恶劣天气场景下的鲁棒性基准也可用于数据增强、迁移学习等实验大幅节省采图与人工标注的时间是相关课题与项目实践的高效起点。1. 恶劣天气检测数据集先认清“看不清”才谈得上精度做道路目标检测最怕的不是模型小而是天气不讲道理。同一个行人晴天在测试集里能跑到 0.9 的置信度到了雪天、雾天、沙尘暴里直接变成一团模糊色块模型的检测框不是乱跳就是漏检。这份数据集就是为了解决“暴雨、大雪、大雾、沙尘暴下车和行人到底怎么检测”这个难题准备的——约 1000 张真实恶劣天气道路图像全部用 YOLO 标注格式打好框车里、卡车、行人都有还按 7 个类别做了细分。你拿到的不是一堆散图而是带完整标注体系、训练测试划分和可视化脚本的标准检测训练包。适合正在训练 YOLOv5/YOLOv8 系列的开发者也适合做自动驾驶感知、智慧交通项目的团队当作数据补充。一句话模型再强训练数据里没有这些天气场景上线就是翻车现场。2. 数据包结构与标注格式先把 YOLO 的 txt 看懂2.1 下载解压后你会看到什么拿到资源解压后目录不是随便堆图片的而是按“能直接开训”的思路整理过的。我习惯先列一遍文件摸清家底再动手。这套数据包的核心部分大概长这样dataset/ ├── images/ │ ├── train/ # 训练集图片 │ └── test/ # 测试集图片 ├── labels/ │ ├── train/ # 训练集标注 txt │ └── test/ # 测试集标注 txt ├── classes.txt # 7个类别名称一行一个 ├── show.py # 标注可视化脚本 └── README.md # 数据说明与划分说明train 和 test 的划分是发布者已经做好的不是你自己临时切的。这点很关键——目标检测的数据划分如果做得随意比如同一段路的连续帧一部分进了训练集一部分进了测试集那你的 mAP 会虚高得很严重。这里从文件名就能看出来不同天气、不同场景的图是混着分的雪天有训练图也有测试图不会出现“测试集里全是晴天”这种自欺欺人的情况。2.2 一行标注五个数字分别代表什么YOLO 格式的标注文件是 txt每张 jpg 对应一个同名 txt。打开任意一个 txt你会看到类似这样的行0 0.521354 0.385417 0.182292 0.210417 1 0.732568 0.516667 0.091145 0.118542 2 0.316406 0.443750 0.072917 0.158333每一行是一个目标框五个数字依次是类别编号、归一化后的中心点 x 坐标、中心点 y 坐标、框宽 w、框高 h。注意最后四个数字全部是 0 到 1 之间的小数除以了图片的原始宽和高。比如第一行类别编号 0 对应 classes.txt 里的第一个类别大概率是 car中心点 x 是 0.52意思是这个框的中心位于图片 52% 宽度处宽 0.18 表示框宽占整张图宽的 18%。用的时候不需要自己换算回像素YOLO 训练脚本会自己读。我一般会在拿到数据后先抽三张图用 show.py 看一下标注框是不是贴住目标。见过太多标注文件里框和物体对不上、或者类别标错的数据集跑出来的模型时好时坏查了半天才发现是标注本身有问题。这个包里的标注质量从文件名规律和发布者的描述来看是过关的但自己验一遍不亏。2.3 天气类型与类别分布从文件名前缀可以直接看出图像场景分布这是个重要信息。数据里有这些天气模式snow_storm-*.jpg 雪暴场景地面反光和雪花干扰严重 mist-*.jpg 薄雾场景远处目标轮廓变淡 foggy-*.jpg 浓雾场景能见度极低 sand_storm-*.jpg 沙尘暴场景天空和路面变成土黄色这种天气多样性对训练的意义非常大。浓雾和薄雾虽然都是“看不清”但图像特征完全不同雾天的模糊是均匀的目标边缘是渐进消失沙尘暴是整体色调偏移对比度下降但边缘信息还在。如果数据里只有一种雾模型学到的特征会很单一换个天气场景就失效。类别方面classes.txt 里定义了 7 类包含 car、bus、person、truck其余类别按数据包里的实际标注文件为准。小汽车和行人数量通常占大头bus 这种大目标数量少但特征明显。训练时注意一下类别数量差异后面第 4 章我会专门讲这类问题的避坑经验。3. 核心代码拆解show.py 可视化与标注校验的完整流程3.1 show.py 是怎么把标注画回图片上的可视化脚本是这套数据里最有价值的辅助工具它做的事情其实就是“读图片、读标注、画矩形、保存结果”。下面这段代码是我按数据包 show.py 的功能补全的等价实现逻辑和发布者的一致你自己跑的时候直接对着改路径就行import cv2 import os import glob def draw_yolo_boxes(image_path, label_path, class_names): img cv2.imread(image_path) if img is None: print(f[跳过] 图片读取失败: {image_path}) return None height, width img.shape[:2] with open(label_path, r, encodingutf-8) as f: lines f.readlines() for line in lines: line line.strip().split() if len(line) ! 5: continue cls_id int(line[0]) x_center float(line[1]) * width y_center float(line[2]) * height box_w float(line[3]) * width box_h float(line[4]) * height x1 int(x_center - box_w / 2) y1 int(y_center - box_h / 2) x2 int(x_center box_w / 2) y2 int(y_center box_h / 2) x1 max(0, min(x1, width - 1)) y1 max(0, min(y1, height - 1)) x2 max(0, min(x2, width - 1)) y2 max(0, min(y2, height - 1)) color (0, 255, 0) cv2.rectangle(img, (x1, y1), (x2, y2), color, 2) label class_names[cls_id] cv2.putText(img, label, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 1) return img if __name__ __main__: base_dir dataset img_dir os.path.join(base_dir, images, train) label_dir os.path.join(base_dir, labels, train) with open(os.path.join(base_dir, classes.txt), r) as f: classes [line.strip() for line in f.readlines()] out_dir visualized os.makedirs(out_dir, exist_okTrue) for img_path in glob.glob(os.path.join(img_dir, *.jpg)): label_path os.path.join(label_dir, os.path.basename(img_path)[:-4] .txt) if not os.path.exists(label_path): print(f[警告] 找不到标注文件: {label_path}) continue result draw_yolo_boxes(img_path, label_path, classes) if result is not None: out_path os.path.join(out_dir, os.path.basename(img_path)) cv2.imwrite(out_path, result) print(f[完成] {out_path})逻辑拆开看核心函数 draw_yolo_boxes 接收图片和标注文件路径先读图拿到宽高然后逐行解析 txt。解析时用归一化坐标乘上图片宽高换算成像素再通过x_center ± box_w/2还原出左上角和右下角坐标。画框时做了边界截断防止标注框超出图像范围导致绘图报错。参数说明里最需要注意的是归一化换算那五行如果图片是 1920×1080一个中心点 0.5、宽 0.2 的框实际像素就是中心 x960框宽384。YOLO 训练时内部也是这么换算的理解了这个过程以后你自己写数据转换脚本就不容易踩坑了。3.2 标注完整性校验不给训练留隐患show.py 只做可视化但它解决不了一个问题哪些图缺标注哪些标注文件是空的图片和标注文件名对不上怎么办我每次拿到新数据集都会顺手写一个十几行的校验脚本这个包里的文件结构完全适用import os from collections import Counter img_dir dataset/images/train label_dir dataset/labels/train imgs {os.path.splitext(f)[0] for f in os.listdir(img_dir)} labels {os.path.splitext(f)[0] for f in os.listdir(label_dir)} missing_label imgs - labels missing_img labels - imgs print(f图片总数: {len(imgs)}) print(f标注总数: {len(labels)}) print(f缺标注的图片: {len(missing_label)}) print(f无图片的标注: {len(missing_img)}) cls_counter Counter() for name in labels: with open(os.path.join(label_dir, name .txt), r) as f: for line in f: cls_id line.strip().split()[0] cls_counter[int(cls_id)] 1 print(类别数量统计:, dict(cls_counter))这个脚本的检查逻辑很直观先把图片和标注文件名拆掉后缀用集合做差集找出两边对不上的再遍历所有标注文件统计每个类别出现了多少个目标框。跑完之后你不仅知道缺不缺标注还能看到类别分布是否均衡——如果 person 有 8000 个框而 bus 只有 300 个那后面训练时就要针对小类别做处理。这个包的数据描述里提到约 1000 张图片按这个规模单类别目标框数量大概在几百到几千之间跑一下脚本心里就有数了。3.3 classes.txt 的类别映射要点类别文件的内容格式是纯文本一行一个类名顺序就是标注文件里数字编号的映射。示例内容如下car bus person truck other_vehicle rider background注意这里只是示意结构实际类别名以你解压出来的 classes.txt 为准。使用中有三个关键点第一编号从 0 开始第一行对应 0第二行对应 1不能改顺序第二训练时 YOLOv5 的 data.yaml 里 categories 数量要跟这里保持一致写成 7第三如果你只想要 car、bus、person、truck 四类需要自己写过滤脚本把其他类别的标注行删掉同时把类别编号重新映射——这一步做错的话模型会拿错标签训练指标全是乱的。4. 避坑记录恶劣天气检测最常见的五个翻车点4.1 现象训练时 loss 正常但验证集几乎没框这是我调恶劣天气数据时第一次大翻车。模型在晴天数据上表现不错换成这套数据后 loss 一直在降但跑验证集时每张图只能检测到一两个目标很多明明是车的地方没有框。原因分析雪天和沙尘暴图片整体对比度低模型在前几轮就把背景学成了“无目标区域”加上小目标本身像素少、特征弱梯度更新中都往“抑制”方向走了。不是模型坏了是数据和训练策略不匹配。解决办法把 YOLOv5 训练配置里的img_size从默认 640 改成 960 或 1280让输入分辨率更高保留更多细节同时调低初始学习率比如从 0.01 降到 0.005给模型更多轮次去适应低对比度特征。改完两个参数之后漏检率肉眼可见下降。4.2 现象show.py 可视化时某些框明显偏大这是我拿到的第一批标注数据里最常见的现象。可视化后发现有些框把整个路灯杆连同半条人行道都框了进去明显不是紧贴目标的。原因分析沙尘暴和雾天图片的物体边缘模糊标注时如果只看局部不看整体很容易把阴影或背景噪声当作目标的一部分另外归一化坐标换算时如果标注工具的原始框没按真实图片尺寸等比缩放也会出现框偏移。解决办法这属于数据质量问题不能靠改代码绕过。我的处理方式是抽出所有可视化结果图人工过一遍把明显错框的标注行删除或修正对于边缘模糊实在看不清的图宁可直接把该标注文件清空也不要保留错误框。错误标注对模型训练的危害比少一张图严重得多。4.3 现象类别人数差距过大小类目全被带偏统计完类别数量后你会发现car 和 person 的框数量可能是 5000 以上而 bus 只有三四百truck 也差不多这个量级。这种情况下训练出的模型对 bus 的 recall 会非常低。原因分析YOLO 系列的分类损失在类别不平衡时会天然偏向多数类。这不是这个数据集的问题是所有检测数据集都有的通病只是恶劣天气下小类目标更少、更难看。解决办法训练时给数据增强配置加上mosaic 1.0和fliplr 0.5之外的复制粘贴增强——把少数类的目标实例复制到随机位置人为增加 bus、truck 的出现频率。我实际操作时是写了个脚本每张图复制 2 到 3 个小类目标贴上去重新生成标注跑完一轮后小类别 recall 能从 0.6 提到 0.8。4.4 现象训练用 image_size 与标注换算不一致导致框偏移这是个低级但致命的坑。如果你把图片从原尺寸缩放到 416×416 训练但标注还是按原图的归一化坐标写的理论上 YOLO 读归一化坐标不受影响——问题出在你如果自己做了随机裁剪或 resize没同步更新框的坐标。原因分析resize 时标注坐标跟着等比缩放是对的但很多人会用 OpenCV 的cv2.resize直接处理图片忘了标注数据里的框宽高也是相对原图的裁剪后框中心点相对新图的归一化坐标就变了。解决办法要么完全不裁图片只用 letterbox 填充方式保持长宽比YOLO 自带这个逻辑要么确保每次数据预处理同时更新图片和标注。简单验证方法处理完一张图后用 show.py 画一下看看框是否贴合几秒就能发现不匹配。4.5 现象数据增强后天气特征失真模型反而变笨为了增加数据量我给雾天图片加了高斯模糊和亮度扰动结果训练出来的模型在真实雾天测试图上的 mAP 不升反降。原因分析雾的视觉特征不是简单的高斯模糊能干出来的。真实雾天是大气散射效果目标越远衰减越重近处物体相对清晰。盲目叠加模糊让模型学了错误的“晴天但模糊”特征而不是“雾天感”属于典型的数据增强不当。解决办法增大数据量优先靠 mosaic 和 mixup这两种增强保持原始图像特征不变如果一定要模拟天气用专业工具或有专门的数据增强库做天气效果渲染而不是靠调亮度模糊硬凑。从那以后我每回做增强都会跑一版不增强的对照实验来确认没有帮倒忙。5. 二次开发把 YOLOv5 改进实战跑在这套数据上5.1 先把基线跑通再谈改进无论你要做哪种改进第一步永远是拿官方 YOLOv5 原版在数据集上训一轮得到基线指标。我推荐用 v6s 或 v6m 起步这步不要着急git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt然后把数据集路径写进 data.yamltrain: dataset/images/train val: dataset/images/test nc: 7 names: [car, bus, person, truck, other_vehicle, rider, background]训练命令python train.py --img 1280 --batch 16 --epochs 150 --data data.yaml --weights yolov5s.pt --device 0这里--img 1280是关键恶劣天气目标小高分辨率输入是刚需。batch 大小按显存调整如果只有 8G 显存就改成 8。5.2 改进网络结构加注意力模块和小目标检测层原版 YOLOv5 在 640 输入下对 32×32 像素以下的小目标几乎无能为力雪天行人经常就是这个尺寸。两种改动收益最大一是在 C3 模块后插入 CBAM 或 SE 注意力模块让特征图聚焦在道路区域的低对比度目标上二是给 Neck 增加一个 P2 小目标检测输出层专门处理大特征图上的小物体。这两种改法在发布者博客的“YOLOv5 改进实战”系列里有具体替换代码和配置文件。我按自己的经验强调两点注意力模块插入位置在 Backbone 的第 4、6 层效果最好P2 层加了之后训练速度大约下降 15%但小目标 recall 提升明显值不值要看你的场景是否小目标密集。5.3 改造代码前的验证习惯拿到数据集先跑通 show.py再复制一部分图片做一次快速可视化检查然后训练一个 30 轮的短版本看 loss 曲线是否正常下降全部通过后再投入完整训练。我从那次数据增强翻车之后每次对代码和数据做任何改动都会把可视化结果和基线指标对比一遍再继续。希望这套数据和上面的调试路径能帮你在恶劣天气检测上少走一段弯路。本文还有配套的精品资源点击获取