基于可学习参数的深度导向滤波器 Deep Guide Filter

深度导向滤波器


这是一篇传统方法和深度学习方法结合的算法,他在引导滤波器(关于这块可查阅我之前的文章)上融入了可学习的参数,从而赋予了更强大的拟合能力,从而可以应用在多个图像处理任务上

关于 Deep Guide Filter (后文简称 DFG)其实有很多博客文章都有,我阅读论文和相关博文后做了整合并加上了自己的思考和理解。

首先我们来看看 DFG 能应用到什么场景上去,文中给出了例子,从左到右分别是图像修复和增强,超分辨率,图像去雾,图像显著区域检测,深度估计

基于可学习参数的深度导向滤波器 Deep Guide Filter

文邹邹一点的说法是,DFG 可以解决 Joint Upsampling 任务,给它一个高分辨率的输入图像 I h I_{h} Ih​ 和一个低分辨率输出图像 O l O_{l} Ol​,算法可以输出高分辨率的图像 O h O_{h} Oh​,他的细节和边缘与 I h I_{h} Ih​相似。具体的 DGF 层结构和梯度计算如下图所示。

基于可学习参数的深度导向滤波器 Deep Guide Filter

源码解析,参数在哪里

可能还是不太明白 DGF 是如何运行的,那么再来看看作者公开的源码

class ConvGuidedFilter(nn.Module):
    def __init__(self, radius=1, norm=nn.BatchNorm2d):
        super(ConvGuidedFilter, self).__init__()
        # 其实这个就是 Mean Filter
        self.box_filter = nn.Conv2d(3, 3, kernel_size=3, padding=radius, dilation=radius, bias=False, groups=3)
        self.conv_a = nn.Sequential(nn.Conv2d(6, 32, kernel_size=1, bias=False),
                                    norm(32),
                                    nn.ReLU(inplace=True),
                                    nn.Conv2d(32, 32, kernel_size=1, bias=False),
                                    norm(32),
                                    nn.ReLU(inplace=True),
                                    nn.Conv2d(32, 3, kernel_size=1, bias=False))
        self.box_filter.weight.data[...] = 1.0

    def forward(self, x_lr, y_lr, x_hr):
        _, _, h_lrx, w_lrx = x_lr.size()
        _, _, h_hrx, w_hrx = x_hr.size()

        N = self.box_filter(x_lr.data.new().resize_((1, 3, h_lrx, w_lrx)).fill_(1.0))
				# 下面几个计算公式与引导滤波一致
        # mean_x
        mean_x = self.box_filter(x_lr)/N
        # mean_y
        mean_y = self.box_filter(y_lr)/N
        # cov_xy
        cov_xy = self.box_filter(x_lr * y_lr)/N - mean_x * mean_y
        # var_x
        var_x  = self.box_filter(x_lr * x_lr)/N - mean_x * mean_x

        # A 这里引入了卷积求解 ak
        A = self.conv_a(torch.cat([cov_xy, var_x], dim=1))
        # b
        b = mean_y - A * mean_x

        # 最终用双线性插值,放大特征图,获得最终的大尺寸的输出 O_H
        mean_A = F.interpolate(A, (h_hrx, w_hrx), mode='bilinear', align_corners=True)
        mean_b = F.interpolate(b, (h_hrx, w_hrx), mode='bilinear', align_corners=True)

        return mean_A * x_hr + mean_b

结合源码,其实就很好理解了,他是在原来的引导滤波中加入了卷积,从而使得 a k a_{k} ak​和 b k b_{k} bk​ 求解的参数是学习而来的,这里我贴一下引导滤波中最终推到出来的计算 a k a_{k} ak​和 b k b_{k} bk​的公式。

这里复习一下导向滤波,它的一个重要的假设是在滤波窗口上存在线性的关系,如下式子,I 是导向图

q i = a k I i + b k q_{i} = a_{k}I_{i}+b_{k} qi​=ak​Ii​+bk​

最终 a k a_{k} ak​ 和 b k b_{k} bk​ 的解可以表示如下,关于引导滤波更详解的讲解和实现,可移步看之前的博客文章 - 美颜磨皮算法之保边(双边&引导)滤波器原理及 Python 实现

a k = I k p k − u k p k σ k 2 + ϵ a_{k}=\frac{I_{k}p_{k}-u_{k}p_{k}}{\sigma_{k}^{2}+\epsilon} ak​=σk2​+ϵIk​pk​−uk​pk​​

b k = ( 1 − a k ) p k b_{k}=(1-a_{k})p_{k} bk​=(1−ak​)pk​

这里,Pk 是原图,ϵ 用来界定平滑和边缘区域的阈值,那么不难看出,源码中的 A 和 B 计算的方法就是上面公式所表达的。

架构上对比传统的引导滤波有两点改进

  1. 对比传统 DGF,引入卷积求解 a k a_{k} ak​和 b k b_{k} bk​,让它可以适应更多的任务,实现 end-to-end 的训练
  2. 避免计算 a k a_{k} ak​和 b k b_{k} bk​ 计算量太大,首先在小分辨率上求解,然后 resize 到大尺寸上,提高算法效率

这里我截取了论文中在语义分割中应用 DGF 后的效果,如下图所示:

基于可学习参数的深度导向滤波器 Deep Guide Filter

使用了 DGF 后,分割效果在边缘处感觉甚至比 Ground Truth 都还会更好一些

不仅在精度上会有提升,DGF 在效率上也很快

基于可学习参数的深度导向滤波器 Deep Guide Filter

最新的 SOTA 人像分割网络 RVM 也用到了 DGF 来输出更大精度更高的 Mask 图。

参考链接


论文链接

https://arxiv.org/pdf/2108.11515.pdf

官方 pytorch 实现

https://github.com/wuhuikai/DeepGuidedFilter/blob/master/GuidedFilteringLayer/GuidedFilter_PyTorch/guided_filter_pytorch/guided_filter.py

上一篇:从零开肝Vue2.0(准备工作)


下一篇:Guide Spring学习记录