How to calculate a Gaussian kernel matrix efficiently in numpy?

匿名 (未验证) 提交于 2019-12-03 01:22:02

问题:

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 in X:             GassMatrix[i,j]=Gaussian(v_i.T,v_j.T,sigma)             j+=1         i+=1     return GassMatrix def Gaussian(x,z,sigma):     return np.exp((-(np.linalg.norm(x-z)**2))/(2*sigma**2)) 

This is my current way. Is there any way I can use matrix operation to do this? X is the data points.

回答1:

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

Alternatively, this should work:

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 

Input:

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

Output:



回答2:

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) 


回答3:

I myself used the accepted answer for my image processing, but I find it (and the other answers) too dependent on other modules. Furthermore, the accepted answer sometimes produces kernels with a lot of zero entries in the end.

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.arange(-l // 2 + 1., l // 2 + 1.)     xx, yy = np.meshgrid(ax, ax)      kernel = np.exp(-(xx**2 + yy**2) / (2. * sig**2))      return kernel / np.sum(kernel) 


回答4:

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]]) 


回答5:

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') 



回答6:

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 


回答7:

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.



标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!