十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

YOLO11改进 - C3k2融合 | RFGM残差傅里叶引导模块:用频域先验修复极暗图像全局照明与结构细节 | TGRS 2026

YOLO11改进 - C3k2融合 | RFGM残差傅里叶引导模块:用频域先验修复极暗图像全局照明与结构细节 | TGRS 2026 前言本文介绍了面向极暗图像细节恢复的残差傅里叶引导模块 RFGM用于缓解低照度场景中结构丢失、边缘模糊和噪声干扰导致的特征退化问题。该方法在频域中分别建模幅值与相位信息通过阶段间残差传递、通道相关性筛选和幅值先验引导稳健恢复全局照明与轮廓结构并结合空间与频率的互补处理进一步细化纹理细节。我们将 RFGM 成功集成进 YOLO11 的 C3k2 模块替代原有部分卷积结构实现更强的暗光特征增强与目标表征能力。文章目录 YOLO11改进大全卷积层、轻量化、注意力机制、损失函数、Backbone、SPPF、Neck、检测头全方位优化汇总专栏链接: YOLO11改进专栏介绍在极暗图像中恢复细粒度细节仍然非常困难因为这类图像通常存在严重的结构信息丢失和噪声污染。现有增强方法往往难以保留复杂纹理和清晰边缘从而限制了它们在文本检测、边缘检测等下游任务中的效果。为解决这些问题论文提出了一种以暗光图像细节恢复为核心的高效双阶段方法。第一阶段引入 Residual Fourier-Guided ModuleRFGM在频域中有效恢复全局照明。RFGM 通过残差连接捕获阶段间和通道间依赖为高保真频域处理提供稳健先验同时缓解不可靠先验带来的误差累积风险。第二阶段使用互补的 Mamba 模块进行纹理结构细化Patch Mamba 作用于通道拼接的非下采样图像块细致建模像素级相关性在不损失分辨率的情况下增强细粒度细节Grad Mamba 显式关注高梯度区域缓解状态空间模型中的状态衰减问题并优先重建锐利边缘和边界。大量基准数据集和下游应用实验表明该方法在保持效率的同时显著提升了暗光图像的细节恢复能力并且这些模块轻量、可插拔能够以较小计算开销集成到已有傅里叶框架中。文章链接论文地址论文地址代码地址代码地址基本原理1. 解决的关键问题RFGM 主要解决极暗图像恢复中“频域先验不稳”和“细节随阶段处理逐步损失”的问题。论文指出极暗图像并不只是亮度低它还伴随结构退化、边缘模糊、纹理缺失和噪声破坏。傅里叶域方法通常把幅值谱与相位谱分开处理幅值更接近图像亮度、能量和全局照明分布相位则保留轮廓、边缘和空间结构。但已有方法往往按卷积块顺序处理幅值和相位前一阶段中有用的亮度或结构信息可能无法被后续阶段充分利用导致信息衰减。另一方面不同通道中包含的结构轮廓和亮度响应并不一致如果孤立处理通道也会错过通道之间可互补的先验。RFGM 因此用“阶段间关联 通道间关联 残差融合”来筛选更可靠的频域信息既利用上一阶段的有效幅值先验又避免错误先验直接覆盖当前特征。2. 整体架构论文整体是一个双阶段暗光图像恢复框架。输入极暗图像先经过一个3×3卷积得到浅层特征然后进入第一阶段的频域全局建模。第一阶段由六个相同的 RFGM 组成重点恢复全局照明和整体结构。每个 RFGM 都会把输入特征映射到傅里叶域拆分为幅值分量和相位分量并分别处理。幅值分支负责选择和融合上一阶段中最有价值的亮度先验相位分支负责把前一阶段的结构信息作为补偿注入当前阶段。第一阶段完成后第二阶段转向空间域细节精修由 Patch Mamba 和 Grad Mamba 共同恢复纹理、边缘和高梯度区域。也就是说RFGM 不是孤立的亮度增强块而是整套方法的频域基础模块它先把全局照明和结构底座恢复得更稳再交给后续 Mamba 分支做细粒度纹理和边界重建。3. 技术原理在第i个 RFGM 中来自上一阶段的特征F_{i-1}先经过 FFT 转换到频域得到幅值A_{i-1}和相位P_{i-1}。二者分别经过卷积和 ReLU 得到当前阶段的幅值A_i与相位P_i。幅值分支会把A_{i-1}和A_i展平成R^{HW×C}计算通道相似性矩阵M ∈ R^{C×C}然后从中选择 Top-1 相关通道作为上一阶段最可靠的亮度先验。该先验经过1×1卷积和 Sigmoid 得到幅值引导权重P_a再与当前幅值相乘并通过残差形式融合Ã_i A_i × P_a A_i。这种设计的关键在于先验只作为引导而不是替代当前表示因此能降低错误先验累积的风险。相位分支则把上一阶段相位P_{i-1}与当前相位P_i在通道维度拼接通过卷积进行自适应融合并以残差形式得到增强后的相位P̃_i。这里的相位信息承担结构补偿作用有助于恢复轮廓、边界和空间布局。最后增强后的幅值Ã_i与相位P̃_i通过 iFFT 回到空间特征作为下一阶段输入。实验上去掉 RFGM 后模型性能下降把 RFGM 插入 FourLLIE、DMFourLLIE 等傅里叶低光增强框架中也能带来增益说明它确实是一个轻量、可插拔、面向频域先验稳定化的核心模块。核心代码classRFGM(nn.Module):def__init__(self,nc,n1):super(RFGM,self).__init__()self.conv0nn.Sequential(nn.Conv2d(3,nc,1,1,0),ProcessBlock(nc),)self.conv1ProcessBlock(nc)self.conv2ProcessBlock(nc)self.conv3ProcessBlock(nc)self.conv4nn.Sequential(ProcessBlock(nc*2),nn.Conv2d(nc*2,nc,1,1,0),)self.conv5nn.Sequential(ProcessBlock(nc*2),nn.Conv2d(nc*2,nc,1,1,0),)self.convoutnn.Sequential(ProcessBlock(nc*2),nn.Conv2d(nc*2,3,1,1,0),)defforward(self,x):xself.conv0(x)x1self.conv1(x)x2self.conv2(x1)x3self.conv3(x2)x4self.conv4(torch.cat((x2,x3),dim1))x5self.conv5(torch.cat((x1,x4),dim1))xoutself.convout(torch.cat((x,x5),dim1))returnxoutYOLO11引入代码在根目录下的ultralytics/nn/目录新建一个C3k2目录然后新建一个以C3k2_RFGM为文件名的py文件 把代码拷贝进去。importtorchimporttorch.nnasnnimporttorch.nn.functionalasFfromultralytics.nn.modules.convimportRepConv,Convfromultralytics.nn.modules.blockimportC3k,C3k2classSpaBlock(nn.Module):def__init__(self,nc):super(SpaBlock,self).__init__()self.blocknn.Sequential(nn.Conv2d(nc,nc,3,1,1),nn.LeakyReLU(0.1,inplaceTrue),nn.Conv2d(nc,nc,3,1,1),nn.LeakyReLU(0.1,inplaceTrue))defforward(self,x):returnxself.block(x)classProcessBlock(nn.Module):def__init__(self,in_nc,spatialTrue):super(ProcessBlock,self).__init__()self.spatialspatial self.spatial_processSpaBlock(in_nc)ifspatialelsenn.Identity()self.frequency_processLightTopKFreBlock(ncin_nc,top_kin_nc)self.catnn.Conv2d(2*in_nc,in_nc,1,1,0)ifspatialelsenn.Conv2d(in_nc,in_nc,1,1,0)defforward(self,x):xorix x_out_fourself.frequency_process(x)x_spatialself.spatial_process(x)xcattorch.cat([x_spatial,x_out_four],1)x_outself.cat(xcat)ifself.spatialelseself.cat(x_out_four)returnx_outxoriclassLightTopKFreBlock(nn.Module):def__init__(self,nc,top_k):super(LightTopKFreBlock,self).__init__()self.ncnc self.top_ktop_k self.conv0nn.Conv2d(nc,nc,1,1,0)self.process1_magnn.Sequential(nn.Conv2d(nc,nc,1,1,0),nn.LeakyReLU(0.1,inplaceTrue),nn.Conv2d(nc,nc,1,1,0))self.process1_phann.Sequential(nn.Conv2d(nc,nc,1,1,0),nn.LeakyReLU(0.1,inplaceTrue),nn.Conv2d(nc,nc,1,1,0))self.process2_phann.Sequential(nn.Conv2d(nc*2,nc,1,1,0),nn.LeakyReLU(0.1,inplaceTrue),nn.Conv2d(nc,nc,1,1,0))self.magGuideFusionMagGuidedFusion(channelsnc)self.conv_outnn.Conv2d(nc*2,nc,1,1,0)defforward(self,x):B,C,H,Wx.shape x_conv0self.conv0(x)x_freqtorch.fft.rfft2(x_conv0,normbackward)mag0torch.abs(x_freq)pha0torch.angle(x_freq)mag1self.process1_mag(mag0)pha1self.process1_pha(pha0)pha_cattorch.cat((pha0,pha1),dim1)pha_outself.process2_pha(pha_cat)mag_out,mag0_weightself.magGuideFusion(mag0,mag1)realmag_out*torch.cos(pha_out)imagmag_out*torch.sin(pha_out)x_out_freqtorch.complex(real,imag)x_outtorch.fft.irfft2(x_out_freq,s(H,W),normbackward)returnx_outclassMagGuidedFusion(nn.Module):def__init__(self,channels):super(MagGuidedFusion,self).__init__()self.channelschannels self.expand_convnn.Conv2d(1,channels,kernel_size1,stride1,padding0)defforward(self,mag0,mag1):B,C,H,Wmag0.shape mag0_flatmag0.view(B,C,-1)# (B, C, H*W)mag1_flatmag1.view(B,C,-1)# (B, C, H*W)mag0_normF.normalize(mag0_flat,dim-1)# (B, C, H*W)mag1_normF.normalize(mag1_flat,dim-1)# (B, C, H*W)similarity_matrixtorch.bmm(mag0_norm,mag1_norm.transpose(1,2))# (B, C, C)similarity_scoressimilarity_matrix.mean(dim-1)# (B, C)top1_indicestorch.argmax(similarity_scores,dim-1)# (B,)mag0_top1torch.stack([mag0[b,top1_indices[b]]forbinrange(B)],dim0).unsqueeze(1)# (B, 1, H, W)mag0_expandedself.expand_conv(mag0_top1)# (B, C, H, W)mag0_weighttorch.sigmoid(mag0_expanded)# (B, C, H, W)fused_featuresmag1*mag0_weightmag1# (B, C, H, W)returnfused_features,mag0_weightclassRFGM(nn.Module):def__init__(self,inc,ouc):super(RFGM,self).__init__()self.conv0nn.Sequential(nn.Conv2d(inc,inc,1,1,0),ProcessBlock(inc),)self.conv1ProcessBlock(inc)self.conv2ProcessBlock(inc)self.conv3ProcessBlock(inc)self.conv4nn.Sequential(ProcessBlock(inc*2),nn.Conv2d(inc*2,inc,1,1,0),)self.conv5nn.Sequential(ProcessBlock(inc*2),nn.Conv2d(inc*2,inc,1,1,0),)self.convoutnn.Sequential(ProcessBlock(inc*2),nn.Conv2d(inc*2,ouc,1,1,0),)defforward(self,x):xself.conv0(x)x1self.conv1(x)x2self.conv2(x1)x3self.conv3(x2)x4self.conv4(torch.cat((x2,x3),dim1))x5self.conv5(torch.cat((x1,x4),dim1))xoutself.convout(torch.cat((x,x5),dim1))returnxoutclassC3k_RFGM(C3k):def__init__(self,c1,c2,n1,shortcutFalse,g1,e0.5,k3):super().__init__(c1,c2,n,shortcut,g,e,k)c_int(c2*e)# hidden channelsself.mnn.Sequential(*(RFGM(c_,c_)for_inrange(n)))classC3k2_RFGM(C3k2):def__init__(self,c1,c2,n1,c3kFalse,e0.5,g1,shortcutTrue):super().__init__(c1,c2,n,c3k,e,g,shortcut)self.mnn.ModuleList(C3k_RFGM(self.c,self.c,2,shortcut,g)ifc3kelseRFGM(self.c,self.c)for_inrange(n))注册在ultralytics/nn/tasks.py中进行如下操作步骤1:fromultralytics.nn.C3k2.C3k2_RFGMimportC3k2_RFGM步骤2修改def parse_model(d, ch, verboseTrue):C3k2_RFGM配置yolo11-C3k2_RFGM.yaml# Ultralytics YOLO , AGPL-3.0 license# YOLO11 object detection model with P3-P5 outputs. For Usage examples see https://docs.ultralytics.com/tasks/detect# Parametersnc:80# number of classesscales:# model compound scaling constants, i.e. modelyolo11n.yaml will call yolo11.yaml with scale n# [depth, width, max_channels]n:[0.50,0.25,1024]# summary: 319 layers, 2624080 parameters, 2624064 gradients, 6.6 GFLOPss:[0.50,0.50,1024]# summary: 319 layers, 9458752 parameters, 9458736 gradients, 21.7 GFLOPsm:[0.50,1.00,512]# summary: 409 layers, 20114688 parameters, 20114672 gradients, 68.5 GFLOPsl:[1.00,1.00,512]# summary: 631 layers, 25372160 parameters, 25372144 gradients, 87.6 GFLOPsx:[1.00,1.50,512]# summary: 631 layers, 56966176 parameters, 56966160 gradients, 196.0 GFLOPs# YOLO11n backbonebackbone:# [from, repeats, module, args]-[-1,1,Conv,[64,3,2]]# 0-P1/2-[-1,1,Conv,[128,3,2]]# 1-P2/4-[-1,2,C3k2_RFGM,[256,False,0.25]]-[-1,1,Conv,[256,3,2]]# 3-P3/8-[-1,2,C3k2_RFGM,[512,False,0.25]]-[-1,1,Conv,[512,3,2]]# 5-P4/16-[-1,2,C3k2_RFGM,[512,True]]-[-1,1,Conv,[1024,3,2]]# 7-P5/32-[-1,2,C3k2_RFGM,[1024,True]]-[-1,1,SPPF,[1024,5]]# 9-[-1,2,C2PSA,[1024]]# 10# YOLO11n headhead:-[-1,1,nn.Upsample,[None,2,nearest]]-[[-1,6],1,Concat,[1]]# cat backbone P4-[-1,2,C3k2_RFGM,[512,False]]# 13-[-1,1,nn.Upsample,[None,2,nearest]]-[[-1,4],1,Concat,[1]]# cat backbone P3-[-1,2,C3k2_RFGM,[256,False]]# 16 (P3/8-small)-[-1,1,Conv,[256,3,2]]-[[-1,13],1,Concat,[1]]# cat head P4-[-1,2,C3k2_RFGM,[512,False]]# 19 (P4/16-medium)-[-1,1,Conv,[512,3,2]]-[[-1,10],1,Concat,[1]]# cat head P5-[-1,2,C3k2_RFGM,[1024,True]]# 22 (P5/32-large)-[[16,19,22],1,Detect,[nc]]# Detect(P3, P4, P5)实验脚本importwarnings warnings.filterwarnings(ignore)fromultralyticsimportYOLOif__name____main__:# 修改为自己的配置文件地址modelYOLO(./ultralytics/cfg/models/11/yolo11-C3k2_RFGM.yaml)# 修改为自己的数据集地址model.train(data./ultralytics/cfg/datasets/coco8.yaml,cacheFalse,imgsz640,epochs10,single_clsFalse,# 是否是单类别检测batch8,close_mosaic10,workers0,optimizerSGD,ampTrue,projectruns/train,nameC3k2_RFGM,)结果
返回列表