深度导向滤波器
这是一篇传统方法和深度学习方法结合的算法,他在引导滤波器(关于这块可查阅我之前的文章)上融入了可学习的参数,从而赋予了更强大的拟合能力,从而可以应用在多个图像处理任务上
关于 Deep Guide Filter (后文简称 DFG)其实有很多博客文章都有,我阅读论文和相关博文后做了整合并加上了自己的思考和理解。
首先我们来看看 DFG 能应用到什么场景上去,文中给出了例子,从左到右分别是图像修复和增强,超分辨率,图像去雾,图像显著区域检测,深度估计
文邹邹一点的说法是,DFG 可以解决 Joint Upsampling 任务,给它一个高分辨率的输入图像 I h I_{h} Ih 和一个低分辨率输出图像 O l O_{l} Ol,算法可以输出高分辨率的图像 O h O_{h} Oh,他的细节和边缘与 I h I_{h} Ih相似。具体的 DGF 层结构和梯度计算如下图所示。
源码解析,参数在哪里
可能还是不太明白 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=akIi+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+ϵIkpk−ukpk
b k = ( 1 − a k ) p k b_{k}=(1-a_{k})p_{k} bk=(1−ak)pk
这里,Pk 是原图,ϵ 用来界定平滑和边缘区域的阈值,那么不难看出,源码中的 A 和 B 计算的方法就是上面公式所表达的。
架构上对比传统的引导滤波有两点改进
- 对比传统 DGF,引入卷积求解 a k a_{k} ak和 b k b_{k} bk,让它可以适应更多的任务,实现 end-to-end 的训练
- 避免计算 a k a_{k} ak和 b k b_{k} bk 计算量太大,首先在小分辨率上求解,然后 resize 到大尺寸上,提高算法效率
这里我截取了论文中在语义分割中应用 DGF 后的效果,如下图所示:
使用了 DGF 后,分割效果在边缘处感觉甚至比 Ground Truth 都还会更好一些
不仅在精度上会有提升,DGF 在效率上也很快
最新的 SOTA 人像分割网络 RVM 也用到了 DGF 来输出更大精度更高的 Mask 图。
参考链接
论文链接
https://arxiv.org/pdf/2108.11515.pdf
官方 pytorch 实现