如何在python中获得高斯滤波器

Posted

技术标签:

【中文标题】如何在python中获得高斯滤波器【英文标题】:How to obtain a gaussian filter in python 【发布时间】:2013-06-15 22:51:58 【问题描述】:

我正在使用 python 创建一个大小为 5x5 的高斯滤波器。 我看到了这篇文章here,他们在其中谈论了类似的事情,但我没有找到获得与 matlab 函数 fspecial('gaussian', f_wid, sigma) 等效的 python 代码的确切方法 还有其他方法吗? 我尝试使用以下代码:

size = 2
sizey = None
size = int(size)
if not sizey:
    sizey = size
else:
    sizey = int(sizey)
x, y = scipy.mgrid[-size: size + 1, -sizey: sizey + 1]
g = scipy.exp(- (x ** 2/float(size) + y ** 2 / float(sizey)))
print g / np.sqrt(2 * np.pi)

得到的输出是

[[ 0.00730688  0.03274718  0.05399097  0.03274718  0.00730688]
 [ 0.03274718  0.14676266  0.24197072  0.14676266  0.03274718]
 [ 0.05399097  0.24197072  0.39894228  0.24197072  0.05399097]
 [ 0.03274718  0.14676266  0.24197072  0.14676266  0.03274718]
 [ 0.00730688  0.03274718  0.05399097  0.03274718  0.00730688]]

我想要的是这样的:

   0.0029690   0.0133062   0.0219382   0.0133062   0.0029690
   0.0133062   0.0596343   0.0983203   0.0596343   0.0133062
   0.0219382   0.0983203   0.1621028   0.0983203   0.0219382
   0.0133062   0.0596343   0.0983203   0.0596343   0.0133062
   0.0029690   0.0133062   0.0219382   0.0133062   0.0029690

【问题讨论】:

Creating Gaussian filter of required length in python 和 astrolitterbox.blogspot.co.uk/2012/04/… 的可能重复 我正在使用博客中提到的代码。我设置了N = 2 and sigma = 1 并使用以下代码:size = 2 sizey = None size = int(size) if not sizey: sizey = size else: sizey = int(sizey) x, y = scipy.mgrid[-size: size + 1, -sizey: sizey + 1] g = scipy.exp( - (x ** 2/float(size) + y ** 2 / float(sizey)) / 2) print g / np.sqrt(2 * np.pi) 但是这里得到的结果与在matlab中使用 fspecial 得到的结果不同 有什么不同?你期望什么,你会得到什么? 我已将其包含在问题中。请再次检查。 【参考方案1】:

使用高斯 PDF 并假设空间不变模糊

def gaussian_kernel(sigma, size):
    mu = np.floor([size / 2, size / 2])
    size = int(size)
    kernel = np.zeros((size, size))
    for i in range(size):
        for j in range(size):
            kernel[i, j] = np.exp(-(0.5/(sigma*sigma)) * (np.square(i-mu[0]) + 
            np.square(j-mu[0]))) / np.sqrt(2*math.pi*sigma*sigma)```

    kernel = kernel/np.sum(kernel)
    return kernel

【讨论】:

【参考方案2】:

这里是提供一个nd-gaussian窗口生成器:

def gen_gaussian_kernel(shape, mean, var):
    coors = [range(shape[d]) for d in range(len(shape))]
    k = np.zeros(shape=shape)
    cartesian_product = [[]]
    for coor in coors:
        cartesian_product = [x + [y] for x in cartesian_product for y in coor]
    for c in cartesian_product:
        s = 0
        for cc, m in zip(c,mean):
            s += (cc - m)**2
        k[tuple(c)] = np.exp(-s/(2*var))
    return k

此函数将为您提供具有给定形状、中心和方差的非归一化高斯窗口。 例如: gen_gaussian_kernel(shape=(3,3,3),mean=(1,1,1),var=1.0) 输出->

[[[ 0.22313016  0.36787944  0.22313016]
  [ 0.36787944  0.60653066  0.36787944]
  [ 0.22313016  0.36787944  0.22313016]]

 [[ 0.36787944  0.60653066  0.36787944]
  [ 0.60653066  1.          0.60653066]
  [ 0.36787944  0.60653066  0.36787944]]

 [[ 0.22313016  0.36787944  0.22313016]
  [ 0.36787944  0.60653066  0.36787944]
  [ 0.22313016  0.36787944  0.22313016]]]

【讨论】:

如果形状只是 2D,这似乎不起作用......也就是在我想生成单个高斯内核的情况下。 @Will.Evo 它也适用于 2d 吗?我不明白为什么它不适用于 2d 案例。尝试运行 gen_gaussian_kernel((5, 5), (1.0, 1.0), 1.0)【参考方案3】:

嘿,我想这可能对你有帮助

import numpy as np
import cv2

def gaussian_kernel(dimension_x, dimension_y, sigma_x, sigma_y):
    x = cv2.getGaussianKernel(dimension_x, sigma_x)
    y = cv2.getGaussianKernel(dimension_y, sigma_y)
    kernel = x.dot(y.T)
    return kernel
g_kernel = gaussian_kernel(5, 5, 1, 1)
print(g_kernel)

[[0.00296902 0.01330621 0.02193823 0.01330621 0.00296902]
 [0.01330621 0.0596343  0.09832033 0.0596343  0.01330621]
 [0.02193823 0.09832033 0.16210282 0.09832033 0.02193823]
 [0.01330621 0.0596343  0.09832033 0.0596343  0.01330621]
 [0.00296902 0.01330621 0.02193823 0.01330621 0.00296902]]

【讨论】:

【参考方案4】:

您也可以尝试这个(作为 2 个独立的 1D 高斯随机变量的乘积)来获得 2D 高斯核:

from numpy import pi, exp, sqrt
s, k = 1, 2 #  generate a (2k+1)x(2k+1) gaussian kernel with mean=0 and sigma = s
probs = [exp(-z*z/(2*s*s))/sqrt(2*pi*s*s) for z in range(-k,k+1)] 
kernel = np.outer(probs, probs)
print kernel

#[[ 0.00291502  0.00792386  0.02153928  0.00792386  0.00291502]
#[ 0.00792386  0.02153928  0.05854983  0.02153928  0.00792386]
#[ 0.02153928  0.05854983  0.15915494  0.05854983  0.02153928]
#[ 0.00792386  0.02153928  0.05854983  0.02153928  0.00792386]
#[ 0.00291502  0.00792386  0.02153928  0.00792386  0.00291502]]

import matplotlib.pylab as plt
plt.imshow(kernel)
plt.colorbar()
plt.show()

【讨论】:

【参考方案5】:

您好,我认为问题在于,对于高斯滤波器,归一化因子取决于您使用了多少维。 所以过滤器看起来像这样 你错过的是归一化因子的平方!并且由于计算精度需要重新归一化整个矩阵! 代码附在这里:

def gaussian_filter(shape =(5,5), sigma=1):
    x, y = [edge /2 for edge in shape]
    grid = np.array([[((i**2+j**2)/(2.0*sigma**2)) for i in xrange(-x, x+1)] for j in xrange(-y, y+1)])
    g_filter = np.exp(-grid)/(2*np.pi*sigma**2)
    g_filter /= np.sum(g_filter)
    return g_filter
print gaussian_filter()

未归一化为 1 的输出:

[[ 0.00291502  0.01306423  0.02153928  0.01306423  0.00291502]
 [ 0.01306423  0.05854983  0.09653235  0.05854983  0.01306423]
 [ 0.02153928  0.09653235  0.15915494  0.09653235  0.02153928]
 [ 0.01306423  0.05854983  0.09653235  0.05854983  0.01306423]
 [ 0.00291502  0.01306423  0.02153928  0.01306423  0.00291502]]

输出除以 np.sum(g_filter):

[[ 0.00296902  0.01330621  0.02193823  0.01330621  0.00296902]
 [ 0.01330621  0.0596343   0.09832033  0.0596343   0.01330621]
 [ 0.02193823  0.09832033  0.16210282  0.09832033  0.02193823]
 [ 0.01330621  0.0596343   0.09832033  0.0596343   0.01330621]
 [ 0.00296902  0.01330621  0.02193823  0.01330621  0.00296902]]

【讨论】:

【参考方案6】:

我为这个问题找到了类似的解决方案:

def fspecial_gauss(size, sigma):

    """Function to mimic the 'fspecial' gaussian MATLAB function
    """

    x, y = numpy.mgrid[-size//2 + 1:size//2 + 1, -size//2 + 1:size//2 + 1]
    g = numpy.exp(-((x**2 + y**2)/(2.0*sigma**2)))
    return g/g.sum()

【讨论】:

这是被否决的原因吗?它似乎是正确的(而且更简洁) 我使用这个函数,它有最接近 Matlab 输出的值。谢谢。【参考方案7】:

该函数实现的功能类似于matlab中的fspecial功能

http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.get_window.html 从 scipy 导入信号

>>>signal.get_window(('gaussian',2),3)
>>>array([ 0.8824969,  1.       ,  0.8824969])

这个函数似乎只生成一维内核

我猜你可以自己实现代码来生成高斯掩码,就像其他人指出的那样。

【讨论】:

【参考方案8】:

一般而言,如果您真的很想获得与 MATLAB 完全相同的结果,实现这一目标的最简单方法通常是直接查看 MATLAB 函数的源代码。

在这种情况下,edit fspecial

...
  case 'gaussian' % Gaussian filter

     siz   = (p2-1)/2;
     std   = p3;

     [x,y] = meshgrid(-siz(2):siz(2),-siz(1):siz(1));
     arg   = -(x.*x + y.*y)/(2*std*std);

     h     = exp(arg);
     h(h<eps*max(h(:))) = 0;

     sumh = sum(h(:));
     if sumh ~= 0,
       h  = h/sumh;
     end;
...

很简单,嗯?将其移植到 Python 只需

import numpy as np

def matlab_style_gauss2D(shape=(3,3),sigma=0.5):
    """
    2D gaussian mask - should give the same result as MATLAB's
    fspecial('gaussian',[shape],[sigma])
    """
    m,n = [(ss-1.)/2. for ss in shape]
    y,x = np.ogrid[-m:m+1,-n:n+1]
    h = np.exp( -(x*x + y*y) / (2.*sigma*sigma) )
    h[ h < np.finfo(h.dtype).eps*h.max() ] = 0
    sumh = h.sum()
    if sumh != 0:
        h /= sumh
    return h

这给了我与 fspecial 相同的答案,在舍入误差内:

 >> fspecial('gaussian',5,1)

 0.002969     0.013306     0.021938     0.013306     0.002969
 0.013306     0.059634      0.09832     0.059634     0.013306
 0.021938      0.09832       0.1621      0.09832     0.021938
 0.013306     0.059634      0.09832     0.059634     0.013306
 0.002969     0.013306     0.021938     0.013306     0.002969

 : matlab_style_gauss2D((5,5),1)

array([[ 0.002969,  0.013306,  0.021938,  0.013306,  0.002969],
       [ 0.013306,  0.059634,  0.09832 ,  0.059634,  0.013306],
       [ 0.021938,  0.09832 ,  0.162103,  0.09832 ,  0.021938],
       [ 0.013306,  0.059634,  0.09832 ,  0.059634,  0.013306],
       [ 0.002969,  0.013306,  0.021938,  0.013306,  0.002969]])

【讨论】:

这正是我想要的。你真的让它变得简单了。谢谢:) @ali_m 我不太明白这一行h[ h &lt; np.finfo(h.dtype).eps*h.max() ] = 0 我看了看文档,它似乎可以防止机器限制错误(?)。 d.type 参数是否必要?还有你为什么用.eps h.max 相乘。很抱歉提出这么旧的帖子。 也可以使用 cv2 和以下 2 个衬里:u = c.getGaussianKernel(5, 1); kernel = np.outer(u, u)。我得到了和上面一样的结果。

以上是关于如何在python中获得高斯滤波器的主要内容,如果未能解决你的问题,请参考以下文章

python图像处理(高斯滤波)

在matlab中使用高斯滤波器进行图像去模糊,没有加性噪声

加性高斯白噪声及维纳滤波的基本原理与Python实现

高斯滤波

sigma滤波是高斯滤波吗

如何用python实现图像的一维高斯滤波