【问题标题】:How to obtain a gaussian filter in python如何在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

【问题讨论】:

  • 我正在使用博客中提到的代码。我设置了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 得到的结果不同
  • 有什么不同?你期望什么,你会得到什么?
  • 我已将其包含在问题中。请再次检查。

标签: python matlab numpy gaussian


【解决方案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)。我得到了和上面一样的结果。
            猜你喜欢
            • 2023-04-03
            • 1970-01-01
            • 2012-10-22
            • 1970-01-01
            • 2013-03-29
            • 2014-10-02
            • 2011-02-15
            • 1970-01-01
            • 2018-10-03
            相关资源
            最近更新 更多