拓冰建站拓冰建站
首页 / 资讯中心 / 正文

恶劣天气下的YOLO目标检测:1000张数据微调与部署实战

简介恶劣天气道路场景是自动驾驶与安防监控中的难点这套图像目标检测数据专门面向此类场景。数据包含约1000张真实拍摄的雨雾、雪暴、沙尘等天气下的道路图片已采用YOLO格式完成标注覆盖car、bus、person、truck等7个常见类别适合用于行人车辆检测模型的训练与算法评估。资源共2000个文件以jpg图像和对应的txt标注文件为主另附1个py可视化脚本能帮助快速查看标注效果整体体积约133.76MB并已完成训练集与测试集划分可直接接入YOLOv5等主流框架。目前已有155人学习下载。对于正在改进YOLO系列模型或研究恶劣天气鲁棒检测的读者这份数据既能作为训练语料也能用于验证数据增强与域适应方法的有效性是一份实用且易上手的数据资源。1. 为什么说1000张恶劣天气数据才是YOLO目标检测最该补的场景晴天的行人车辆检测现在随便一个开源数据集拉出来都能把mAP刷到0.9以上。但真把YOLO部署到雨夜的路口、起雾的高速、雪天的小区入口模型的召回率会摔得很难看。这不是网络结构的问题是训练分布和推理分布不一致的问题。模型没见过雨滴拖影、雾天低对比度、夜间反光里的行人它就只能靠猜测。标题里这份“恶劣天气下道路行人车辆、约1000张、YOLO标注格式”的数据集恰好就是用来补这一块的。量不大但针对性极强适合做二轮微调、域适应验证和边缘设备部署前的鲁棒性测试。对做智慧交通、辅助驾驶感知、安防监控的工程师来说这才是YOLO训练的完整闭环里真正缺的一环。别指望1000张能训练出一个通用大模型它的正确用法是让已经在晴天数据上收敛的模型在恶劣天气下别崩得太快。2. 先摸清数据家底KITTI标注转YOLO格式前要做的三件事拿到这批标注第一件事不是急着开训练而是先做数据体检。1000张这个名字很笼统你得搞清楚它内部是怎么分布的是雨天占600张、雾天200张、雪天100张、夜间100张还是全部挤在一种天气里。分布直接决定微调策略如果只有雨天那模型对雾天的提升就近似为零。2.1 把可视化脚本跑起来看图对不对得上标注YOLO标注格式是class x_center y_center width height全部归一化到0到1之间且坐标是相对图片宽高的比例值。拿到数据集后我一般先写个小脚本把标注框画回到原图上排查两类错误标注框和真实目标错位、类别ID和实际物体不符。这个步骤花不了十分钟但能省下后面调试时几小时的糊涂账。import cv2 # 读取图片和同名 txt 标注 img_path images/rain_001.jpg label_path labels/rain_001.txt img cv2.imread(img_path) h, w img.shape[:2] with open(label_path, r) as f: lines f.readlines() # YOLO 格式class, x_center, y_center, width, height均归一化 for line in lines: parts line.strip().split() cls int(parts[0]) x_c, y_c, bw, bh map(float, parts[1:]) # 反算左上角和右下角像素坐标 x1 int((x_c - bw / 2) * w) y1 int((y_c - bh / 2) * h) x2 int((x_c bw / 2) * w) y2 int((y_c bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, str(cls), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 1) cv2.imwrite(check_rain_001.jpg, img)这段代码把归一化坐标换算回像素绝对值直接画出每个框。如果发现大量框里根本没有行人或车辆说明数据集质量存疑。检查的重点是雨夜样本夜间框普遍偏小很多标注员会漏标远处的小目标这一条直接关系到后续小目标检测的召回率。另外注意类别ID有没有从0开始连续编号YOLO不认跳号的类别。2.2 用脚本统计样本的清晰度分布决定要不要做图像去模糊预处理恶劣天气图像的一大特征是局部模糊尤其是雨雪造成的动态模糊。简单办法是用拉普拉斯算子的方差来评估每个样本的清晰程度输出一张分布表把最模糊的几十张挑出来人工看一眼确认是本来就是运动模糊还是标注图片被压缩过。这个指标同时决定了训练时要不要开更重的数据增强以及推理阶段要不要加去雨去雾前置网络。import cv2 import numpy as np import os for fname in sorted(os.listdir(images)): path os.path.join(images, fname) img cv2.imread(path, cv2.IMREAD_GRAYSCALE) # 拉普拉斯方差越小图像越模糊 lap_var cv2.Laplacian(img, cv2.CV_64F).var() print(f{fname}: {lap_var:.2f})一般阈值经验值是这样清晰白天图方差在500以上雨天在200到500之间雾天可能低到100夜间加雨可能不足50。假设这个数据集整体偏低方案就分两种如果只是个别图模糊直接保留并配合多尺度训练如果整体方差都低那训练前就得考虑接一个轻量的去雾网络做前置处理。这里不建议把模糊图全部删掉因为推理阶段遇到的真实场景也是模糊的保留有利于模型适应同样的退化分布。2.3 数据划分的比例要预留验证集不能只分训练和测试1000张的体量很尴尬。如果按传统的8:1:1划分验证集只有100张雨夜这类困难样本可能只分到十几张验证指标的波动会非常大。更稳妥的划分方式是按天气场景分层采样先按场景把数据分组再在每个组内按7:2:1划分保证每种天气在三个集合里都有代表。划分时还要考虑一个细节同一段视频里连续帧往往被一起打包进数据集如果训练集里有第100帧、验证集里有第105帧两张图只有0.2秒间隔这属于泄漏会虚高验证指标。正确做法是先按视频片段ID或场景ID去重再做组内划分。命令行里用脚本按文件名前缀分组即可比如rain_001、rain_002属于同一场景就把它们绑在一起划分而不是逐张随机分。划分集合占比数量约用途train70%700模型权重更新val20%200训练过程监控与早停test10%100最终效果评估不参与任何调参3. 用YOLO v8在自建天气数据集上从零跑通训练流程数据检查完毕下面讲训练。标题给的是YOLO标注格式所以不存在格式转换问题可以直接被YOLO系列仓库读取。选型上v8是目前平衡速度与精度的默认选择v5在旧硬件上的兼容性更好v11适合想压榨精度的场景。这里以YOLO v8为例讲完整命令链路。3.1 环境配置和数据集目录结构组织yolo的安装不建议用源码编译直接用pip安装官方包即可CUDA环境独立配置。常见做法是单独建一个conda环境把torch的CUDA版本和ultralytics的版本对齐避免出现装完包之后检测不到GPU的情况。conda create -n yolo python3.10 -y conda activate yolo pip install ultralytics torch torchvision --index-url https://download.pytorch.org/whl/cu121目录结构从根目录算起一级一级建好images/train、images/val、labels/train、labels/val这四个目录是必须的每个子目录里放对应的图片和txt文件。然后新建一个weather.yaml内容如下path: /data/weather_set train: images/train val: images/val test: images/test nc: 2 names: [pedestrian, vehicle]这里的path要写绝对路径nc和names的顺序必须跟txt标注里的类别ID一一对应。如果这个数据集的默认类别是COCO的80类而它只标注了行人车辆那就要单独建一个只有2类的yaml不能直接用coco.yaml。3.2 训练命令的7个关键参数从预训练权重到mosaic关闭策略训练命令本身不长参数才是决定效果的关键。完整命令如下yolo detect train \ data/data/weather_set/weather.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.001 \ mosaic0.5 \ close_mosaic10 \ patience15 \ device0逐项说明参数含义modelyolov8n.pt表示加载COCO预训练权重而不是从头训练这是1000张小数据集能收敛的前提从头训练的话这类数据量撑不起深层网络的权重更新。epochs100对于1000张图是够用的再多容易过拟合。mosaic0.5表示有50%概率使用马赛克增强这个参数在恶劣天气数据上要慎重雨滴和雾的纹理在拼接后会产生大量伪框干扰模型学习所以我一般会调低到0.5甚至0.3。close_mosaic10是最后一个epoch关闭马赛克增强具体数值是epoch数最后一轮让模型在真实分布上微调收敛这个和yolo训练数据标记的质量高度相关标记不准的数据在马赛克增强下会被严重放大噪声。patience15是连续15个epoch验证集指标不升就早停1000张数据一般不愁训练时间但早停能防过拟合。训练完成后能用的产物是runs/detect/train/weights/best.pt和last.pt。best.pt是验证集mAP最高的权重last.pt是最后一个epoch的权重。在恶劣天气这样的小数据集上两者常常差好几个点一律用best.pt。3.3 训练过程如何判断收敛loss曲线与PR曲线的读法训练结束不要急着收工先看runs/detect/train/results.csv里的曲线。核心指标是train/box_loss和val/box_loss这两个值在训练结束时应该呈收敛趋势如果val的box_loss在第30个epoch后反弹这是过拟合信号。这是因为恶劣天气图像的背景纹理复杂模型很容易把雨滴条纹当作特征去拟合训练损失还在降验证损失已经翘头此时就该停止并回调到验证损失最低的epoch权重。另一个判断点在confusion_matrix.png上。拿雨夜样本来说行人被预测成车辆的混淆很常见因为夜间行人衣着颜色和车辆尾部轮廓在低照度下存在相似纹理。如果混淆矩阵里“行人→车辆”的比例超过百分之十五说明模型并没有真正学到行人的形态而是学到了夜间高亮物体的共同特征。这时光调训练参数已经没用回退到2.1节重新检查标注是否有把远处行人标成车辆的错框通常会有收获。4. 恶劣天气下的yolo检测策略图像预处理与数据增强怎么配合才不白做同样的1000张数据预处理策略不同训练出来的模型能力差一大截。这一章专门讲恶劣天气场景下yolo训练前的图像处理方案。4.1 雨雾噪声的输入端处理去雨算法要放在pipline的哪一层很多人习惯把去雨去雾模型放进推理管线这种做法有它的道理但也容易踩坑。以去雾为例常用的暗通道先验算法对雾天图像有效但对夜间图像会严重偏色因为夜间低照度区域的暗通道假设不成立。所以我的建议是图像预处理放在训练集增强阶段而不是推理阶段的固定前置。训练时给模型同时喂“原始雨天图”和“轻度去雨图”让模型自己学两种域的特征推理时就不需要额外背一个去雨网络。# 训练前置增强按概率对输入图做去雨模拟 import random import cv2 def degrade_rainy(img, strength0.3): # 模拟雨线生成方向性噪声叠加到原图 h, w img.shape[:2] rain np.random.normal(0, 0.05, (h, w, 1)).astype(np.float32) rain cv2.blur(rain, (1, 3)) angle random.uniform(-10, 10) m cv2.getRotationMatrix2D((w//2, h//2), angle, 1) rain cv2.warpAffine(rain, m, (w, h)) # 叠加并归一化 out img.astype(np.float32) * (1 - strength) rain * strength * 255 return np.clip(out, 0, 255).astype(np.uint8)这段代码模拟的是雨线的方向和模糊特征随机旋转角度是为了防止模型学到固定角度的雨纹。关键在于这个增强要有一定的随机概率触发一般设在0.3到0.5之间如果每张图都加雨模型会把所有输入都当成雨天图反而丢失了原本的域信息。yolo数据集的增强本身包含hsv、翻转等操作叠加自定义增强时需要放在mosaic之前执行否则雨纹会被马赛克的边界截断形成虚假的矩形纹理。4.2 弱光增强与检测置信度gamma校正不能乱加夜间图像的对比度极低直接训练的话模型对行人的特征提取会非常困难。常见的做法是训练时不提升亮度而是做随机gamma扰动让模型见多识广。但这里有个具体问题gamma值选多少合适如果设得太低比如0.3图像过亮会磨平夜间车灯的高光信息YOLO在检测车灯时反而会丢失一个非常强的视觉锚点。经验值范围是gamma在0.7到1.2之间均匀随机采样只对训练集做验证集保持原始图像。另外一定不要直接在推理管线里加固定的gamma校正因为真实场景的夜间图像亮度分布极不均匀路灯下亮、树荫下暗是常态全局gamma只会让暗区更暗。要加就加局部自适应直方图均衡化可以用CLAHE但它的计算量偏大边缘设备上是否启用取决于部署的算力余量。4.3 yolo损失函数在困难样本上的行为从置信度下降判断数据集边界训练一轮之后把验证集里所有预测框的置信度统计出来你会看到两座山峰一堆框在0.8以上一堆框在0.3以下中间区域几乎没人。这说明模型对困难样本要么认得准、要么完全没把握很少模糊过渡。落在0.3以下的那些框往往对应着雨夜里远处的小目标它们的真实宽高可能只有二三十个像素。yolo损失函数中负责小目标的head分支在这个尺度上能提取的特征极其有限所以提升方案不是调损失权重而是把输入分辨率从640提升到960或1280。yolo detect train \ data/data/weather_set/weather.yaml \ modelyolov8n.pt \ imgsz960 \ batch8 \ rectTrue \ epochs100imgsz960对小目标检测有质的提升但batch需要降到8以避免显存溢出。rectTrue会按图片宽高比分组做矩形训练减少黑边填充带来的计算浪费对1024分辨率的输入尤其有效。修改之后重新训练重点观察验证集上0.3到0.5置信度区间的框有没有向左边的低置信度区间迁移这个迁移方向决定了模型是从“猜”变成了“拒绝”。5. 在rk3588边缘设备上部署yolo模型雨天夜间场景的实测要点训练结束后模型最终要跑在真实设备上。以RK3588这类边缘设备为例yolo模型的部署链路是.pt转.onnx再转.rknn中间要经过量化校准。这里讲三个最容易出问题的环节。5.1 导出的预处理参数必须感知原图尺寸RK3588的NPU对输入尺寸有对齐要求通常需要32的倍数。很多转模型的脚本会直接把输入固定成640×640这个操作对恶劣天气场景是有伤害的雨天中的车辆往往出现在画面的中远处比晴天场景更小固定到640之后能保留的有效像素更少。如果你在4.3节用了imgsz960训练导出时也要保持同样的分辨率不要降回来。from ultralytics import YOLO # 加载训练好的模型导出 ONNX注意 opset 版本 model YOLO(runs/detect/train/weights/best.pt) model.export(formatonnx, imgsz960, opset12)opset12是rknn-toolkit2支持的版本上限高于这个版本会导致后续转换报错。imgsz960要与训练时一致否则输入分布一变量化误差会显著放大。5.2 用真实恶劣天气的检验视频确认推理时延的稳定性转完rknn模型之后拿一段真实雨天夜间视频跑一次需要确认的是帧率和置信度的关系。有的工程师为了跑到30FPS把检测阈值从0.25调到0.5结果雨天低对比度行人的置信度普遍在0.3到0.45之间调高阈值等于直接把行人全部过滤掉。正确的做法是保持0.25阈值不动把nms的iou阈值从0.5调到0.4减少重叠框的输出数量从而降低后处理耗时而不是粗暴地抬置信度阈值。checklist供现场参考雨天夜间行人的平均置信度是否低于0.4低于则考虑降分辨率重训练或换更大模型同一行人连续10帧的检测框位置是否抖动超过自身宽度的30%抖动明显要检查NMS和锚框匹配rknn量化后mAP相对浮点模型的掉点是否超过3%超过就改用hybrid quantization混合量化策略只量化部分层。5.3 恶劣天气数据的增量更新标注格式和质量决定后续扩展成本部署不是终点。后续模型要持续更新新的雨雪天气数据进来后按2.1小节的检查流程再走一遍然后把新旧数据合并按7:2:1重新划分重新训练替换掉旧权重。1000张数据做第一版足够验证但真正要把雨天防事故做到可用建议后续按每周收集数百张困难样本的频率做增量这些样本的标注质量比数量更关键。一张标注模糊的雨夜图比十张晴天的准框图对模型的负面影响更大。本文还有配套的精品资源点击获取
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门