
简介本数据集面向自动驾驶感知、道路环境识别与计算机视觉方向的学习者和开发者聚焦雨雪天气下的路面状况分类任务可区分结冰路面、雪地、下雨湿滑与干燥路面四类典型场景适合用于目标检测与图像分类模型的训练、验证及算法对比实验。资源共收录651个文件其中646张jpg原始图片、3个json标注文件与2个txt说明文件压缩包约26.92MB图片均保留原始分辨率标注采用COCO格式可直接对接主流检测框架进行数据加载与训练。目前已有1011人学习下载具备一定的社区验证基础。借助该数据集读者能够快速搭建雨雪路面状况识别流程省去自行采集与标注的成本并基于COCO标注开展模型微调、类别平衡分析与跨天气泛化能力评估为道路安全感知相关研究提供可复用的数据支撑。1. 雨雪天气路面状况数据集从文件名到 COCO 标注的落地判断拿到一个标注好的路面数据集第一反应往往不是“能跑多准”而是“这标注到底能不能用”。雨雪天气路面状况数据集就是冲着这个痛点来的它把结冰路面、雪地、下雨湿滑、干燥路面四类场景用 COCO 格式标好图片全部保留原始分辨率没有做过度压缩或裁剪。文件名里那串ice-road31_jpg.rf.647734b2a0c45eadc7006abc92df2e1c.jpg看着像随机哈希其实是标注流水线导出的典型命名说明这批图经历过一次统一的格式转换和重命名。对做自动驾驶感知、路面附着系数估计、或者冬季道路养护巡检的团队来说这类数据最值钱的地方不是“图多”而是“标注边界和类别定义是否经得起推敲”。这份资源适合已经有一定检测模型训练经验、想补冬季场景短板的人如果你还在纠结 YOLO 和 COCO 格式怎么互转建议先把手头的单类检测跑通再回来。2. 拆开 COCO 标注四类路面的定义边界与文件结构2.1 类别定义不是拍脑袋先看标注粒度结冰路面、雪地、下雨湿滑、干燥路面这四类听起来像互斥实际在图像里经常重叠。比如雪后初晴路面既有残雪又有融水标注时到底算雪地还是湿滑这份数据集的处理方式是把每个类别当作独立目标框来标允许同一张图里出现多个类别框。这意味着你在训练时不能简单用 softmax 做单标签分类得走多标签或者目标检测路线。常见做法是直接用 COCO 的categories字段定义四个类别 id然后在annotations里按框标注。我一般会先统计每个类别的框数量和图片分布如果某一类框数不到总数的 10%就要考虑是不是要过采样或者调 loss 权重。2.2 目录结构长什么样怎么快速验证完整性COCO 格式的标准结构是annotations/instances_train.json、instances_val.json加上train/、val/两个图片目录。但实际拿到的压缩包经常是扁平化的图片全堆在一个文件夹里json 也只有一个。这时候别急着写训练脚本先跑一段校验代码确认每张图都能在 json 里找到对应标注且image_id不重复。import json import os from collections import Counter # 加载 COCO 标注文件 with open(annotations/instances.json, r, encodingutf-8) as f: coco json.load(f) # 统计图片和标注数量 img_ids [img[id] for img in coco[images]] ann_img_ids [ann[image_id] for ann in coco[annotations]] print(f图片总数: {len(img_ids)}) print(f标注框总数: {len(coco[annotations])}) print(f类别列表: {[c[name] for c in coco[categories]]}) # 检查是否有标注指向不存在的图片 missing set(ann_img_ids) - set(img_ids) print(f孤立标注数: {len(missing)}) # 每类框数分布 cat_counter Counter(ann[category_id] for ann in coco[annotations]) for cat in coco[categories]: print(f类别 {cat[name]} (id{cat[id]}): {cat_counter.get(cat[id], 0)} 个框)这段代码的逻辑很直接先加载 json然后分别统计图片 id 和标注里的 image_id做差集就能发现脏数据。参数上唯一要注意的是encodingutf-8有些标注文件里带中文类别名不指定编码在 Windows 上会翻车。如果孤立标注数不为零说明标注流水线有 bug得回去找原始导出脚本别硬着头皮训。2.3 原始图片的坑分辨率不一致怎么办项目正文里强调“图片均采用原始图片”这既是优点也是麻烦。原始图片意味着分辨率、长宽比、曝光条件都不统一直接 resize 到 640x640 会把远处的结冰路面压成几个像素。我一般会先统计图片尺寸分布如果长边普遍在 1920 以上训练时用mosaic增强配合multi-scale训练比一刀切 resize 效果好得多。另外注意检查有没有灰度图混在 RGB 里COCO 标注工具通常按三通道处理遇到单通道图会直接报错。3. 把 COCO 转成 YOLO 格式转换脚本与四个边界坑3.1 为什么还要转 YOLO直接读 COCO 不行吗COCO 格式用起来最别扭的地方是标注和图片分离训练时每次都要按 image_id 去 json 里查IO 开销大。YOLO 格式把每张图的标注写成同名 txt一行一个框训练框架读起来快得多。而且很多轻量级检测框架对 COCO 的支持不如 YOLO 格式直接。转换本身不复杂但边界情况特别多下面这个脚本我用了很多次基本覆盖了常见坑。import json import os from PIL import Image def coco_to_yolo(coco_json, img_dir, out_dir): with open(coco_json, r, encodingutf-8) as f: coco json.load(f) # 建立 image_id 到文件名的映射 img_info {img[id]: img for img in coco[images]} # 建立 category_id 到连续索引的映射YOLO 要求从 0 开始 cat_ids sorted([c[id] for c in coco[categories]]) cat_id_to_idx {cid: idx for idx, cid in enumerate(cat_ids)} os.makedirs(out_dir, exist_okTrue) # 按图片分组标注 from collections import defaultdict ann_by_img defaultdict(list) for ann in coco[annotations]: ann_by_img[ann[image_id]].append(ann) for img_id, anns in ann_by_img.items(): info img_info[img_id] w, h info[width], info[height] # 用图片实际尺寸兜底防止 json 里的宽高写错 img_path os.path.join(img_dir, info[file_name]) if os.path.exists(img_path): with Image.open(img_path) as im: w, h im.size lines [] for ann in anns: # COCO 框格式: [x_min, y_min, width, height] x, y, bw, bh ann[bbox] # 转成 YOLO 的归一化中心点格式 cx (x bw / 2) / w cy (y bh / 2) / h nw bw / w nh bh / h # 裁剪到 [0,1]防止标注越界 cx, cy max(0, min(1, cx)), max(0, min(1, cy)) nw, nh max(0, min(1, nw)), max(0, min(1, nh)) cls_idx cat_id_to_idx[ann[category_id]] lines.append(f{cls_idx} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}) txt_name os.path.splitext(info[file_name])[0] .txt with open(os.path.join(out_dir, txt_name), w) as f: f.write(\n.join(lines)) print(f转换完成类别映射: {cat_id_to_idx}) coco_to_yolo(annotations/instances.json, images/, labels/)逻辑说明先建立 image_id 到图片信息的映射再把 category_id 重映射成从 0 开始的连续索引这是 YOLO 的硬性要求。参数上cx, cy, nw, nh都做了 clamp因为有些标注框会超出图片边界不裁剪的话训练时 loss 会炸。最后用图片实际尺寸兜底是因为我遇到过 json 里 width/height 写反的情况直接按 json 算会导致所有框错位。3.2 四个边界坑空标注、越界框、类别不连续、文件名冲突第一个坑是空标注图片。COCO 里有些图没有任何 annotation转换后生成空 txtYOLO 训练时会把这类图当负样本但如果负样本比例太高模型会偏向预测背景。我一般会统计空标注图占比超过 20% 就考虑剔除一部分。第二个坑是越界框上面脚本已经用 clamp 处理但更好的做法是回头修标注源文件。第三个坑是类别 id 不连续比如只有 1、3、5 三个类别直接当索引用会报错必须重映射。第四个坑是文件名冲突原始图片名里带哈希转成 txt 后如果两张图哈希前几位相同可能覆盖建议在转换时加一层唯一性校验。3.3 转换后怎么快速验证没转错转完别急着训先抽几张图把 YOLO 格式的框画回去和原图叠一起看。下面这段代码用 OpenCV 画框跑一遍就能肉眼确认。import cv2 import os def visualize_yolo(img_path, label_path, class_names): img cv2.imread(img_path) h, w img.shape[:2] if os.path.exists(label_path): with open(label_path) as f: for line in f: cls, cx, cy, nw, nh map(float, line.split()) x1 int((cx - nw / 2) * w) y1 int((cy - nh / 2) * h) x2 int((cx nw / 2) * w) y2 int((cy nh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, class_names[int(cls)], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imwrite(check.jpg, img) visualize_yolo(images/ice-road31.jpg, labels/ice-road31.txt, [结冰, 雪地, 湿滑, 干燥])跑完打开check.jpg重点看框有没有整体偏移、类别名有没有对错。如果框的位置明显偏下或偏右多半是 json 里的宽高和实际图片不一致回去查info[width]和Image.open().size的差异。4. 训练参数怎么设从学习率到类别权重的实操建议4.1 四类路面的样本不均衡怎么破结冰路面和雪地在自然场景里本来就比干燥路面少如果直接按原始分布训模型会把大部分框预测成干燥。我一般先跑一遍统计看每类框数然后决定用哪种策略。常见做法有三种过采样少数类图片、在 loss 里给少数类更高权重、或者用 focal loss 替代交叉熵。如果结冰类框数不到干燥类的三分之一我会在 dataloader 里给结冰类图片加一个 2 到 3 倍的采样权重同时把分类 loss 的类别权重设成反比。4.2 输入尺寸和增强策略的取舍原始图片分辨率高直接缩到 416 会丢细节缩到 1280 又吃显存。我的经验是如果显卡显存 8G 以下用 640 输入配合 mosaic 和 mixup让模型在训练时见到多尺度显存 12G 以上可以上 960 或 1024但 batch size 要降到 4 以下。增强方面雨雪天气本身就有光照变化所以颜色抖动可以开大一点但水平翻转要慎用——路面场景翻转后左右车道逻辑变了如果下游任务依赖车道方向翻转会引入噪声。4.3 验证集怎么切才不泄露COCO 格式的数据集如果按图片随机切 train/val同一段路的连续帧可能同时出现在两边导致验证指标虚高。正确做法是按路段或按时间切比如前 70% 的连续帧做训练后 30% 做验证。如果数据里没有路段信息至少按文件名里的序号做间隔切分别用随机切。我见过有人随机切完 mAP 到 0.85实际路测掉到 0.5就是泄露的锅。5. 避坑与排查标注、转换、训练里最容易翻车的五件事5.1 现象训练 loss 正常下降但 mAP 极低原因通常是类别索引对错了。COCO 的 category_id 可能从 1 开始YOLO 要求从 0 开始如果转换时没重映射模型学到的类别和验证时用的类别名完全错位。解决方法是转换后打印类别映射表和data.yaml里的names逐一对齐。5.2 现象验证时框全挤在图片左上角这是归一化坐标算错了。常见原因是用了 json 里的 width/height但实际图片被 resize 过两者不一致。解决方法是转换时强制用PIL.Image.open().size读实际尺寸别信 json 里的元数据。5.3 现象某些图片训练时报 “invalid bbox”COCO 标注里存在宽或高为 0 的框转换后变成nw0或nh0YOLO 的 loss 计算会直接报错。解决方法是转换时过滤掉bw 1 or bh 1的标注并在日志里记录被过滤的数量如果数量多说明标注质量有问题。5.4 现象模型把湿滑路面全预测成结冰这两类在视觉上确实像尤其是反光的路面。除了调类别权重还可以在数据增强里加一点高斯模糊和对比度扰动让模型别太依赖纹理细节。另外检查标注里有没有把湿滑误标成结冰的情况抽 50 张图人工过一遍比调参管用。5.5 现象转完 YOLO 格式后图片和标签对不上文件名里的哈希被截断或者大小写不一致都会导致这个问题。解决方法是转换时用os.path.splitext取完整文件名别手动截断并且在生成 txt 后做一次os.path.exists校验确保每张图都有对应标签。6. 进阶用法用这份数据做路面附着系数回归的迁移思路检测框只能告诉你“哪里有结冰”但下游控制模块更想知道“这段路的摩擦系数大概是多少”。一个实用的迁移思路是把四类路面当作离散的附着系数等级用检测框的类别概率做加权平均得到一个连续的附着系数估计值。具体做法是先训好检测模型推理时对每个框取类别 softmax 概率然后按μ Σ(p_i * μ_i)算其中μ_i是每类路面的经验附着系数比如干燥 0.8、湿滑 0.5、雪地 0.3、结冰 0.1。这样不用重新标回归数据就能把分类结果转成控制模块能用的连续量。验证这个思路是否靠谱可以拿一小段有 GPS 和 IMU 的路测数据做对比把检测模型输出的 μ 和车辆实际制动减速度反推的 μ 做相关性分析如果 Pearson 系数低于 0.6说明类别定义或者权重需要调。我一般会先用这份数据集训一个 baseline然后在自己的路测数据上做 fine-tune最后用滑动窗口平滑 μ 输出避免单帧误检导致控制抖动。从那以后我每次拿到新的路面数据集都强制先跑一遍标注校验和可视化再谈训练。希望帮到你。本文还有配套的精品资源点击获取