【CVPR 2026即插即用模块】DEGConv方向引导边缘门控卷积,适合裂缝分割、血管分割、车道线检测、电力线检测、边缘检测、医学细长结构分割、目标检测、实例分割等CV任务通用,涨点起飞!
一、论文信息
本文目录
一、论文信息
二、论文摘要概况
三、DEGConv方向引导边缘门控卷积结构图
四、DEGConv模块的作用
五、DEGConv模块的原理
六、DEGConv模块的优势
七、即插即用模块代码
论文题目:MixerCSeg: An Efficient Mixer Architecture for Crack Segmentation
via Decoupled Mamba Attention中文题目:MixerCSeg:一种基于解耦Mamba注意力机制的高效裂缝分割混合器架构
论文链接:[2603.01361] MixerCSeg: An Efficient Mixer Architecture for Crack Segmentation via Decoupled Mamba Attention
所属单位:1中国山东大学齐鲁交通学院 2美国杜兰大学计算机科学系
二、论文摘要概况
特征编码器在像素级裂纹分割中发挥着关键作用,其通过塑造精细纹理和微细结构的表征来实现精准处理。现有的CNN、Transformer及基于Mamba的模型均仅能捕捉部分所需的空间或结构信息,在建模复杂裂纹图案时存在明显局限。为解决这一问题,我们提出MixerCSeg混合架构——该架构如同一个协作专家团队:CNN类路径专注于局部纹理特征,Transformer风格路径捕捉全局依赖关系,而受Mamba启发的流式机制则在同一编码器内建模序列上下文。MixerCSeg的核心组件TransMixer在探索Mamba潜在注意力机制的同时,建立了专门的路径以自然呈现局部特征与全局感知能力。为提升结构保真度,我们引入空间块处理策略及方向引导边缘门控卷积(DEGConv),在保持计算开销最小的前提下显著增强对不规则裂纹几何形态的边缘敏感性。随后采用空间细化多级融合(SRF)模块在不增加复杂度的情况下优化多尺度细节。多项裂纹分割基准实验表明,MixerCSeg仅需2.05 GFLOPs计算资源和2.54百万参数即可实现业界领先性能,充分展现了高效性与强大的表征能力。
VMamba [18] 中热图与注意力图的可视化结果。得益于多方向扫描机制,全局通道中的标记能够形成覆盖整个范围的感受野,而非局限于历史上下文;相比之下,局部通道则专注于邻近区域的视野范围。
三、DEGConv方向引导边缘门控卷积结构图
我们提出的C2 SSM 架构概述。该C2 SSM 采用非对称U-Net架构,其解码器整合了簇中心扫描模块与空间通道特征调制器,以实现空间通道层面的全局特征耦合。
四、DEGConv模块的作用
(1)增强裂缝边缘感知能力
DEGConv(Direction-guided Edge Gated Convolution)模块的核心作用是增强模型对裂缝边缘和纹理细节的感知能力。由于裂缝通常呈现细长、弯曲、分叉和不连续等复杂形态,传统卷积难以准确追踪裂缝的延伸方向和边界信息。DEGConv通过引入方向先验信息,使模型能够更加敏感地识别裂缝边缘,从而提高像素级分割精度。
(2)强化复杂拓扑结构建模
实际道路裂缝往往具有多方向分支、交叉连接以及不规则拓扑结构。DEGConv利用方向引导机制对裂缝走向进行编码,使模型能够学习裂缝的几何结构特征和拓扑关系,从而更准确地识别复杂裂缝形态。
(3)补充编码器的纹理表达能力
TransMixer主要负责全局与局部特征提取,而DEGConv位于解码前阶段,专门用于强化裂缝纹理和边缘信息。论文指出,DEGConv能够帮助模型进一步捕获裂缝的纹理特征和形态特征,使后续SRF融合模块获得更高质量的特征输入。
(4)提升像素级裂缝分割精度
裂缝分割本质上是一个精细边界定位问题。DEGConv通过方向约束和边缘增强,使模型能够更加准确地区分裂缝与背景区域,尤其是在低对比度和复杂背景场景下,能够有效提升裂缝边界定位能力。
五、DEGConv模块的原理
1)空间块划分策略(Spatial Block Processing)
为了降低计算成本并提高局部方向建模能力,DEGConv首先将输入特征图划分为多个不重叠的局部块(View)。对于第i层特征图:
模型按照固定尺寸划分成多个局部区域,每个区域独立计算方向信息和边缘特征。这样既能够保留局部结构信息,又能避免全图计算带来的高复杂度。
(2)方向嵌入生成(Direction Embedding Generation)
这是DEGConv最重要的创新之一。
作者首先对局部区域进行通道平均,然后利用Sobel算子计算水平梯度 dx和垂直梯度 dy:
获得每个像素的方向角度信息。
随后将方向角划分为多个方向区间(bins),统计每个区域的方向分布直方图(Orientation Histogram),最终生成方向先验向量(Directional Embedding)。
(3)轻量级边缘卷积(Edge Convolution)
为了进一步提取裂缝纹理特征,作者设计了轻量级EdgeConv。
首先使用1×1卷积降低通道维度,减少计算量;随后分别采用:
- 1×k 条带卷积
- k×1条带卷积
分别提取水平方向和垂直方向特征。
最后将两个方向特征进行拼接,并利用Depth-wise卷积融合,形成增强后的边缘特征表示。
(4)门控机制(Gating Mechanism)
在获得方向嵌入后,DEGConv将方向先验与原始特征相加:
生成门控权重。同时对原始特征执行EdgeConv:
利用门控权重动态调节信息流。
这一机制能够:
- 强化重要裂缝区域;
- 抑制背景噪声;
- 保留关键边缘信息。
从而实现更加精准的裂缝特征增强。
5)后处理边缘优化
由于空间块划分可能导致块边界不连续问题,作者在所有局部块重组后,再额外引入一层EdgeConv进行后处理,从而缓解块边界伪影问题,恢复完整的空间结构。
六、DEGConv模块的优势
1. 具备方向感知能力
DEGConv通过方向嵌入理解裂缝延伸方向和拓扑结构,使模型能够识别复杂裂缝形态,这是传统卷积无法实现的。
2. 增强边缘和纹理表达
专门的EdgeConv结构能够提取裂缝边缘、分叉区域和微小裂纹,高频细节特征得以保留,提高像素级分割精度。
3. 抑制背景干扰
门控机制动态筛选信息,仅保留与方向先验一致的重要区域,有效降低阴影、污渍或光照变化等背景干扰对分割的影响。
4. 计算开销低
DEGConv采用局部块处理和轻量卷积,计算开销低(FLOPs增加0.08G,参数量增加0.14M),但分割性能显著提升,性能收益比高。
5. 几何可解释性强
方向嵌入基于梯度直方图构建,具有明确几何意义,相比黑箱注意力方法,更容易理解和可视化。
6. 特别适合细长结构目标
DEGConv天然适合细长目标的分割与检测,如裂缝、血管、道路、电力线等方向性强、拓扑复杂的目标。
图4. MixerCSeg与当前最先进方法在不同环境下的可视化对比结果。
七、即插即用模块代码
import math import einops import torch import torch.nn as nn import torch.nn.functional as F class EdgeConv(nn.Module): def __init__(self, in_channels, mid_channels, out_channels, kernel_size=3, bias=True): super().__init__() self.in_proj = nn.Conv2d( in_channels=in_channels, out_channels=mid_channels, kernel_size=1, bias=bias) self.w_conv = nn.Conv2d( mid_channels, mid_channels, kernel_size=(1, kernel_size), stride=1, padding=(0, kernel_size//2), groups=mid_channels) self.h_conv = nn.Conv2d( mid_channels, mid_channels, kernel_size=(kernel_size, 1), stride=1, padding=(kernel_size//2, 0), groups=mid_channels ) self.out_proj = nn.Conv2d( in_channels=mid_channels * 2, out_channels=out_channels, kernel_size=1, bias=True ) def forward(self, x): x = self.in_proj(x) x_w = self.w_conv(x) x_h = self.h_conv(x) x = torch.cat([x_w, x_h], dim=1) x = self.out_proj(x) return x class DEGConv(nn.Module): def __init__(self, in_dim, nbins, cell_size = (8, 8)): super().__init__() self.nbins = nbins self.cell_size = cell_size self.hog_feat = nn.Sequential( nn.Conv2d(nbins, in_dim, kernel_size=1), nn.Conv2d(in_dim, in_dim, kernel_size=3, padding=1, groups=in_dim, bias=False), nn.GroupNorm(in_dim // 8, in_dim), nn.ReLU(inplace=True), nn.AdaptiveAvgPool2d((1, 1)) ) self.weight = nn.Sequential( EdgeConv(in_channels=in_dim, mid_channels=in_dim//2, out_channels=in_dim), nn.GroupNorm(in_dim//8, in_dim) ) self.conv = nn.Sequential( nn.Conv2d(in_channels=in_dim, out_channels=in_dim, kernel_size=1, stride=1), nn.GroupNorm(in_dim//8, in_dim) ) self.fuse_block = nn.Sequential( EdgeConv(in_channels=in_dim, mid_channels=in_dim//2, out_channels=in_dim, kernel_size=3), nn.GroupNorm(in_dim//8, in_dim) ) self.sigmoid = nn.Sigmoid() def forward(self, x): residual = x x = image2patches(x) x_hog = self.get_hog_feature(x) x_hog = self.hog_feat(x_hog) x1 = self.sigmoid(self.weight(x + x_hog)) x2 = self.conv(x) x = x1 * x2 x = patches2image(x) x = x + residual x = self.fuse_block(x) return x def get_hog_feature(self, x): x_mean = x.mean(dim=1, keepdim=True) B, _, H, W = x_mean.shape device = x_mean.device sobel_x = torch.tensor([[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]], dtype=torch.float32).view(1, 1, 3, 3).to(device) sobel_y = torch.tensor([[-1, -2, -1], [0, 0, 0], [1, 2, 1]], dtype=torch.float32).view(1, 1, 3, 3).to(device) dx = F.conv2d(x_mean.float(), sobel_x, padding=1) # b, 1, h, w dy = F.conv2d(x_mean.float(), sobel_y, padding=1) # direction gradient_dir = torch.atan2(dy, dx) # [-π,π] gradient_dir = torch.abs(gradient_dir) # [0,π] # cells cell_h, cell_w = self.cell_size H_cells = int(H / cell_h) W_cells = int(W / cell_w) # dirs_crop = gradient_dir[:, :, :H_cells*cell_h, :W_cells*cell_w] # [B, H_cells, W_cells, cell_h*cell*w] dirs = dirs_crop.view(B, H_cells, W_cells, -1) bin_with = torch.pi / self.nbins bin_indices = (dirs / bin_with).floor().long() bin_indices = torch.clamp(bin_indices, 0, self.nbins-1) bin_indices_flat = bin_indices.view(B*H_cells*W_cells, dirs.shape[-1]) weight = [] for i in range(bin_indices_flat.shape[0]): bins = bin_indices_flat[i] count = torch.bincount(bins, minlength=self.nbins) weight.append(count) weight = torch.stack(weight, dim=0).view(B, H_cells , W_cells, -1) / 64 # B, H_cells , W_cells, self.bins start = torch.pi / (2*self.nbins) hog_feature = torch.linspace(start, torch.pi - start, self.nbins).to(device).repeat(B, H_cells, W_cells,1) * weight return hog_feature.permute(0, 3, 1, 2) def image2patches(x): """b c (hg h) (wg w) -> (hg wg b) c h w""" x = einops.rearrange(x, 'b c (hg h) (wg w) -> (hg wg b) c h w', hg=2, wg=2) return x def patches2image(x): """(hg wg b) c h w -> b c (hg h) (wg w)""" x = einops.rearrange(x, '(hg wg b) c h w -> b c (hg h) (wg w)', hg=2, wg=2) return x # 使用示例 if __name__ == "__main__": device = "cuda" if torch.cuda.is_available() else "cpu" input = torch.randn(1, 64, 128, 128).to(device) model = DEGConv(in_dim=64, nbins=8).to(device) print(model) print("CSDN:AI魔改大王") output = model(input) print('DEGConv input_size:', input.size()) print('DEGConv output_size:', output.size())