How to calculate a Gaussian kernel matrix efficiently in numpy?

前端 未结 12 2186
名媛妹妹
名媛妹妹 2020-11-29 20:54
def GaussianMatrix(X,sigma):
    row,col=X.shape
    GassMatrix=np.zeros(shape=(row,row))
    X=np.asarray(X)
    i=0
    for v_i in X:
        j=0
        for v_j i         


        
相关标签:
12条回答
  • 2020-11-29 21:10

    linalg.norm takes an axis parameter. With a little experimentation I found I could calculate the norm for all combinations of rows with

    np.linalg.norm(x[None,:,:]-x[:,None,:],axis=2)
    

    It expands x into a 3d array of all differences, and takes the norm on the last dimension.

    So I can apply this to your code by adding the axis parameter to your Gaussian:

    def Gaussian(x,z,sigma,axis=None):
        return np.exp((-(np.linalg.norm(x-z, axis=axis)**2))/(2*sigma**2))
    
    x=np.arange(12).reshape(3,4)
    GaussianMatrix(x,1)
    

    produces

    array([[  1.00000000e+00,   1.26641655e-14,   2.57220937e-56],
           [  1.26641655e-14,   1.00000000e+00,   1.26641655e-14],
           [  2.57220937e-56,   1.26641655e-14,   1.00000000e+00]])
    

    Matching:

    Gaussian(x[None,:,:],x[:,None,:],1,axis=2)
    
    array([[  1.00000000e+00,   1.26641655e-14,   2.57220937e-56],
           [  1.26641655e-14,   1.00000000e+00,   1.26641655e-14],
           [  2.57220937e-56,   1.26641655e-14,   1.00000000e+00]])
    
    0 讨论(0)
  • 2020-11-29 21:11

    A good way to do that is to use the gaussian_filter function to recover the kernel. For instance:

    indicatrice = np.zeros((5,5))
    indicatrice[2,2] = 1
    gaussian_kernel = gaussian_filter(indicatrice, sigma=1)
    gaussian_kernel/=gaussian_kernel[2,2]
    

    This gives

    array[[0.02144593, 0.08887207, 0.14644428, 0.08887207, 0.02144593],
           [0.08887207, 0.36828649, 0.60686612, 0.36828649, 0.08887207],
           [0.14644428, 0.60686612, 1.        , 0.60686612, 0.14644428],
           [0.08887207, 0.36828649, 0.60686612, 0.36828649, 0.08887207],
           [0.02144593, 0.08887207, 0.14644428, 0.08887207, 0.02144593]]
    
    0 讨论(0)
  • 2020-11-29 21:13

    I tried using numpy only. Here is the code

    def get_gauss_kernel(size=3,sigma=1):
        center=(int)(size/2)
        kernel=np.zeros((size,size))
        for i in range(size):
           for j in range(size):
              diff=np.sqrt((i-center)**2+(j-center)**2)
              kernel[i,j]=np.exp(-(diff**2)/(2*sigma**2))
        return kernel/np.sum(kernel)
    

    You can visualise the result using:

    plt.imshow(get_gauss_kernel(5,1))
    

    0 讨论(0)
  • 2020-11-29 21:15

    A 2D gaussian kernel matrix can be computed with numpy broadcasting,

    def gaussian_kernel(size=21, sigma=3):
        """Returns a 2D Gaussian kernel.
        Parameters
        ----------
        size : float, the kernel size (will be square)
    
        sigma : float, the sigma Gaussian parameter
    
        Returns
        -------
        out : array, shape = (size, size)
          an array with the centered gaussian kernel
        """
        x = np.linspace(- (size // 2), size // 2)
        x /= np.sqrt(2)*sigma
        x2 = x**2
        kernel = np.exp(- x2[:, None] - x2[None, :])
        return kernel / kernel.sum()
    

    For small kernel sizes this should be reasonably fast.

    Note: this makes changing the sigma parameter easier with respect to the accepted answer.

    0 讨论(0)
  • 2020-11-29 21:20

    I'm trying to improve on FuzzyDuck's answer here. I think this approach is shorter and easier to understand. Here I'm using signal.scipy.gaussian to get the 2D gaussian kernel.

    import numpy as np
    from scipy import signal
    
    def gkern(kernlen=21, std=3):
        """Returns a 2D Gaussian kernel array."""
        gkern1d = signal.gaussian(kernlen, std=std).reshape(kernlen, 1)
        gkern2d = np.outer(gkern1d, gkern1d)
        return gkern2d
    

    Plotting it using matplotlib.pyplot:

    import matplotlib.pyplot as plt
    plt.imshow(gkern(21), interpolation='none')
    

    0 讨论(0)
  • 2020-11-29 21:20

    Adapting th accepted answer by FuzzyDuck to match the results of this website: http://dev.theomader.com/gaussian-kernel-calculator/ I now present you with this definition:

    import numpy as np
    import scipy.stats as st
    
    def gkern(kernlen=21, sig=3):
        """Returns a 2D Gaussian kernel."""
    
        x = np.linspace(-(kernlen/2)/sig, (kernlen/2)/sig, kernlen+1)
        kern1d = np.diff(st.norm.cdf(x))
        kern2d = np.outer(kern1d, kern1d)
        return kern2d/kern2d.sum()
    
    print(gkern(kernlen=5, sig=1))
    

    output:

    [[0.003765   0.015019   0.02379159 0.015019   0.003765  ]
     [0.015019   0.05991246 0.0949073  0.05991246 0.015019  ]
     [0.02379159 0.0949073  0.15034262 0.0949073  0.02379159]
     [0.015019   0.05991246 0.0949073  0.05991246 0.015019  ]
     [0.003765   0.015019   0.02379159 0.015019   0.003765  ]]
    
    0 讨论(0)
提交回复
热议问题