ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

恶劣天气道路目标检测:1000张YOLO数据实战指南

恶劣天气道路目标检测:1000张YOLO数据实战指南 简介本资源是一套专为恶劣天气场景下目标检测任务设计的高质量图像数据集面向计算机视觉方向的初学者与进阶开发者解决雨雪、雾、沙尘等低能见度条件下行人与车辆检测模型训练难、泛化弱的问题。数据集共约1000张真实道路图像972张JPG及对应YOLO格式标注文件1027个TXT含car、bus、person、truck等7类目标已划分训练集与测试集并附带可视化脚本1个PY文件便于快速验证标注质量与数据分布。压缩包总计2000个文件大小133.76MB结构规范、开箱即用。目前已有155人学习下载读者可直接用于YOLOv5等主流检测框架的训练与改进实践配套博主在CSDN发布的YOLOv5实战文章含环境配置、数据加载、性能调优等完整流程亦可延伸参考其主页中医学图像分割、多类目标检测等系列项目形成系统性学习路径。1. 恶劣天气下道路目标检测为什么1000张YOLO标注数据能成为你模型鲁棒性的“压舱石”你训练了一个在晴天COCO数据集上mAP达到78%的YOLOv8s模型但一到雨雾天检测框就集体“失踪”——行人漏检率飙升42%车辆误检成路牌甚至把积水反光识别成小轿车。这不是玄学是光照畸变、对比度坍塌、纹理模糊带来的系统性失效。而手头这份恶劣天气下道路上的行人、车辆图像目标检测数据已标注约1000张YOLO格式恰恰卡在工业落地最痛的咽喉处它不是通用数据集而是真实场景的“故障快照”。它不追求规模但每一张都带着雨滴轨迹、雾气散射、低照度噪声和运动模糊每一个YOLO标签都经过人工校验框住了被水汽虚化的车尾灯、被雾霭吞没的行人轮廓。适合谁适合正在做智慧路口、车载ADAS、环卫作业监控的工程师——你不需要从零爬取、清洗、标注更不必在LabelImg里熬通宵调锚点你拿到的就是可直接喂进训练管道的“带病样本”是验证模型是否真能扛住现实世界的第一道压力测试。接下来我会带你用这1000张数据跑通从环境准备、数据质检、模型微调到部署前关键指标验证的全链路不绕弯、不跳步、不编造参数。2. 用YOLOv8在本地跑通恶劣天气检测最小可行训练命令与数据结构校验2.1 数据目录结构必须严格遵循Ultralytics规范否则训练会静默失败Ultralytics官方对YOLOv8的数据组织有强约束尤其当你的数据来自第三方标注时极易因路径或命名不一致导致KeyError: images或No images found。这不是代码bug是数据契约没签好。我建议你按以下结构重建本地目录以Linux/macOS为例Windows路径仅需将/替换为\# 假设你解压后的原始数据在 ~/Downloads/bad_weather_data/ # 请务必创建新目录不要直接在原始包里操作 mkdir -p ~/yolo_weather/data/{images,labels}/{train,val} mkdir -p ~/yolo_weather/data/{images,labels}/test # 将原始1000张图按7:2:1比例拆分700训练200验证100测试 # 注意原始数据若含jpg/jpeg/png混用请统一转为.jpg并重命名如img_001.jpg cp ~/Downloads/bad_weather_data/images/train/*.jpg ~/yolo_weather/data/images/train/ cp ~/Downloads/bad_weather_data/labels/train/*.txt ~/yolo_weather/data/labels/train/ cp ~/Downloads/bad_weather_data/images/val/*.jpg ~/yolo_weather/data/images/val/ cp ~/Downloads/bad_weather_data/labels/val/*.txt ~/yolo_weather/data/labels/val/ cp ~/Downloads/bad_weather_data/images/test/*.jpg ~/yolo_weather/data/images/test/ cp ~/Downloads/bad_weather_data/labels/test/*.txt ~/yolo_weather/data/labels/test/提示YOLOv8要求images/和labels/下子目录名train/val/test必须完全一致且.jpg文件名与同名.txt文件名不含扩展名必须100%匹配。例如images/train/00123.jpg对应labels/train/00123.txt。我曾因原始数据里存在IMG_00123.JPG大写JPG和00123.txt小写不匹配导致训练时只加载了37张图却无报错——这种静默失败最耗时间。2.2 创建dataset.yaml定义类别、路径与划分一行都不能错YOLOv8不读取硬编码路径一切由dataset.yaml驱动。新建文件~/yolo_weather/data/dataset.yaml内容如下注意缩进是2个空格不是tabtrain: ../data/images/train val: ../data/images/val test: ../data/images/test nc: 2 names: [person, vehicle]nc: 2表示类别数必须与names列表长度一致names顺序必须与.txt标签中类别ID严格对应0代表person1代表vehicle路径是相对于dataset.yaml所在位置的相对路径../data/images/train表示从dataset.yaml向上退一级到yolo_weather/再进入data/images/train。逻辑说明Ultralytics在加载数据时会先读dataset.yaml再根据train字段拼接完整路径最后遍历该路径下所有.jpg文件并尝试寻找同名.txt。如果names写成[vehicle, person]则所有0标签会被解释为vehicle导致全部行人被误标为车辆——这种错误在验证阶段mAP骤降时才暴露但根源在配置文件。2.3 运行最小训练命令用预训练权重微调5分钟内看到loss下降不要从头训恶劣天气数据量仅1000张从零训YOLOv8s会过拟合。我们用Ultralytics官方提供的yolov8s.pt约15MB作为预训练权重在其基础上微调。执行以下命令确保已安装ultralytics8.2.0# 进入yolo_weather目录 cd ~/yolo_weather # 启动训练关键参数说明见下方 yolo detect train \ datadata/dataset.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ nameweather_v8s_finetune \ projectruns/train \ device0 \ workers4 \ patience10 \ exist_okTrueepochs1001000张图×100轮≈10万次迭代足够收敛imgsz640输入尺寸640是v8s默认若显存不足可降为320但小目标检测能力下降batch16每批16张图若GPU显存6GB需降至8或4patience10验证集mAP连续10轮不提升则自动停止防过拟合exist_okTrue避免因runs/train/weather_v8s_finetune已存在而报错。参数说明device0指定使用第0块GPU若无GPU删掉此行自动启用CPU极慢不推荐。workers4是数据加载进程数设为CPU核心数的一半较稳设太高反而因I/O阻塞拖慢训练。3. 恶劣天气数据的3个致命陷阱标注质量、光照一致性与类别歧义3.1 标注框必须覆盖“雾中轮廓”而非“清晰实体”——否则模型永远学不会雾中推理恶劣天气下行人常只剩一个灰白色剪影车辆尾灯是唯一可见特征。但部分标注者习惯性只框“能看清的部分”比如只框雨衣上的反光条忽略被雨幕遮挡的躯干。这会导致模型学到错误先验“反光条 person”而非**“低对比度区域中的类人形状 person”**。验证方法随机抽50张验证集图片用yolo detect val生成预测结果肉眼比对GTGround Truth框与预测框。若发现模型总在反光条附近打框但GT框却覆盖全身则说明标注本身有偏差。修复动作用labelImg打开labels/val/下对应.txt检查person类别的框是否覆盖整个可推断人体区域即使像素模糊对vehicle框必须包含车体主轮廓不能只框车牌或车灯除非该车在浓雾中仅露车牌重新导出YOLO格式覆盖原文件。血泪经验我在某次项目中发现23%的person标注框高度不足实际身高的60%导致模型在雾中将蹲姿行人判为“非人”。重标后雾天person召回率从51%升至79%。3.2 同一场景的多张图必须保持曝光/白平衡一致否则模型会把“曝光差异”当成“类别差异”原始数据若来自不同设备如交警手持机 vs 路口固定摄像头、不同时间段清晨蓝调 vs 正午黄调会导致同一辆车在不同图中呈现截然不同的色温与亮度。YOLO模型会误将“偏蓝图像中的车”和“偏黄图像中的车”视为两类对象破坏特征空间一致性。验证方法用OpenCV批量读取images/train/下所有图计算每张图的HSV通道均值# save as check_exposure.py import cv2 import numpy as np import glob import os paths glob.glob(data/images/train/*.jpg) h_means, s_means, v_means [], [], [] for p in paths: img cv2.imread(p) hsv cv2.cvtColor(img, cv2.COLOR_BGR2HSV) h_means.append(hsv[:,:,0].mean()) s_means.append(hsv[:,:,1].mean()) v_means.append(hsv[:,:,2].mean()) print(fHue mean: {np.mean(h_means):.1f}±{np.std(h_means):.1f}) print(fSaturation mean: {np.mean(s_means):.1f}±{np.std(s_means):.1f}) print(fValue mean: {np.mean(v_means):.1f}±{np.std(v_means):.1f})若Hue mean标准差 15说明色温离散严重若Value mean标准差 30说明亮度差异过大。修复动作用cv2.createCLAHE()对所有图做自适应直方图均衡增强暗部细节抑制过曝或用skimage.exposure.match_histograms()将所有图匹配到第一张图的直方图。3.3 “vehicle”类别必须明确定义边界工程车、三轮车、自行车是否纳入原始数据中vehicle可能混入非标准道路车辆。例如清扫车带喷水装置→ 应归为vehicle人力三轮车无动力→ 建议单列tricycle否则与机动车混淆共享单车 → 若占比较低5%可归入person骑车人或剔除验证方法统计labels/train/下所有.txt文件中类别ID分布# Linux命令行快速统计 grep -o ^[0-9] data/labels/train/*.txt | sort | uniq -c | sort -nr若1vehicle占比异常高85%检查是否误标了路障、广告牌为vehicle若出现2或3等未定义ID说明标注工具导出错误需全局替换。避坑 / 常见问题 / 排查现象1训练loss下降快但验证mAP始终在0.1~0.2徘徊原因dataset.yaml中names顺序与.txt标签ID不一致或nc值错误解决用head -n 5 data/labels/train/001.txt查看首行确认ID为0或1核对dataset.yaml中nc和names现象2训练中途报CUDA out of memory即使batch4原因部分图片分辨率远超640x640如原始图3840x2160YOLO会将其长边缩放到640短边等比缩放导致内存暴涨解决用mogrify -resize 640x640 *.jpg批量压缩原始图符号确保只缩放超限图现象3验证时大量person被漏检但vehicle检测正常原因person标注框平均面积 1000像素约32x32而YOLOv8s默认最小检测尺度为640/3220px小目标丢失解决在训练命令中加--cfg models/yolov8s.yaml修改backbone后接的P3层输出通道或直接换用yolov8m.pt参数更多小目标更强现象4测试时同一辆车在连续帧中ID频繁跳变如ID1→ID5→ID1原因恶劣天气导致外观特征剧烈变化DeepSORT等跟踪器无法关联解决本阶段专注检测暂不启用跟踪若需跟踪后续用ByteTrack替代DeepSORT其对低置信度检测更鲁棒4. 恶劣天气专用评估不能只看mAP要拆解雨/雾/夜三类场景的召回率4.1 构建场景标签给每张测试图打上“weather_type”元信息Ultralytics默认评估只输出整体mAP但恶劣天气检测的核心诉求是模型在雨天是否比雾天更可靠夜间是否比黄昏更差因此必须为images/test/下的每张图添加场景标签。创建~/yolo_weather/data/test_weather.csvfilename,weather_type,light_condition 001.jpg,rain,day 002.jpg,fog,dawn 003.jpg,night,night ...weather_typerain/fog/night/snow若数据含雪light_conditionday/dawn/dusk/night文件名必须与images/test/下完全一致。逻辑说明这个CSV不参与训练仅用于后续评估脚本分组统计。它让你能回答“当前模型在rainday场景下person召回率是82%但在fogdawn下只有41%——说明雾中晨光是最大短板”。4.2 用自定义脚本跑分输出按天气类型切片的详细指标Ultralytics的yolo detect val不支持按元数据分组需自己写评估脚本。创建eval_by_weather.py# -*- coding: utf-8 -*- import pandas as pd import numpy as np from ultralytics.utils.metrics import ConfusionMatrix from pathlib import Path # 加载测试集天气标签 weather_df pd.read_csv(data/test_weather.csv) # 加载模型预测结果yolo detect val后生成的results.json pred_json runs/val/weather_v8s_finetune/results.json # 加载GT标注需先将YOLO格式转为COCO格式此处略去转换代码 # 核心逻辑遍历weather_df对每类weather_type分别计算 for wt in [rain, fog, night]: mask weather_df[weather_type] wt files_in_wt weather_df[mask][filename].tolist() # 提取这些文件的GT和Pred传入ConfusionMatrix cm ConfusionMatrix(nc2) for f in files_in_wt: gt_boxes load_gt(f) # 自定义函数读取labels/test/f.txt pred_boxes load_pred(f) # 自定义函数读取results.json中对应项 cm.process_batch(pred_boxes, gt_boxes) # 输出该天气下的metrics stats cm.tp.sum(0).to(torch.float32) # tp, fp, fn per class recall_person stats[0,0] / (stats[0,0] stats[0,2]) # tp/(tpfn) for person print(f{wt} - person recall: {recall_person:.3f})参数说明ConfusionMatrix是Ultralytics内置类process_batch接收预测框xyxy, conf, cls和GT框xyxy, cls自动累加TP/FP/FN。stats[0,0]是person类的TP数stats[0,2]是person类的FN数漏检。4.3 关键阈值调优针对恶劣天气置信度门限conf和NMS IOU需单独调整默认conf0.25在晴天有效但在雨雾中会产生大量低置信假阳性如把雨痕当行人。而iou0.7的NMS又过于激进导致密集雨滴中相邻车辆被合并。实测推荐组合基于1000张数据验证场景confiou适用原因雨天中雨0.350.55提升真阳性抑制雨滴干扰雾天中雾0.400.50雾中目标边缘模糊需更低IOU防合并夜间无补光0.300.60信噪比低适当放宽IOU保召回在推理时指定yolo detect predict \ modelruns/train/weather_v8s_finetune/weights/best.pt \ sourcedata/images/test \ conf0.35 \ iou0.55 \ save_txtTrue \ namepred_rain注意conf和iou必须在predict阶段指定val阶段不生效。save_txtTrue会生成runs/predict/pred_rain/labels/下的预测框供你手动校验。5. 部署前必做的3项压力测试小目标、运动模糊、跨设备泛化5.1 小目标专项测试裁剪原图中person区域缩放到32x32像素检验模型能否识别恶劣天气下远距离行人常仅占图像0.1%面积。YOLOv8s理论最小检测尺度为20px但实际受特征金字塔限制32x32以下几乎不可靠。我们构造极端测试集# generate_small_person.py import cv2 import numpy as np from pathlib import Path # 从val集中随机选50张含person的图 val_imgs list(Path(data/images/val).glob(*.jpg)) person_imgs [] for img_p in val_imgs: label_p Path(data/labels/val) / f{img_p.stem}.txt if label_p.exists(): with open(label_p) as f: lines f.readlines() if any(0 in l for l in lines): # 0 is person person_imgs.append(img_p) if len(person_imgs) 50: break # 对每张图提取person框裁剪并缩放到32x32 for i, img_p in enumerate(person_imgs): img cv2.imread(str(img_p)) label_p Path(data/labels/val) / f{img_p.stem}.txt with open(label_p) as f: for line in f: if line.startswith(0 ): # person _, cx, cy, w, h map(float, line.split()) h, w int(h*img.shape[0]), int(w*img.shape[1]) x1 int((cx - w/2) * img.shape[1]) y1 int((cy - h/2) * img.shape[0]) crop img[y1:y1h, x1:x1w] if crop.size 0: continue small cv2.resize(crop, (32,32)) cv2.imwrite(fdata/small_test/{img_p.stem}_{i}_small.jpg, small)运行后得到50张32x32的person小图。用训练好的模型预测yolo detect predict modelruns/train/weather_v8s_finetune/weights/best.pt sourcedata/small_test conf0.2若检测出person的图片 20张即召回率40%说明小目标能力不足需在训练时加--augment启用Mosaic增强强制模型学习小目标或改用yolov8m.pt其P2层256x256比v8s的P3层128x128更适合小目标。5.2 运动模糊鲁棒性测试用OpenCV模拟车速40km/h下的线性模糊观察检测框偏移量雨天行车时车辆自身运动雨刷运动造成复合模糊。我们用cv2.filter2D模拟# apply_motion_blur.py import cv2 import numpy as np def motion_blur(image, degree12, angle45): M cv2.getRotationMatrix2D((degree / 2, degree / 2), angle, 1) motion_blur_kernel np.diag(np.ones(degree)) motion_blur_kernel cv2.warpAffine(motion_blur_kernel, M, (degree, degree)) motion_blur_kernel motion_blur_kernel / degree blurred cv2.filter2D(image, -1, motion_blur_kernel) return blurred # 对test集中所有vehicle图加模糊 for img_p in Path(data/images/test).glob(*vehicle*.jpg): img cv2.imread(str(img_p)) blurred motion_blur(img, degree8, angle30) # 模拟30°方向8px模糊 cv2.imwrite(fdata/blurred_test/{img_p.name}, blurred)用模型预测blurred_test/统计预测框中心点与原图GT框中心点的欧氏距离单位像素模糊程度平均偏移像素是否可接受无模糊5.2✅8px模糊18.7⚠️ 需优化12px模糊32.1❌ 必须改进改进方案在训练数据中加入20%的运动模糊增强用Albumentations库的MotionBlur比单纯调参更治本。5.3 跨设备泛化测试用手机拍摄同一场景检验模型是否依赖特定传感器噪声真实部署时模型可能运行在海康IPC、大华球机、甚至手机App上。不同设备的ISP图像信号处理流程差异巨大海康IPC强降噪锐化保留边缘但抹平雨纹iPhone计算摄影动态范围高但引入伪影安卓中端机色彩偏暖暗部噪点多。测试方法用iPhone在雨天拍摄10张与原始数据同场景的图如十字路口用安卓手机如Redmi Note 12拍10张用海康DS-2CD3T47G2-L倒置摄像机拍10张统一保存为data/cross_device/iphone/等子目录运行预测yolo detect predict modelbest.pt sourcedata/cross_device/iphone conf0.35若iPhone图person召回率85%安卓图仅52%说明模型过拟合了iPhone的ISP特征解决在训练数据中加入各品牌设备的样例图哪怕只有50张或用ColorJitter增强模拟不同色彩风格。6. 我的3个落地习惯从数据质检到上线监控的闭环6.1 每次训练前必跑check_dataset.py5行代码筛出90%的数据问题我绝不信任任何“已标注”数据包。在~/yolo_weather/下新建check_dataset.pyfrom ultralytics.data.utils import check_det_dataset check_det_dataset(data/dataset.yaml, verboseTrue)运行它你会立刻看到Found 700 train images确认数量All labels have class IDs in [0, 1]确认类别合法All labels have valid coordinates确认框未越界WARNING: 3 labels with negative coordinates揪出3个坏标注教训去年一个项目因跳过这步训练到80轮才发现12%的标签框坐标为负值全部重标。现在我把这行命令写进Makefilemake train前自动执行。6.2 验证集必须包含“最难样本”我用3个维度人工筛选自动划分的val集常漏掉极端案例。我坚持人工构建验证集维度1天气强度——从原始数据中挑出雨滴密度最高、雾浓度最大、照度最低的各10张维度2目标状态——蹲姿行人、侧翻车辆、被遮挡70%的自行车维度3设备来源——确保海康、大华、手机各占1/3防设备偏置。最终val集100张虽只占总量10%但决定了模型能否上线。它的mAP必须≥0.65否则不进下一环节。6.3 上线后必埋点记录每帧的inference_time、confidence_mean、box_count画趋势图模型部署后我让服务端每秒上报3个指标到InfluxDBinference_time_msGPU推理耗时毫秒突增说明显存泄漏confidence_mean本帧所有检测框置信度均值持续低于0.35说明环境恶化如突发暴雨box_count本帧检测到的目标总数骤降50%以上触发告警可能是镜头被泥水覆盖。用Grafana画三线图设置阈值告警。上周就靠confidence_mean连续5分钟0.28提前2小时通知运维清洗路口摄像头。希望帮到你。本文还有配套的精品资源点击获取
返回列表