高斯核可通过 函数 cv2.getGaussianKernel 获得,但该函数只能生成一维高斯核
虽然不能直接通过函数获取二维高斯核,但是可以通过公式 kernel_x * kernel_y.T 计算得出(下面有例子)。
假设我们指定高斯核的尺寸为 7x7,kernel 的中心点像素坐标为 (3, 3)
sigma 可由公式计算得到: sigmaX = sigmY = 0.3 * ((ksize - 1) * 0.5 - 1) + 0.8 = 1.4
将每一个像素坐标 (0, 0), (0, 1)… 带入如下高斯函数,可以计算得到二维高斯核
f ( x ) = 1 2 π σ x σ y e − 1 2 [ ( x − μ ) 2 σ x 2 + ( y − μ ) 2 σ y 2 ] f(x) = \frac{1}{{2π} \sigma_x \sigma_y} e^{-\frac{1}{2} [\frac{(x-μ)^2}{\sigma_x^2} + \frac{(y-μ)^2}{\sigma_y^2}]} f(x)=2πσxσy1e−21[σx2(x−μ)2+σy2(y−μ)2] 因为 σ x = σ y \sigma_x = \sigma_y σx=σy ,公式简化为
f ( x ) = 1 2 π σ 2 e − ( x − μ ) 2 + ( y − μ ) 2 2 σ 2 f(x) = \frac{1}{{2π} \sigma^2} e^{-\frac{(x-μ)^2+(y-\mu)^2}{2\sigma^2}} f(x)=2πσ21e−2σ2(x−μ)2+(y−μ)2
下面举例,代码内容包括:
import cv2
import numpy as np
import math
"""
基础参数设置:
(1)我们指定高斯核的尺寸为 ksize=7x7
(2)sigma 可由公式计算得到: sigma = 0.3 * ((ksize - 1) * 0.5 - 1) + 0.8
"""
kernel_size = 7
sigma = 0.3 * ((kernel_size - 1) * 0.5 - 1) + 0.8
radium = kernel_size//2 # radium=3
""" 通过函数 cv2.getGaussianKernel 生成二维高斯核 """
kernel_1d = cv2.getGaussianKernel(ksize=kernel_size, sigma=sigma, ktype=cv2.CV_32F)
kernel_2d = kernel_1d * kernel_1d.T
print(kernel_2d)
""" 手撸高斯核,通过二维高斯公式计算得出 """
constant = 1/(2 * math.pi * sigma**2)
gaussian_kernel = np.zeros((kernel_size, kernel_size))
for i in range(0, kernel_size, 1):
for j in range(0, kernel_size, 1):
x = i-radium
y = j-radium
gaussian_kernel[i, j] = constant*math.exp(-0.5/(sigma**2)*(x**2+y**2))
gaussian_kernel = gaussian_kernel/gaussian_kernel.sum() # 归一化
print('\n', gaussian_kernel)
可以看出,我们自己的代码得出的结果和 cv2.getGaussianKernel 函数得出的结果是一样的
例子包括:
import cv2
import numpy as np
import copy
# 读取图片
image = cv2.imread('images/lena.bmp', 0)
cv2.imshow('original', image)
# 初始化参数
rows, cols = image.shape
sigma = 0.84089642
kernel_size = np.int(np.round(sigma*3)*2+1) # 一般高斯核尺寸通过计算得到:6*sigma+1 要保证尺寸的宽度和高度都为奇数
radium = kernel_size//2
# 通过函数 cv2.GaussianBlur 进行滤波处理(模糊处理)
result1 = cv2.GaussianBlur(image, ksize=(kernel_size, kernel_size), sigmaX=sigma)
cv2.imshow('result1', result1)
# 生成高斯核
kernel_1d = cv2.getGaussianKernel(ksize=kernel_size, sigma=sigma, ktype=cv2.CV_32F)
kernel_2d = kernel_1d * kernel_1d.T
# print(kernel_2d)
# 边缘保留原图想的像素值
result2 = copy.deepcopy(image)
for i in range(radium, rows-radium, 1):
for j in range(radium, rows-radium, 1):
result2[i, j] = (image[i-radium:i+radium+1, j-radium:j+radium+1] * kernel_2d).sum()
result2 = np.uint8(result2)
cv2.imshow('result2', result2)
cv2.waitKey()
cv2.destroyAllWindows()