简介
描述
高斯模糊:使用高斯函数求出的值来作为卷积核进行图像的卷积运算。
卷积核总结:
- 对图像进行降维以及特征提取,一般用于人工智能。
- 行数和列数均为奇数的矩阵。
- 卷积核元素的总和体现出输出的亮度。
高斯分布
f
(
x
)
=
1
2
π
σ
2
e
−
(
x
−
μ
)
2
2
σ
2
f(x)=\frac{1}{\sqrt{2\pi\sigma^2}} {e^{-\frac{(x-\mu)^2}{2\sigma^2}}}
f(x)=2πσ21e−2σ2(x−μ)2
高斯函数
G
(
r
)
=
1
2
π
σ
2
N
e
−
r
2
2
σ
2
G(r)=\frac{1}{\sqrt{2\pi\sigma^2}^{N}} {e^{-\frac{r^2}{2\sigma^2}}}
G(r)=2πσ2N1e−2σ2r2
σ
\sigma
σ是正态函数的标准差,
r
r
r代表模板中元素到模板中心的距离,又称为模糊半径,
N
N
N代表处于
N
N
N维空间。
模糊半径
定义:欧式距离(N维向量的模)。
欧几里得度量(euclidean metric)也称欧氏距离,是一个通常采用的距离定义,指在m维空间中两个点之间的真实距离,或者向量的自然长度(即该点到原点的距离)。
卷积运算
卷积核
原图像
卷积结果
从原图像中提取与卷积同等大小的矩阵与卷积核进行矩阵相乘运算。
6
=
(
0
−
2
+
0
)
+
(
−
2
+
20
−
8
)
+
(
0
−
2
+
0
)
6=(0-2+0)+(-2+20-8)+(0-2+0)
6=(0−2+0)+(−2+20−8)+(0−2+0)
细节
卷积处理后,图像的每条边少了一个像素。
解决:将已有的点拷贝到另一面的对应位置,也就是填充边。
高斯函数卷积核
假设
σ
=
1.5
\sigma=1.5
σ=1.5,高斯卷积核如下。
实现
Python计算卷积核
import math
pi = 3.1415926
sigma = 1.5
e = 2.7182804
def G(r):
return (1 / pow(math.sqrt(2 * pi * pow(sigma, 2)), 2)) * pow(e, -((r*r) / (2 * pow(sigma, 2))))
print("G(2) = %.7f" % G(2)) # G(2) = 0.0290803
print("G(1) = %.7f" % G(1)) # G(1) = 0.0566406
print("G(0) = %.7f" % G(0)) # G(0) = 0.0707355
OpenGL卷积核实现
#iChannel0 "file://images/img.jpg" // 与shader脚本文件在同级目录下
// 高斯函数用到的常量
const float pi = 3.1415926;
const float sigma = 1.5;
const float e = 2.7182804;
// 高斯函数, r为欧式距离
float G(float r) {
return (1.0 / pow(sqrt(2.0 * pi * pow(sigma, 2.0)), 2.0)) * pow(e, -((r*r) / (2.0 * pow(sigma, 2.0))));
}
// 主函数
void mainImage(out vec4 fragColor, in vec2 fragCoord) {
// 计算uv, iResolution.xy是screen大小
vec2 uv = fragCoord.xy / iResolution.xy;
// 模拟像素
vec2 pixed = 2.0 / iResolution.xy;
// 相邻像素的uv
vec2 texcoords[9];
texcoords[0] = uv + vec2(-1.0, -1.0) * pixed;
texcoords[1] = uv + vec2(0.0, -1.0) * pixed;
texcoords[2] = uv + vec2(1.0, -1.0) * pixed;
texcoords[3] = uv + vec2(-1.0, 0.0) * pixed;
texcoords[4] = uv + vec2(0.0, 0.0) * pixed;
texcoords[5] = uv + vec2(1.0, 0.0) * pixed;
texcoords[6] = uv + vec2(-1.0, 1.0) * pixed;
texcoords[7] = uv + vec2(0.0, 1.0) * pixed;
texcoords[8] = uv + vec2(1.0, 1.0) * pixed;
// 相邻像素对应的权重, 卷积核
float w[9];
w[0] = w[2] = w[6] = w[8] = G(2.0);
w[1] = w[3] = w[5] = w[7] = G(1.0);
w[4] = G(0.0);
// 权重总和, 用来归一化卷积核
float totalWeight = w[0] * 4.0 + w[1] * 4.0 + w[4];
// 卷积运算
vec4 gaussColor = vec4(0.0);
for (int i = 0; i < 9; i++) {
gaussColor += texture2D(iChannel0, texcoords[i]) * w[i] / totalWeight;
}
// 原图
vec4 originalColor = texture2D(iChannel0, uv);
// sin + time动态变化
float normalTime = abs(sin(iTime));
// mix输出颜色
fragColor = mix(originalColor, gaussColor, normalTime);
}
OpenGL高斯模糊优化
优化点:
- 在片元着色器会重复计算卷积核,比较耗时;可以放在CPU计算,传给shader。
-
3
×
3
3 \times 3
3×3卷积就需要在片元中纹理采样9次,可以降低为6次。
- 先进行横向模糊,采样3次,存储横向结果texture。
- 横向结果texture再进行纵向模糊,采样3次。