# 双边滤波函数

既然高斯模糊没有良好地保留边界,我们就选取一个能够保边去噪的滤波器,高斯双边滤波算法就是这样的一个滤波器。高斯模糊仅仅考虑了像素的空间分布,权重从中间向周边降低。而双边滤波则进一步考虑了图像的像素值,从而保证边缘部分不会被过滤掉。根据维基百科 [3][3],一个双边滤波器定义为:

Ifiltered(x)=1WpΣxiΩI(xi)fr(I(xi)I(x))gs(xix)(8)Ifiltered(x)=1WpΣxi∈ΩI(xi)fr(||I(xi)−I(x)||)gs(||xi−x||)(8)

Ifiltered(x)=1WpΣxiΩI(xi)fr(I(xi)I(x))gs(xix)Ifiltered(x)=1WpΣxi∈ΩI(xi)fr(||I(xi)−I(x)||)gs(||xi−x||)

其中,Ifiltered (x) 是过滤后的图像,x 是被过滤的像素坐标,Ω 是像素 x 的滤波核领域,I (x) 是初始未被过滤的图像。然后 fr 是域值权重函数,gr 是空间权重函数。而 Wp 是归一化因子,其计算方式如下:

Wp=ΣxiΩfr(I(xi)I(x))gs(xix)(9)Wp=Σxi∈Ωfr(||I(xi)−I(x)||)gs(||xi−x||)(9)

Wp=ΣxiΩfr(I(xi)I(x))gs(xix)Wp=Σxi∈Ωfr(||I(xi)−I(x)||)gs(||xi−x||)

可以看到 fr 函数输入的是两个像素之间的差,而 gs 输入的是两个像素坐标之间的差。考虑一个像素,其坐标为 (i,j),而其邻域像素的坐标为 (k,l),则计算与邻域像素 (k,l) 的滤波核函数为:

w(i,j,k,l)=exp((ik)2+(jl)22σ2dI(i,j)I(k,l)22σ2r)(10)w(i,j,k,l)=exp(−(i−k)2+(j−l)22σ2d−||I(i,j)−I(k,l)||22σ2r)(10)

w(i,j,k,l)=exp((ik)2+(jl)22σd2I(i,j)I(k,l)22σr2)w(i,j,k,l)=exp(−(i−k)2+(j−l)22σd2−||I(i,j)−I(k,l)||22σr2)

公式给出的核函数包含了 frfr 和 gsgs,其中左边部分就是 gsgs,而右边部分则为 frfr。在片元着色器中,我实现的双边滤波函数如下所示。这是一个暴力的两重循环,因为图像的邻域是二维的。

“”
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#version 330 core

in vec2 Texcoord;

uniform sampler2D image;
uniform float filterRadius;

const float blurScale = 0.05f;
const float blurDepthFalloff = 500.0f;

void main(){
// gets size of single texel.
vec2 tex_offset = 1.0 / textureSize(image, 0);
float sum = 0.0f;
float wsum = 0.0f;
float value = texture(image, Texcoord).r;
for(float y = -filterRadius;y <= filterRadius;y += 1.0f)
{
for(float x = -filterRadius;x <= filterRadius;x += 1.0f)
{
float sample = texture(image, Texcoord + vec2(x, y) * tex_offset).r;
// spatial domain.
float r = length(vec2(x, y)) * blurScale;
float w = exp(-r * r);
// range domain.
float r2 = (sample - value) * blurDepthFalloff;
float g = exp(-r2 * r2);
sum += sample * w * g;
wsum += w * g;
}
}
if(wsum >= 0.0f)
sum /= wsum;
gl_FragDepth = sum;
}

更新于

请我喝[茶]~( ̄▽ ̄)~*

Natsuneko 微信支付

微信支付

Natsuneko 支付宝

支付宝

Natsuneko 贝宝

贝宝