0 论文信息
- 论文标题: Efficient Frequency-Domain Image Deraining with Contrastive Regularization
- 中文标题:基于对比正则化的高效频域图像去雨
- 论文链接
- 论文代码
- 论文出处:ECCV
0 论文概述
单图像去雨(SID)是低层次图像恢复的关键任务,现有基于 Transformer 的方法虽能通过全局建模实现高质量重建,但存在空间域全局建模计算成本高、负样本中雨纹模式信息未充分利用的问题。为此,本文提出 FADformer 框架:通过融合频域与空域特征的 FFCM 模块实现高效全局 - 局部建模,通过引入残差通道先验的 PGFN 模块增强局部细节修复,再结合频域对比正则化(FCR)充分利用负样本信息。在 7 个公开数据集(4 个合成 + 3 个真实)上的实验表明,FADformer 在 PSNR、SSIM 等指标上超越现有 SOTA 方法,且模型参数和计算量仅为同类方法的 20% 左右,同时 FCR 具有跨数据集、跨模型、跨任务的通用性。
1 实验动机
现有单图像去雨方法面临两大核心挑战,且频域特性为解决这些挑战提供了新视角:
- 全局建模效率低:主流方法依赖空域自注意力机制实现全局建模,但计算成本随图像尺寸呈平方增长,难以平衡效果与效率(如图 1 所示,现有方法参数 / 计算量与性能不成正比)。
- 负样本利用不足:多数方法仅依赖清晰图像(正样本)训练,忽视负样本(含雨图像)中的雨纹模式信息;少数对比学习方法未结合去雨任务先验,效果有限。
- 频域天然优势:雨纹在频域具有显著且稳定的特征,与图像内容空间独立(图 2a);频域局部修复可对空域产生全局影响(图 2b),可实现高效全局建模和雨纹 - 内容分离。
2 模块介绍
FFCM 是一种可插拔的高效全局建模模块,特别适用于图像去雨、去模糊、去雾等频率特征显著的图像恢复任务。它通过在频域执行卷积混合,实现自注意力级别的全局感知能力,却仅需卷积级的计算开销,从而在保持高质量重建的同时显著降低模型复杂度
适用场景:
- 低层视觉重建类任务
单幅图像去雨 / 去雾 / 去雪 / 去模糊 / 超分辨率
原因:这些任务对纹理细节、全局结构恢复都高度敏感,而频域分析可精准捕获退化噪声模式(如雨条纹方向、雾气密度、模糊核频率分布)。
优势:FFCM 能在频域高效提取全局退化特征,同时在空间域保持局部细节,兼顾质量与效率
- 高分辨率图像修复与重建
如 Real-World Restoration(真实世界去噪、图像增强等)。
优势:频域特征能高效表达全局照度和纹理变化,FFCM 可作为轻量替代注意力模块使用
- Transformer或CNN结构的轻量化替换模块
可直接替代传统Transformer中的 Self-Attention 或CNN中的 大卷积核模块
适合应用于高效Transformer(如Uformer、Restormer、SwinIR等)的加速版本中
- 频率特征显著的任务
例如医学成像(MRI、CT复原)、SAR遥感去噪、OCT影像增强
这类任务天然在频率空间有强特征分布,FFCM可直接利用FFT特征增强重建效果
模块作用:
局部–全局融合(Local–Global Fusion)
通过在空间域使用多尺度深度卷积(Multi-DConv)提取局部特征;
再将其送入频率域(Fourier Domain)进行全局建模;
最后再通过逆变换(IFFT)返回空间域,实现特征的融合
高效全局建模(Efficient Global Modeling)
不依赖复杂的自注意力矩阵,而是利用FFT天然的全局感受野来捕获图像中的远程依赖关系;
因此能以卷积复杂度(O(NlogN)) 近似实现全局特征交互
增强结构敏感性(Structure-Aware Filtering)
雨条纹、雾、模糊等退化信号在频域中表现明显,FFCM可直接在频谱上建模这些特征,提取出与退化模式相关的全局信息;
对细节恢复与纹理重建有显著帮助
importtorchimporttorch.nnasnnclassFourierUnit(nn.Module):def__init__(self,in_channels,out_channels,groups=1):super(FourierUnit,self).__init__()self.groups=groups# 定义卷积层,用于处理傅里叶变换后的特征self.conv_layer=torch.nn.Conv2d(in_channels=in_channels*2,out_channels=out_channels*2,kernel_size=1,stride=1,padding=0,groups=self.groups,bias=False)# 定义批归一化层self.bn=torch.nn.BatchNorm2d(out_channels*2)# 定义ReLU激活函数self.relu=torch.nn.ReLU(inplace=True)defforward(self,x):batch,c,h,w=x.size()# 进行二维傅里叶变换ffted=torch.fft.rfft2(x,norm='ortho')# 获取傅里叶变换的实部x_fft_real=torch.unsqueeze(torch.real(ffted),dim=-1)# 获取傅里叶变换的虚部x_fft_imag=torch.unsqueeze(torch.imag(ffted),dim=-1)# 合并实部和虚部ffted=torch.cat((x_fft_real,x_fft_imag),dim=-1)# 调整维度顺序ffted=ffted.permute(0,1,4,2,3).contiguous()# 调整形状以适应卷积层输入ffted=ffted.view((batch,-1,)+ffted.size()[3:])# 通过卷积层ffted=self.conv_layer(ffted)# 通过批归一化和ReLU激活ffted=self.relu(self.bn(ffted))# 调整形状以适应傅里叶逆变换ffted=ffted.view((batch,-1,2,)+ffted.size()[2:]).permute(0,1,3,4,2).contiguous()# 转换为复数形式ffted=torch.view_as_complex(ffted)# 进行逆傅里叶变换output=torch.fft.irfft2(ffted,s=(h,w),norm='ortho')returnoutputclassFreq_Fusion(nn.Module):def__init__(self,dim,kernel_size=[1,3,5,7],se_ratio=4,local_size=8,scale_ratio=2,spilt_num=4):super(Freq_Fusion,self).__init__()self.dim=dim self.c_down_ratio=se_ratio self.size=local_size self.dim_sp=dim*scale_ratio//spilt_num# 定义初始卷积层1self.conv_init_1=nn.Sequential(# PWnn.Conv2d(dim,dim,1),nn.GELU())# 定义初始卷积层2self.conv_init_2=nn.Sequential(# DWnn.Conv2d(dim,dim,1),nn.GELU())# 定义中间卷积层self.conv_mid=nn.Sequential(nn.Conv2d(dim*2,dim,1),nn.GELU())# 定义傅里叶单元self.FFC=FourierUnit(self.dim*2,self.dim*2)# 定义批归一化和ReLU激活self.bn=torch.nn.BatchNorm2d(dim*2)self.relu=torch.nn.ReLU(inplace=True)defforward(self,x):# 将输入张量分割为两个x_1,x_2=torch.split(x,self.dim,dim=1)# 通过初始卷积层1x_1=self.conv_init_1(x_1)# 通过初始卷积层2x_2=self.conv_init_2(x_2)# 合并两个特征图x0=torch.cat([x_1,x_2],dim=1)# 通过傅里叶单元并进行残差连接x=self.FFC(x0)+x0# 通过批归一化和ReLU激活x=self.relu(self.bn(x))returnxclassFFCM(nn.Module):def__init__(self,dim,token_mixer_for_gloal=Freq_Fusion,mixer_kernel_size=[1,3,5,7],local_size=8):super(FFCM,self).__init__()self.dim=dim# 定义全局特征融合模块self.mixer_gloal=token_mixer_for_gloal(dim=self.dim,kernel_size=mixer_kernel_size,se_ratio=8,local_size=local_size)# 定义通道注意力卷积层self.ca_conv=nn.Sequential(nn.Conv2d(2*dim,dim,1),nn.Conv2d(dim,dim,kernel_size=3,padding=1,groups=dim,padding_mode='reflect'),nn.GELU())# 定义通道注意力模块self.ca=nn.Sequential(nn.AdaptiveAvgPool2d(1),nn.Conv2d(dim,dim//4,kernel_size=1),nn.GELU(),nn.Conv2d(dim//4,dim,kernel_size=1),nn.Sigmoid())# 定义初始卷积层self.conv_init=nn.Sequential(# PW->DW->nn.Conv2d(dim,dim*2,1),nn.GELU())# 定义深度可分离卷积层1self.dw_conv_1=nn.Sequential(nn.Conv2d(self.dim,self.dim,kernel_size=3,padding=3//2,groups=self.dim,padding_mode='reflect'),nn.GELU())# 定义深度可分离卷积层2self.dw_conv_2=nn.Sequential(nn.Conv2d(self.dim,self.dim,kernel_size=5,padding=5//2,groups=self.dim,padding_mode='reflect'),nn.GELU())defforward(self,x):# 通过初始卷积层x=self.conv_init(x)# 将特征图分割x=list(torch.split(x,self.dim,dim=1))# 通过深度可分离卷积层1x_local_1=self.dw_conv_1(x[0])# 通过深度可分离卷积层2x_local_2=self.dw_conv_2(x[0])# 通过全局特征融合模块x_gloal=self.mixer_gloal(torch.cat([x_local_1,x_local_2],dim=1))# 通过通道注意力卷积层x=self.ca_conv(x_gloal)# 应用通道注意力x=self.ca(x)*xreturnxif__name__=='__main__':ffcm_module=FFCM(dim=64)input=torch.randn(1,64,256,256)# 将输入张量传入 FFCM 模块output=ffcm_module(input)# 输出结果的形状print("输入张量的形状:",input.shape)print("输出张量的形状:",output.shape)