news 2026/9/9 13:15:30

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
图像去雨实战指南: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 + S

R 是带雨图,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 block,decoder 对称上采样,带 skip connection,激活函数用 GELU。

这里贴一段简化版的核心网络骨架,帮助理解整体拼装逻辑:

class DerainModel(nn.Module): def __init__(self, in_ch=3, out_ch=3): super().__init__() self.enc1 = BasicConv(in_ch, 64, stride=1) self.enc2 = BasicConv(64, 128, stride=2) self.enc3 = BasicConv(128, 256, stride=2) self.transformer = nn.Sequential(*[ TransformerBlock(dim=256, num_heads=8) for _ in range(6) ]) self.dec3 = BasicConv(256, 128, stride=1) self.dec2 = BasicConv(128, 64, stride=1) self.dec1 = BasicConv(64, out_ch, stride=1, act=None) 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×256,batch size 8,AdamW 优化器,初始学习率 2e-4,warmup 前 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_perceptual
  • L1 损失:相比 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,也能从视觉效果上快速发现“数据分布漂移”的苗头,别等全套训练跑完才去验证。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/9 13:13:42

Hy4预览版50小时实测:游戏合集、性能表现与免费体验全解析

1. 这个Hy4预览版到底是什么1.1 一句话说清核心定位先说结论:Hy4是眼下讨论度挺高的一个游戏平台预览版本,官方这次不仅把内核开放给玩家提前体验,还顺手整理了一批游戏合集放进来,算是给所有观望的人一个“先尝后买”的机会。和那…

作者头像 李华
网站建设 2026/9/9 13:13:17

不用装插件打开 SWF 文件:Ruffle Flash Player 模拟器上手指南

不用装插件打开 SWF 文件:Ruffle Flash Player 模拟器上手指南 【免费下载链接】ruffle A Flash Player emulator written in Rust 项目地址: https://gitcode.com/GitHub_Trending/ru/ruffle 双击 .swf 文件,提示"未找到打开方式"。下…

作者头像 李华
网站建设 2026/9/9 13:12:41

QSPI接口NAND Flash驱动移植实战:从选型到性能调优

简介:面向STM32F446嵌入式开发者的QSPI NAND闪存驱动实例,基于四线SPI接口实现与多种SPI NAND器件的通信,实测可完成读、写、擦除、识别等基本操作。QSPI相比传统SPI具有更高数据吞吐,适用于音频缓存、图像存储、日志记录等对容量…

作者头像 李华
网站建设 2026/9/9 13:09:16

Java中数据类型与变量

1. 字面常量 常量即程序运行期间,固定不变的量称为常量,比如:一个礼拜七天,一年12个月等。 public class Demo{public static void main(String[] args){System.out.println("hello world!");//字符串常量System.out.pr…

作者头像 李华
网站建设 2026/9/9 13:08:03

数据库恢复技术考点全解析:从故障分类到REDO/UNDO流程

期末考试季又到了,很多同学在《数据库原理》这门课上最头疼的章节,往往不是 SQL 语法,也不是关系代数,而是“数据库恢复技术”。这块内容概念多、流程杂、考题灵活,偏偏分值还不低。有人觉得它难,是因为把重…

作者头像 李华