保边滤波器(Edge Preserving Filter)是指在滤波过程中能够有效的保留图像中的边缘信息的一类特殊滤波器。其中双边滤波器(Bilateral filter)、引导滤波器(Guided image filter)、加权最小二乘法滤波器(Weighted least square filter)为几种比较广为人知的保边滤波器。下面对每种滤波器进行一一介绍。
Bilateral的意思是:Affecting or undertaken by two sides equally,表示由双方(边)平等共同决定,有点类似于地位平等的双边谈判的感觉。双边滤波器中地位平等的双边即是指滤波的最终结果由像素值(值域)和像素位置(空域)来共同决定。最为常见的高斯平滑滤波器就是由像素位置单边决定的滤波器,其表达式如下:
双边滤波器中的一边即为上述常见的高斯平滑滤波器,两个像素物理距离越大则权值越小,反之则权值越大。双边滤波器中另一边则由像素值值域决定,两个像素,值相差越小,那么越不可能是边缘,那么越应该对其进行平滑处理,也就是应该提高其在滤波器中的权值(类似于空域中距离越近)而反之,像素值相差越大则越有可能是边缘,则应该尽力保留(类似于空域中距离越远),类比上面的公式,可以得到值域的高斯滤波器如下:
双边滤波器由上述两个滤波器共同决定,因此其最终形式为:
function [ tonedMap ] = navieBilateral( radMap,dw,rw,dsigma,rsigma)
% NAVIEBILATERAL Summary of this function goes here
% Detailed explanation goes here
% radmap为照度图像,dw和dr分别为空域和值域的滤波器大小
% dsigma和rsigma分别为空域和值域的高斯sigma因子
% 首先生成空域的高斯滤波器权重因子
[x,y] = meshgrid(-dw:dw,-dw:dw);
g1 = exp(-(x.^2+y.^2)/(2*dsigma^2));
% 对图像进行对称扩张,保证在图像的边缘仍然可以进行处理
pw = max(dw,rw);
padradMap = padarray(radMap,[pw pw],'symmetric');
dim = size(padradMap);
tonedMap = zeros(dim(1)-pw,dim(2)-pw);
for i= pw+1:dim(1)-pw
for j=pw+1:dim(2)-pw
I = padradMap(i-rw:i+rw,j-rw:j+rw); %取相应图像块
g2 = exp(-(I-padradMap(i,j)).^2/(2*rsigma^2)); %值域滤波因子生成
w = g1(:).*g2(:); %生成双边因子
tonedMap(i-pw,j-pw) = sum(w.*I(:))/sum(w);
end
end
end
双边滤波器利用了一个值域的高斯函数来调整滤波器在遇到图像边缘时的表现,使其在图像的一般区域表现出平滑性,同时在边缘区域尽量消除其平滑性,我们通过一个简单的实验来理解这一过程。
双边滤波器可以用于HDR图像压缩,其压缩原理很简单,HDR图像经过双边滤波器滤波以后得到一个Base layer,原始图像与Base layer之差则为Detail layer,对base layer进行压缩以后再将detail layer叠加上去就可以得到压缩后的图像。
% Implementation of "Fast Bilateral Filtering for the Display of High-Dynamic-Range Images"
% Input "radmap" must be of type double!
function tonedImage = toneMapDurand(radmap,dw,rw,dsigma,rsigma,contrast)
%首先分离图像的baselayer和detaillayer
radmap = log10(radmap);
base = navieBilateral(radmap,dw,rw,dsigma,rsigma);
detail = radmap - base;
logmax = max(base(:));
logmin = min(base(:));
compressionFactor = log10(contrast)/(logmax-logmin);
log_absolute_scale = logmax*compressionFactor;
log_compressed = base * compressionFactor + detail - log_absolute_scale;
tonedImage = 10.^(log_compressed);
end
上述过程中,通过双边滤波器所得到的base layer其实就是HDR图像中存在的一些明显的大起伏,举个例子,HDR图像就像我国地势一样,动态分布很大,错综复杂,任何一个地区都是高低起伏不定的,但是通过双边滤波器以后,可以把我国的地势大体看成西部高原,中部丘陵,东部平原,这三个台阶就是所谓的base layer。在base layer的基础上,一些局部的高低变化,比如平原地区的小山峰,丘陵地区的盆地,这些就是detail layer。对HDR图像的压缩,就是压缩西部高原,中部丘陵,东部平原三者之间的高度差。
原始双边滤波器的计算量是很大的,因为针对每一个像素在其领域都要在值域计算高斯函数来得到权重因子,这也限制了其发展。
引导滤波器是利用优化方法解决保边滤波的问题。所谓保边,也就是保持梯度的相对性,引导滤波器的一个重要假设就是认为,保边滤波后的结果和引导图像在滤波窗口内呈现线性关系:
解出 ak 的值如下:
上式分子中 1|ω|∑i∈ωkIi=μk ,分母中, 1|ω|∑i∈ωkI2i−1|ω|∑i∈ωkIiμk=E(I2)−E(I)2=σ2k ,也就是窗口 ω 中像素的方差。因此,参数 a 最终的表达是如下:
一般情况下,我们所使用的引导图像就是图像本身,也就是 I≡p ,那么 ak=σ2k/(σ2k+ϵ) , bk=(1−ak)μk ,考虑窗口内“高方差”和“低方差”的两种情况:
“高方差”: σ2k≫ϵ ,那么 ak≈1 , bk≈0
“低方差”: σ2k≪ϵ ,那么 ak≈0 , bk≈μk
也就是,在高方差的地方,保持梯度,在低方差的时候尽量平滑(取值为平均值),这和我们的前面的期望是一样的。
然而,如果滤波窗口为 w ,那么任意一个像素都存在 w×w 个窗口包含它,也就是说存在 w×w 个上述 ak 和 bk ,为了处理该问题,最简单的方式就是将这些值做平均:
其中 a⎯⎯i 为所有包含像素 i 的窗口所得 ak 的平均值,也就是:
这一步的非常有必要,如果每个像素的输出值仅仅由使其为窗口中心窗口所对应的 ak 和 bk 决定,图像很容易存在artifacts,这样做的目的其实是对所有映射进行平滑,消除图像的artifacts。那么我们在matlab中如何实现引导滤波器呢?首先,对每一个像素求导其对应的 ak 和 bk 系数:
对于给定的一幅图像 g ,如果一方面希望输出图像 u 与其很接近,另一方面又希望在除了边缘的地方越平滑越好 g ,全局来看,这是两个矛盾的东西,加权最小二乘法的作者认为,最优化这对矛盾的方式就是最小化下面的Cost function:
其中 p 表示像素的物理位置, (up−gp)2 这一项就是约束让输入和输出尽量接近,后面的一项则是为了让输出 u 在两个方向的导数越小越好,也就是越平滑越好。当然,平滑的贡献由 ax,p 和 ay,p 两个权重因子控制。 λ 控制还原度和平滑度之间的权重。因为在图像中,一维梯度表示为 ∂u∂x 或者 ∂u∂y ,也就是在 u 上施加的一个算子 ∂∂x 或者 ∂∂y , 那么我们可以认为 ∂u∂x 等效应 f(u) , f 就是这算子 ∂∂x 或者 ∂∂x 。因为在图像中这两个算子在任何位置都是不变的,我们姑且认为它们是常量,这样 ∂u∂x 可以写成 ∂∂xu ,这样,我们就可以对 u 进行求导,根据链式法则:
上面的表示中,两次一阶梯度算子等于一次二阶梯度算子,同样的,将其看做常量,因此进一步化简:
当上式等于0时,损失函数值最小,也就是:
文中,上式中 ax 和 ay 分别如下:
其中, l 为图像经过log运算后结果, α 取值在1.2到2.0之间,用于控制其对梯度的敏感度, ϵ 是用于防止出现计算结果出现0的一个极小值。