webentwicklung-frage-antwort-db.com.de

Wie kann man eine Gaußsche Kernel-Matrix effizient in numpy berechnen?

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

Dies ist mein aktueller Weg. Gibt es eine Möglichkeit, die Matrix-Operation dazu zu verwenden? X ist die Datenpunkte.

14
deathlee

Möchten Sie den Gaußschen Kernel für z. Bildglättung? Wenn ja, gibt es eine Funktion gaussian_filter() in scipy:

Alternativ sollte dies funktionieren:

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

Eingang:

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

Ausgabe: enter image description here

21
FuzzyDuck

Sie können einfach eine einfache 2D Dirac-Funktion gaussian-filter filtern - /, das Ergebnis ist dann die verwendete Filterfunktion:

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)
15
Nils Werner

Ich selbst habe die akzeptierte Antwort für meine Bildverarbeitung verwendet, aber ich finde es (und die anderen Antworten) zu abhängig von anderen Modulen. Außerdem führt die akzeptierte Antwort manchmal zu Kerneln mit vielen Null-Einträgen am Ende. 

Deshalb hier meine kompakte Lösung:

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(-0.5 * (np.square(xx) + np.square(yy)) / np.square(sig))

    return kernel / np.sum(kernel)
11
clemisch

Ich versuche die Antwort von FuzzyDuck hier zu verbessern. Ich denke, dieser Ansatz ist kürzer und verständlicher. Hier verwende ich signal.scipy.gaussian, um den 2D-Gaußschen Kernel zu erhalten.

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

Plotten Sie es mit matplotlib.pyplot:

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

 Gaussian kernel plotted using matplotlib

6
Teddy Hartanto

Eine 2D-Gaußsche Kernel-Matrix kann mit Numpy-Broadcasting berechnet werden.

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

Für kleine Kerngrößen sollte dies ziemlich schnell sein.

Hinweis: Dies erleichtert das Ändern des Sigma-Parameters in Bezug auf die akzeptierte Antwort.

4
rth

linalg.norm nimmt einen axis-Parameter an. Mit einem kleinen Experiment stellte ich fest, dass ich die Norm für alle Kombinationen von Reihen mit berechnen konnte 

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

Es erweitert x in ein 3D-Array aller Unterschiede und übernimmt die Norm für die letzte Dimension.

So kann ich dies auf Ihren Code anwenden, indem Sie den Parameter axis zu Ihrer Gaussian hinzufügen:

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)

produziert

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

Passend dazu:

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

Aufbauend auf der Antwort von Teddy Hartanto. Sie können einfach Ihre eigenen eindimensionalen Gaußschen Funktionen berechnen und dann mit np.outer die zweidimensionale berechnen. Sehr schneller und effizienter Weg.

Mit dem folgenden Code können Sie auch unterschiedliche Sigmas für jede Dimension verwenden

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
2
Domi

Ich habe nur mit Numpy versucht

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)

und dann anrufen 

plt.imshow(get_gauss_kernel(5,1))

 Here is the output

1
Suraj Singh