高斯模糊是一种图像滤波器,它使用正态分布(高斯函数)计算模板值,并使用该模板与原图像做卷积运算,达到模糊图像的目的。
N维空间的正态分布如公式1-1所示
G
(
r
)
=
1
2
π
σ
2
e
−
r
2
(
2
σ
2
)
(
1
−
1
)
G(r)=\frac{1}{\sqrt{2 \pi \sigma^{2}} e^{-r^{2}\left(2 \sigma^{2}\right)}}(1-1)
G(r)=2πσ2e−r2(2σ2)1(1−1)
其中,
σ
\sigma
σ是正态分布的标准差,
σ
\sigma
σ值越大,进行高斯模糊后的图像越模糊(平滑)。r为模糊半径,模糊半径是指模板元素到模板中心的距离。
以下用二维模板举例,假设二维模板大小为
m
∗
n
m*n
m∗n,则模板元素上的元素
(
x
,
y
)
(x,y)
(x,y)对应的高斯计算公式为:
G
(
x
,
y
)
=
1
2
π
σ
2
e
−
(
x
−
m
/
2
)
2
+
(
y
−
n
/
2
)
2
2
σ
2
(
1
−
2
)
G(x, y)=\frac{1}{2 \pi \sigma^{2}} e^{-\frac{(x-m / 2)^{2}+(y-n / 2)^{2}}{2 \sigma^{2}}}(1-2)
G(x,y)=2πσ21e−2σ2(x−m/2)2+(y−n/2)2(1−2)
在二维空间中,这个公式生成的曲面的等高线是从中心开始呈正态分布的同心圆。分布不为零的像素组成的卷积矩阵与原始图像做变换。每个像素的值都是周围相邻像素值的加权平均。原始像素的值有最大的高斯分布值,所以有最大的权重,相邻像素随着距离原始像素越来越远,其权重也越来越小。这样进行模糊处理比其它的均衡模糊滤波器更高地保留了边缘效果。
理论上来讲,图像中每点的分布都不为零,这也就是说每个像素的计算都需要包含整幅图像。在实际应用中,在计算高斯函数的离散近似时,在大概3σ距离之外的像素都可以看作不起作用,这些像素的计算也就可以忽略。通常,图像处理程序只需要计算(6σ+1)*(6σ+1)的矩阵就可以保证相关像素影响。
import cv2
import numpy as np
def GaussianSmooth2D(image: np.ndarray, sigma: float):
'''
此程序用于高斯平滑灰度图像,图像不能是3维灰度图,只能是2维的。此外,本程序实现自动全零填充,输出维度跟输入维度一样。
image:二维图像,cv2的灰度读入
sigma:高斯核的标准差
'''
# 确保sigma为正数
sigma = sigma if sigma>0 else 0
# 高斯核矩阵大小为(6*sigma+1)*(6*sigma+1)
ksize = round(sigma * 3) * 2 + 1
if (ksize == 1):
return image
kernel = np.zeros((ksize, ksize))
scale = -0.5/(sigma * sigma)
cons = -scale / np.pi
sum = 0
for i in range(ksize):
for j in range(ksize):
x = i - (ksize - 1) / 2
y = j - (ksize - 1) / 2
temp = cons * np.exp(scale * (x*x + y*y))
kernel[i, j] = temp
sum += temp
# 归一化
kernel = kernel / sum
p = [ksize//2, ksize//2]
dst = np.pad(image, p, 'constant')
guassian_img = np.empty((image.shape))
for i in range(p[0], image.shape[0] + p[0]):
for j in range(p[1], image.shape[1] + p[1]):
guassian_img[i-p[0], j-p[1]] = np.sum(kernel * dst[i-p[0]:i+p[0]+1,j-p[1]:j+p[1]+1])
return guassian_img.astype(np.uint8)
自己手写的代码肯定比调官方库慢,但是有些时候还是需要理解其中的原理,重复造轮子也不是不行。