How to calculate a Gaussian kernel matrix efficiently in numpy?

前端 未结 12 2185
名媛妹妹
名媛妹妹 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 20:59

    Building up on Teddy Hartanto's answer. You can just calculate your own one dimensional Gaussian functions and then use np.outer to calculate the two dimensional one. Very fast and efficient way.

    With the code below you can also use different Sigmas for every dimension

    import numpy as np
    def generate_gaussian_mask(shape, sigma, sigma_y=None):
        if sigma_y==None:
            sigma_y=sigma
        rows, cols = shape
    
        def get_gaussian_fct(size, sigma):
            fct_gaus_x = np.linspace(0,size,size)
            fct_gaus_x = fct_gaus_x-size/2
            fct_gaus_x = fct_gaus_x**2
            fct_gaus_x = fct_gaus_x/(2*sigma**2)
            fct_gaus_x = np.exp(-fct_gaus_x)
            return fct_gaus_x
    
        mask = np.outer(get_gaussian_fct(rows,sigma), get_gaussian_fct(cols,sigma_y))
        return mask
    
    0 讨论(0)
  • 2020-11-29 21:00

    You may simply gaussian-filter a simple 2D dirac function, the result is then the filter function that was being used:

    import numpy as np
    import scipy.ndimage.filters as fi
    
    def gkern2(kernlen=21, nsig=3):
        """Returns a 2D Gaussian kernel array."""
    
        # create nxn zeros
        inp = np.zeros((kernlen, kernlen))
        # set element at the middle to one, a dirac delta
        inp[kernlen//2, kernlen//2] = 1
        # gaussian-smooth the dirac, resulting in a gaussian filter mask
        return fi.gaussian_filter(inp, nsig)
    
    0 讨论(0)
  • 2020-11-29 21:03

    If you are a computer vision engineer and you need heatmap for a particular point as Gaussian distribution(especially for keypoint detection on image)

    def gaussian_heatmap(center = (2, 2), image_size = (10, 10), sig = 1):
        """
        It produces single gaussian at expected center
        :param center:  the mean position (X, Y) - where high value expected
        :param image_size: The total image size (width, height)
        :param sig: The sigma value
        :return:
        """
        x_axis = np.linspace(0, image_size[0]-1, image_size[0]) - center[0]
        y_axis = np.linspace(0, image_size[1]-1, image_size[1]) - center[1]
        xx, yy = np.meshgrid(x_axis, y_axis)
        kernel = np.exp(-0.5 * (np.square(xx) + np.square(yy)) / np.square(sig))
        return kernel
    

    The usage and output

    kernel = gaussian_heatmap(center = (2, 2), image_size = (10, 10), sig = 1)
    plt.imshow(kernel)
    print("max at :", np.unravel_index(kernel.argmax(), kernel.shape))
    print("kernel shape", kernel.shape)
    

    max at : (2, 2)

    kernel shape (10, 10)

    kernel = gaussian_heatmap(center = (25, 40), image_size = (100, 50), sig = 5)
    plt.imshow(kernel)
    print("max at :", np.unravel_index(kernel.argmax(), kernel.shape))
    print("kernel shape", kernel.shape)
    

    max at : (40, 25)

    kernel shape (50, 100)

    0 讨论(0)
  • As I didn't find what I was looking for, I coded my own one-liner. You can modify it accordingly (according to the dimensions and the standard deviation).

    Here is the one-liner function for a 3x5 patch for example.

    from scipy import signal
    
    def gaussian2D(patchHeight, patchWidth, stdHeight=1, stdWidth=1):
        gaussianWindow = signal.gaussian(patchHeight, stdHeight).reshape(-1, 1)@signal.gaussian(patchWidth, stdWidth).reshape(1, -1)
        return gaussianWindow
    
    print(gaussian2D(3, 5))
    

    You get an output like this:

    [[0.082085   0.36787944 0.60653066 0.36787944 0.082085  ]
    [0.13533528  0.60653066 1.         0.60653066 0.13533528]
    [0.082085   0.36787944 0.60653066 0.36787944 0.082085  ]]
    

    You can read more about scipy's Gaussian here.

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

    I myself used the accepted answer for my image processing, but I find it (and the other answers) too dependent on other modules. Therefore, here is my compact solution:

    import numpy as np
    
    def gkern(l=5, sig=1.):
        """\
        creates gaussian kernel with side length l and a sigma of sig
        """
    
        ax = np.linspace(-(l - 1) / 2., (l - 1) / 2., l)
        xx, yy = np.meshgrid(ax, ax)
    
        kernel = np.exp(-0.5 * (np.square(xx) + np.square(yy)) / np.square(sig))
    
        return kernel / np.sum(kernel)
    

    Edit: Changed arange to linspace to handle even side lengths

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

    Do you want to use the Gaussian kernel for e.g. image smoothing? If so, there's a function gaussian_filter() in scipy:

    Updated answer

    This should work - while it's still not 100% accurate, it attempts to account for the probability mass within each cell of the grid. I think that using the probability density at the midpoint of each cell is slightly less accurate, especially for small kernels. See https://homepages.inf.ed.ac.uk/rbf/HIPR2/gsmooth.htm for an example.

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

    Testing it on the example in Figure 3 from the link:

    gkern(5, 2.5)*273
    

    gives

    array([[ 1.0278445 ,  4.10018648,  6.49510362,  4.10018648,  1.0278445 ],
           [ 4.10018648, 16.35610171, 25.90969361, 16.35610171,  4.10018648],
           [ 6.49510362, 25.90969361, 41.0435344 , 25.90969361,  6.49510362],
           [ 4.10018648, 16.35610171, 25.90969361, 16.35610171,  4.10018648],
           [ 1.0278445 ,  4.10018648,  6.49510362,  4.10018648,  1.0278445 ]])
    

    The original (accepted) answer below accepted is wrong The square root is unnecessary, and the definition of the interval is incorrect.

    import numpy as np
    import scipy.stats as st
    
    def gkern(kernlen=21, nsig=3):
        """Returns a 2D Gaussian kernel array."""
    
        interval = (2*nsig+1.)/(kernlen)
        x = np.linspace(-nsig-interval/2., nsig+interval/2., kernlen+1)
        kern1d = np.diff(st.norm.cdf(x))
        kernel_raw = np.sqrt(np.outer(kern1d, kern1d))
        kernel = kernel_raw/kernel_raw.sum()
        return kernel
    
    0 讨论(0)
提交回复
热议问题