资讯详情

资讯详情

图像去雨实战指南:Derain模型设计、训练与部署全解析

简介Derain是一份基于Python实现的图像去雨项目资源包面向图像处理与计算机视觉方向的学习者和开发者重点解决恶劣天气下拍摄图像因雨滴干扰而清晰度下降的问题。项目围绕雨滴去除任务涵盖预处理、特征提取、雨滴建模与背景恢复等完整流程可帮助读者理解传统图像处理与深度学习方法相结合的去雨方案。资源包共包含4个文件大小约3.72MB其中2份PDF论文ICONIP论文及ECCV 2010 Guided Filter相关文献提供算法理论支撑1个main.py主脚本展示工程实现1个readme说明文档辅助环境配置与代码阅读便于对照论文原理逐步复现实验。当前已有199人学习下载。通过项目包读者既能获得去雨算法的理论参考也能直接查看Python代码实现了解如何利用CNN等模型识别并分割雨滴、重建清晰背景适合作为课程设计、毕业设计或算法入门阶段的参考资料。 很多人第一次看到 Derain 这个词第一反应是野兽派画家安德烈·德朗。我去年启动这个项目时干脆就把项目代号定成“Derain”一方面致敬那个用色张扬的画家另一方面它和计算机视觉里的 deraining图像去雨完美同源。这个项目的目标很直接在单张雨图上把雨纹去掉把背景恢复干净让下游的目标检测、语义分割算法不再被雨线干扰。做这个项目之前我低估了去雨这个方向的复杂度。雨纹这东西看似简单实际是低层视觉里极其刁钻的任务它有长条结构、有方向性、和背景高频纹理极易混淆而且真实场景里几乎没有干净的 GT 可以监督。这篇博文里我会把 Derain 从动机、模型选型、数据配置到踩坑记录完整拆开适合正在做图像复原、低层视觉或者准备把去雨算法部署到监控/车载场景的开发者参考。1. 为什么给项目起名“Derain”先搞清楚要解决的是哪一种雨1.1 雨不是同一种东西雨滴、雨纹和雨雾很多人一想到去雨就以为“模型能处理一切雨天图像”。但真实画面里的雨大体能分成三类稀疏雨滴贴近镜头的大颗水滴对背景遮挡严重形状变形明显一般需要目标检测配合局部修复不适合用全局去雨模型硬扛密集雨纹空间分布不均匀、细长条、方向受风影响的雨线这是大多数去雨论文研究的对象全局雨雾大气散射引起的对比度下降、画面发白本质上更接近去雾问题。Derain 项目的主要目标是第二类密集雨纹顺带缓解第三类雨雾带来的对比度损失。之所以一开始就做任务边界划分是因为我见过太多人拿一个去雨模型跑全景雨图结果雨滴区域被磨成光斑背景还糊成一片。如果任务边界不清晰模型不在能力范围内时很难体面失败。1.2 为什么不能直接拿去噪或去模糊模型顶上雨纹和普通噪声、运动模糊都不是一回事。去噪模型通常假设噪声是独立同分布的但雨纹是长条状、方向一致、亮度高于背景普通去噪会把雨纹当作边缘结构保留下来。去模糊模型假设退化是全局卷积但雨纹在不同位置的形态差异很大全局假设根本立不住。所以项目必须单独设计。Derain 的定位是端到端监督学习输入带雨图输出干净背景。表面上就是个 image-to-image 的任务但真正决定效果上限的是对雨纹结构的建模方式和训练数据分布。这两个问题没想清楚网络再漂亮也只是在拟合合成数据的噪声。1.3 传统滤波方案为什么不考虑早期我也试过导向滤波、低秩稀疏分解这类方案。在简单雨图上确实能去掉一部分雨纹但参数敏感换个场景就要重新调雨纹比较密集时背景细节会被严重连带抹掉。深度学习方案至少在特征表达上有足够的容量去区分雨纹和背景纹理所以 Derain 从立项起就选了神经网络路线。现在回头看这个决策没有任何问题。2. 从雨纹合成模型到网络结构Derain 的骨架搭建2.1 合成模型 R B S 与它背后的盲区绝大多数去雨数据集都基于一个经典假设R B SR 是带雨图B 是干净背景S 是雨层。合成数据就是靠这个公式把雨纹贴到干净图上生成。但实际场景里S 不只有雨纹还有雨滴散焦、镜面反射、雨丝切割背景带来的遮挡信息。简单相加模型天然丢失了“雨纹遮挡背景”这一层信息导致模型在真实图上容易把遮挡区域处理成模糊残留。应对方式是在网络里不直接回归背景 B而是回归雨层 S再用输入 R 减去 S 得到背景。这样做的好处是网络只需要专注学习“雨纹残差”背景的大块结构信息可以靠输入直接保留视觉上稳定得多。2.2 为什么没有沿用纯 CNN 结构最初我跑的是类似残差 U-Net 的 CNN 结构。U-Net 在小尺寸 patch 上表现不错验证集 PSNR 也很好看但一上真实场景就露馅长雨纹的尾部区域总有锯齿而且背景纹理被过度平滑。原因不难理解。CNN 靠局部感受野提取特征雨纹细长且横跨大范围局部卷积很难把一整条雨纹的上下文关系串起来。我在最低分辨率层换成了几层 Transformer block用全局注意力建模长距离依赖效果立刻稳定下来。窗口尺寸设得比常规小一点因为雨纹虽然是全局结构但注意力不需要覆盖整张图反而在局部窗口内做相对位置编码更高效。最终结构是 encoder 三层下采样、channel 从 64 到 256最低分辨率层放 6 层 Transformer blockdecoder 对称上采样带 skip connection激活函数用 GELU。这里贴一段简化版的核心网络骨架帮助理解整体拼装逻辑class DerainModel(nn.Module): def __init__(self, in_ch3, out_ch3): super().__init__() self.enc1 BasicConv(in_ch, 64, stride1) self.enc2 BasicConv(64, 128, stride2) self.enc3 BasicConv(128, 256, stride2) self.transformer nn.Sequential(*[ TransformerBlock(dim256, num_heads8) for _ in range(6) ]) self.dec3 BasicConv(256, 128, stride1) self.dec2 BasicConv(128, 64, stride1) self.dec1 BasicConv(64, out_ch, stride1, actNone) def forward(self, rain): x1 self.enc1(rain) # 64 x2 self.enc2(x1) # 128 x3 self.enc3(x2) # 256 x3 self.transformer(x3) out self.dec3(x3) out self.dec2(out x2) out self.dec1(out x1) rain_layer self.final_conv(out) # 还原到输入分辨率 return rain - rain_layer注意最后一层不是直接输出背景而是输出雨层残差。这个改动对真实场景的泛化帮助很大。3. 可复现的完整链路数据、训练和评估指标怎么选3.1 数据集的偏置问题比想象中严重我用过的数据集主要有这几类数据集特点适合场景Rain100H / Rain100L合成雨纹雨量差异大基线验证、快速迭代DID-MDN多类雨纹、雨滴、雨雾混合提升模型泛化能力SPA-Data真实雨图配对齐次背景标注成本高真实场景微调验证训练时我把 Rain100H 和 DID-MDN 混合每个 epoch 随机采样保证雨纹类型不单一。SPA-Data 不参与训练只作为验证集用来观察模型在真实雨图上的表现。如果只盯着 Rain100L 评估指标会很漂亮但真实场景很容易翻车因为 Rain100L 背景偏平坦、雨纹稀疏模型无法学到复杂纹理下的区分能力。3.2 训练配置照着抄就行环境是 PyTorch 2.0、单卡 A100 或 3090 都行。输入 patch 我取 256×256batch size 8AdamW 优化器初始学习率 2e-4warmup 前 5 个 epoch 线性上升之后 cosine 退火到 5e-6。为了省显存和提高吞吐用 FP16 混合精度训练大概跑 60 到 80 个 epoch 就能看到稳定收敛。数据增强是重头戏。我用的组合是随机水平翻转、随机 90 度旋转、随机亮度扰动、随机加高斯噪声。一个容易被忽视的点是亮度扰动不能太大否则模型会把亮度变化误学成雨层测试时出现颜色漂移。我后来把饱和度和色相扰动直接砍掉只保留亮度项颜色偏移问题才消停。3.3 评估指标不能只看 PSNR去雨领域经典评估指标是 PSNR 和 SSIM但现在越来越多人意识到这两个指标有盲区。PSNR 本质是像素级误差指标网络输出稍微平滑一点误差反而小所以 PSNR 会偏好“糊”的结果。SSIM 对结构敏感一些但对纹理细节仍不够。我的评估组合是 PSNR、SSIM、LPIPS 三件套外加人工目检。LPIPS 用预训练 VGG 网络提取特征计算感知距离能反映人眼观感上的差异。目检时重点看屋檐、树叶、玻璃镜面、栅栏这类高频纹理区域因为这些地方最容易暴露模型“把背景当雨纹磨掉”的问题。4. 踩坑记录合成模型在真实雨天的三次惨案4.1 第一次翻车验证集 PSNR 34.5真实雨图像蒙了层白纱项目中期模型在 SPA-Data 验证集上 PSNR 到了 34.5 dB我信心满满地拿了一段真实监控雨天视频去测试结果画面像蒙了层白纱虽然雨纹没了但背景对比度也塌了整个图发灰发平。排查链条是这样的先怀疑测试代码有 bug检查归一化参数、通道顺序、resize 逻辑全部没问题再怀疑分辨率导致发现真实视频是 1920×1080模型输入是 256直接 resize 导致雨纹变粗、边缘形态和训练分布不一致最后定位到域差异合成雨纹边缘锐利、对比高真实雨纹经过镜头模糊后边缘柔和模型学习的锐利滤波器反而把真实雨纹周围的背景也抹掉了。解决方法是给合成雨纹加“真实化”处理对雨纹层做随机运动模糊、随机长度和方向扰动、叠加局部亮度波动。这样生成的数据在频域上和真实雨纹更接近模型泛化能力立刻提升了一截。4.2 第二次翻车雨纹去掉了树叶和栅栏也没了这个问题比第一次更隐蔽。模型学会了去雨也学会了把背景里的高频纹理当雨纹处理。尤其树叶边缘、金属栅栏这类方向和雨纹接近的结构输出结果里直接被平滑掉。我一开始以为是网络容量不够试了更大模型PSNR 几乎没有变化才意识到这不是容量问题是约束方向问题。我加了一个梯度一致性损失在非雨区域的梯度上约束输出和输入保持一致雨纹区域的梯度则强制它趋近于消失。实际操作中需要先做一个雨区 mask简单一点的做法是用输入雨图和输出背景的差分图做阈值分割锁定雨纹位置。这样模型可以把“去雨”和“保留背景纹理”两个目标分头优化树叶和栅栏的保留效果明显好转。4.3 第三次翻车训练 loss 收敛验证集却出现颜色偏移某次实验在训练集上 loss 很好看但验证集输出明显偏绿。第一反应是数据增强里的色相抖动开太大了但关闭之后问题还在。后来逐层排查才发现是某次归一化参数没有统一训练时用的图像均值是 [0.485, 0.456, 0.406]验证时误用了另一套 ImageNet 均值通道分布错位导致颜色偏移。这个坑现在回看很蠢但它提醒我图像复原任务里归一化参数的统一是评估有效性的第一前提。任何颜色层面的指标异常先检查输入预处理再检查模型本身。5. Loss 组合、模型蒸馏和部署前处理的完整经验5.1 Loss 组合不是越复杂越好我最终采用的 Loss 组合是三项L L1 0.2 * L_ssim 0.1 * L_perceptualL1 损失相比 L2 对边缘更友好背景细节不容易被整体平均掉SSIM 损失从结构层面约束输出避免出现块状伪影感知损失用 VGG16 的 relu1_2 和 relu2_2 层特征做约束让输出在感知特征空间更接近真实背景。也试过加 GAN 判别器当时效果确实更锐利但训练不稳定调了很久依然偶发颜色抖动。对工程落地来说稳定优先GAN 最终没有进入正式版本。我个人的体会是先调好 L1 SSIM再逐步加感知损失效果曲线相对可控不建议一开始就上大杂烩。5.2 模型轻量化蒸馏比剪枝更省心部署阶段资源有限原始模型在 Jetson Orin 上跑一次前向要 60ms显然不够实时。我先试了结构化剪枝但去掉某些 channel 后雨纹尾部容易出现断裂调了很多次恢复精度都不理想。后来改用蒸馏方案大模型做 teacher训练一个小参数模型学习 teacher 的中间特征图小模型精度只下降 0.3 dB 左右但推理时间降到 18ms这个性价比完全可以接受。再配合 INT8 PTQ 量化FP16 降到 INT8 后 PSNR 仅损失 0.15 dB。对低层视觉任务来说量化敏感度通常没有分类那样高可以放心做。5.3 部署前处理不是所有区域都需要去雨真实监控场景里雨往往只出现在画面局部天空区域和近景区域可能根本无雨。如果整帧都送入去雨模型既浪费算力又可能对无雨区域的边缘造成不必要扰动。我后来加了一个轻量的雨区检测模块把画面切成分块只对有雨分块做去雨再拼回原图。这个改动让整体帧率提升了接近一倍而且无雨区域的画面完全是原图人工查看也不会觉得被处理过。如果你打算把去雨模型接到目标检测或语义分割前面建议前处理模块和后处理模块分开评估去雨本身的效果、以及下游任务指标是否提升要分别记录。很多时候去雨算法主观效果很好但下游检测的 AP 反而下降这说明模型把雨纹信息丢过头了下游算法依赖的那些边缘结构也被抹掉了。如果让我重新做一次 Derain我第一个要改的不会是网络结构而是数据的真实化程度。模型结构再强也补不了合成数据和真实雨天之间的巨大鸿沟。先把雨纹合成管线里的运动模糊、方向分布、局部亮度波动调到位模型的泛化能力才能立得住。一个小技巧训练时每隔几个 epoch 用同一段真实雨天视频做定性评测哪怕它没有 GT也能从视觉效果上快速发现“数据分布漂移”的苗头别等全套训练跑完才去验证。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →