图像去雨Derain实战:从技术路线到PyTorch代码与避坑指南

发布时间:2026/10/11 11:59:31
图像去雨Derain实战:从技术路线到PyTorch代码与避坑指南 简介Derain 是一份面向图像处理与计算机视觉学习者的 Python 去雨项目资源聚焦于消除照片中的雨滴干扰提升恶劣天气下图像的清晰度与可用性。项目综合运用图像预处理、特征提取、雨滴建模与背景恢复等思路并涉及卷积神经网络、条件生成对抗网络等深度学习方法的实践适合具备一定 Python 与图像处理基础、希望深入理解去雨算法的读者参考。压缩包共 4 个文件包含 2 个 pdf 论文资料、1 个 py 主程序脚本和 1 个 txt 说明文档整体约 3.72MB其中论文可用于理解算法原理脚本则提供可运行的实现入口。目前已有 199 人学习下载。通过这份资源读者可以对照论文梳理去雨流程借助主程序脚本动手复现算法并参考说明文档快速了解项目结构与运行方式为后续的图像恢复与增强研究提供可借鉴的实践素材。1. Derain从一张雨滴糊住的行车记录仪截图说起前阵子帮一个做智慧工地巡检的朋友看数据他手里有一批雨天拍的监控截图雨滴挂在镜头上画面像蒙了一层毛玻璃钢筋绑扎间距、安全帽佩戴这些细节全糊成一团。他问我能不能用算法把雨去掉我第一反应就是 Derain 这个方向——图像去雨。Derain 是 derainde-rain的缩写在计算机视觉里专指从单张图像或视频序列中分离并去除雨滴、雨线、雨雾还原干净背景的技术。它解决的不是让照片更好看而是让下游的检测、识别、测量任务在雨天不掉精度。适合谁做安防监控、自动驾驶感知、户外巡检、遥感影像预处理的工程师以及想入门底层视觉复原的研究生。这一章先把 Derain 到底在做什么、为什么难、值不值得投入讲清楚后面几章直接上可复现的代码和参数。2. Derain 的两条技术路线雨线、雨滴和雨雾到底怎么分2.1 先搞清楚你要去的是哪种雨很多人一上来就说我要去雨结果拿到的数据里既有斜向雨线又有镜头上的失焦雨滴还有整体发灰的雨雾。这三类在物理成因和算法处理上完全不同选错路线后面全白干。雨线rain streak是雨滴下落时在曝光时间内形成的运动模糊方向性强、长度和角度随快门和风速变化通常叠加在背景上属于加性噪声。雨滴raindrop是附着在镜头或玻璃上的球状水珠它同时产生折射和模糊会把背景局部扭曲属于透射模糊的复合退化。雨雾rain fog / haze是大量悬浮水滴对光的散射导致对比度下降、颜色偏移更接近大气散射模型。我一般会先看数据如果雨是斜线状、背景还能辨认走雨线去除如果是圆斑、背景被局部放大或扭曲走雨滴去除如果整幅发灰、远景消失先做去雾再做去雨。这个判断决定了你后面选数据集、选网络结构、选损失函数。2.2 从物理模型到深度学习为什么现在主流是数据驱动早期方法靠先验。雨线检测用形态学成分分析MCA把图像分解成低频背景和高频雨线再对高频做稀疏约束。雨滴去除用层分离模型假设观测图像是背景层和雨滴层的线性组合。这些方法在合成数据上指标还行一到真实雨天就翻车因为真实雨线的形状、密度、光照变化远超手工先验的覆盖范围。现在主流是深度学习。核心思路是让网络学习一个从退化图像到干净图像的映射。早期用 CNN 做残差学习预测雨线层再相减后来引入注意力机制让网络关注雨线区域再后来用生成对抗网络GAN提升视觉质量用循环一致性解决成对数据难获取的问题。近两年 Transformer 架构也被搬进来因为自注意力对长条状雨线的全局建模更自然。选型上我的建议很直接如果你有成对数据同一场景有雨和无雨优先用监督学习结构选带注意力或多尺度的 CNN/Transformer损失用 L1 感知损失 对抗损失组合。如果没有成对数据用半监督或零样本方法但要有心理准备指标和稳定性会差一截。不要迷信某个SOTA 模型先看你的数据分布和它训练集像不像。2.3 一个最小可跑的 Derain 训练脚本长什么样下面给一个基于 PyTorch 的最小训练框架结构用简化的残差注意力网络数据用合成雨线。这不是某个现成仓库的代码是我自己搭验证流程时常用的骨架你可以直接替换数据集和模型。import torch import torch.nn as nn import torch.optim as optim from torch.utils.data import Dataset, DataLoader # 简化残差块两层卷积 跳跃连接 class ResidualBlock(nn.Module): def __init__(self, channels64): super().__init__() self.conv1 nn.Conv2d(channels, channels, 3, padding1) self.relu nn.ReLU(inplaceTrue) self.conv2 nn.Conv2d(channels, channels, 3, padding1) def forward(self, x): residual x out self.relu(self.conv1(x)) out self.conv2(out) return out residual # 残差学习缓解梯度消失 # 去雨网络输入3通道输出3通道中间堆残差块 class DerainNet(nn.Module): def __init__(self, num_blocks8): super().__init__() self.head nn.Conv2d(3, 64, 3, padding1) self.blocks nn.Sequential(*[ResidualBlock(64) for _ in range(num_blocks)]) self.tail nn.Conv2d(64, 3, 3, padding1) def forward(self, x): feat self.head(x) feat self.blocks(feat) rain self.tail(feat) # 预测雨线层 return x - rain # 原图减雨线 干净图 # 合成数据集真实干净图 随机方向雨线 class SyntheticRainDataset(Dataset): def __init__(self, clean_images): self.clean clean_images def __len__(self): return len(self.clean) def __getitem__(self, idx): clean self.clean[idx] # 生成随机角度和长度的雨线掩码实际项目里用更真实的雨线渲染 rain torch.randn_like(clean) * 0.15 rainy torch.clamp(clean rain, 0, 1) return rainy, clean # 训练循环 def train(model, loader, epochs50, lr1e-4): device torch.device(cuda if torch.cuda.is_available() else cpu) model.to(device) optimizer optim.Adam(model.parameters(), lrlr) criterion nn.L1Loss() # L1 比 L2 更不容易产生模糊 for epoch in range(epochs): model.train() total_loss 0 for rainy, clean in loader: rainy, clean rainy.to(device), clean.to(device) optimizer.zero_grad() output model(rainy) loss criterion(output, clean) loss.backward() optimizer.step() total_loss loss.item() print(fEpoch {epoch1}, Loss: {total_loss/len(loader):.4f}) # 使用示例 # dataset SyntheticRainDataset(clean_tensor_list) # loader DataLoader(dataset, batch_size8, shuffleTrue) # model DerainNet(num_blocks8) # train(model, loader)逻辑说明网络不直接输出干净图而是预测雨线层再用输入减去雨线。这样做的好处是残差学习更容易训练网络只需要关注雨线的高频部分不用重建整个背景。num_blocks控制容量8 到 16 是常见范围太小欠拟合太大在数据少时过拟合。L1Loss比 MSE 更保边缘去雨任务里边缘清晰度很关键。参数说明学习率1e-4是 Adam 的稳妥起点如果 loss 震荡降到5e-5batch size 受显存限制8 或 16 都行但 batch 太小 BN 统计不稳可以考虑 GroupNorm。训练轮数不是固定值看验证集 PSNR 不再上升就停通常 50 到 200 轮。合成雨线的强度0.15只是示意真实项目要用雨线渲染引擎生成不同密度、角度、模糊程度的样本。3. 数据集、评价指标和训练策略别在第一步就埋雷3.1 公开数据集怎么选合成和真实的差距在哪Derain 领域常用的公开数据集分两类合成雨线和真实雨图。合成数据集通常用干净图加渲染雨线生成成对样本优点是配对精确、指标可算缺点是雨线分布和真实场景有域差。真实数据集靠采集同一场景的雨天和晴天图或者用视频帧对齐优点是真实缺点是配对误差大、场景有限。我一般这样用先在合成数据上把流程跑通、把模型结构调好再用真实数据做微调或域适应。如果你只有真实雨图没有干净图考虑用循环一致性或零样本方法但评估只能靠无参考指标加人眼判断。选数据集时重点看三点雨的类型是否匹配你的场景、图像分辨率是否够、场景多样性是否覆盖你的部署环境。不要拿一个全是城市道路的数据集去训工地监控模型域差会让你怀疑人生。3.2 PSNR、SSIM 和 LPIPS指标好看不等于能用去雨任务常用三个指标。PSNR 衡量像素级误差值越高越好但它对模糊不敏感一个糊掉的图也可能有高 PSNR。SSIM 衡量结构相似性比 PSNR 更贴近人眼但对纹理丰富的区域仍然不够。LPIPS 用深度特征算感知距离值越低越好和主观质量相关性更高。我的经验是三个指标一起看再配合下游任务指标。比如你做安全帽检测去雨后的图送进检测器看 mAP 涨了多少这比 PSNR 涨 0.5dB 有意义得多。如果只能选一个优先看 LPIPS 和下游指标PSNR 作为参考。很多论文里 PSNR 刷得很高实际图一看还是糊的这就是过拟合指标的典型翻车。3.3 损失函数组合和训练技巧单一 L1 损失会让结果偏平滑细节丢失。常见组合是 L1 感知损失VGG 特征距离 对抗损失。感知损失保纹理对抗损失保真实感但对抗训练不稳定权重给大了会出现伪影。我一般先用 L1 训到收敛再加感知损失微调最后视情况加对抗损失权重从 0.01 起调。训练技巧上数据增强很关键随机裁剪、水平翻转、颜色抖动都能提升泛化。学习率用余弦退火或阶梯下降别一直固定。验证集要按场景划分不能随机划分否则同一场景的图同时出现在训练和验证里指标虚高。还有一点去雨网络的输入最好归一化到 [0,1] 或 [-1,1]和预训练权重保持一致不然收敛慢。4. 避坑与排查那些让我返工三次的问题4.1 去雨后画面发灰、对比度下降现象输出去雨图整体比干净图暗或灰像蒙了一层。原因通常是网络学到了平均背景把雨线和部分背景一起减掉了或者损失函数对低频约束不足。解决在损失里加一个低频一致性项约束输出和输入的低频分量接近或者改用预测干净图而不是预测雨线层让网络直接对背景负责。另外检查数据归一化反归一化时别把范围截断错了。4.2 雨线去不干净残留细长条纹现象粗雨线去掉了细密雨丝还在。原因是感受野不够网络看不到长条状雨线的全局结构。解决加多尺度分支或空洞卷积扩大感受野用注意力机制让网络关注雨线区域训练数据里增加细雨线的比例。如果用的是 CNN可以堆更多残差块但注意过拟合。Transformer 在这类问题上天然有优势但数据量要够。4.3 真实场景效果远差于合成数据现象合成验证集 PSNR 35dB真实雨图一跑全是伪影。原因是域差合成雨线的分布和真实雨线不一样。解决做域适应用真实雨图做无监督微调或者在合成时用更真实的雨线渲染考虑雨滴的折射、运动模糊、光照变化。还有一个实用做法拿少量真实成对数据做微调哪怕只有几十对也能明显改善。4.4 训练 loss 不下降或震荡现象loss 卡住不动或者上下跳。原因可能是学习率太大、batch 太小、数据有问题、网络初始化不当。解决先用一个极小数据集过拟合如果 loss 能降到接近零说明网络和数据管道没问题再调学习率和 batch。检查数据里有没有全黑或全白的异常样本。初始化用 Kaiming 或默认别自己乱设。Adam 的默认 betas 一般够用不要随便改。4.5 推理速度太慢达不到实时现象模型在服务器上跑一张图要几百毫秒部署到边缘设备更慢。原因是网络太深或分辨率太高。解决用轻量结构减少通道数和残差块数量用深度可分离卷积推理前把图缩到合适分辨率去雨后再上采样用 TensorRT 或 ONNX Runtime 加速。如果场景允许用视频去雨利用时序信息比单帧去雨更稳也更快。5. 进阶技巧把 Derain 嵌进真实 pipeline 的几个习惯先说一个验证方法。去雨模型训完之后别只看指标做一次下游任务验证拿你的检测或分割模型分别在雨天原图和去雨图上跑对比 mAP 或 IoU。如果去雨后下游指标没涨甚至降了说明去雨过程引入了伪影或丢失了关键信息这时候要回头调损失权重而不是继续刷 PSNR。我一般会保留一个下游验证集专门用来做这个判断。再说一个具体技巧分块推理加重叠融合。高分辨率图直接送网络显存吃不消切成小块又会在边界产生接缝。做法是切块时保留重叠区域推理后对重叠部分做加权平均权重用高斯窗这样接缝基本看不出来。代码如下import torch import torch.nn.functional as F def tile_inference(model, image, tile_size256, overlap32): # image: [1, 3, H, W] _, _, H, W image.shape output torch.zeros_like(image) weight torch.zeros_like(image) step tile_size - overlap for i in range(0, H, step): for j in range(0, W, step): i_end min(i tile_size, H) j_end min(j tile_size, W) i_start max(i_end - tile_size, 0) j_start max(j_end - tile_size, 0) tile image[:, :, i_start:i_end, j_start:j_end] with torch.no_grad(): pred model(tile) # 高斯窗加权边界权重低中心权重高 h, w pred.shape[2], pred.shape[3] gauss torch.outer( torch.hann_window(h, devicepred.device), torch.hann_window(w, devicepred.device) ).unsqueeze(0).unsqueeze(0) output[:, :, i_start:i_end, j_start:j_end] pred * gauss weight[:, :, i_start:i_end, j_start:j_end] gauss return output / (weight 1e-8)逻辑说明用 Hann 窗做加权中心区域贡献大边界贡献小重叠区域自然融合。tile_size根据显存选256 或 512 都常见overlap至少覆盖网络感受野32 到 64 比较稳。这个技巧在遥感大图和监控全景图上特别有用直接整图推理要么爆显存要么边缘效果差。最后说一个习惯每次实验都固定随机种子记录数据版本、模型配置、学习率和指标。去雨这方向复现性是个大坑同一个模型不同次训练结果能差 1dB 以上。我吃过亏后来养成用配置文件管理实验的习惯省了很多后悔药。另外别迷信排行榜你的场景数据才是最终裁判。如果这个方向对你的业务有价值先花两天把数据管道和评估流程搭好再动模型顺序反了会浪费几周。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询