Porównaj ceny domen i usług IT, sprzedawców z całego świata

Jak skutecznie obliczyć macierz Gaussa jądra w numpy?


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

To jest moja obecna ścieżka. Czy jest jakiś sposób, żebym mógł użyć do tego operacji macierzy? X to punkty danych.
Zaproszony:
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Czy chcesz na przykład użyć jądra Gaussa do wygładzania obrazu? Jeśli tak, to jest funkcja
gaussian_filter()
http://docs.scipy.org/doc/scip ... ilter
w scipy:

Zaktualizowana odpowiedź

Powinno to zadziałać - chociaż nadal nie jest w 100% dokładne, próbuje uwzględnić masę prawdopodobieństwa w każdej komórce siatki. Myślę, że użycie gęstości prawdopodobieństwa w środku każdej komórki jest trochę mniej dokładne, szczególnie w przypadku małych jąder. Zobacz przykład

https://homepages.inf.ed.ac.uk ... h.htm
https://homepages.inf.ed.ac.uk ... h.htm
.
def gkern(kernlen=21, nsig=3):
"""Returns a 2D Gaussian kernel.""" lim = kernlen//2 + (kernlen % 2)/2
x = np.linspace(-lim, lim, kernlen+1)
kern1d = np.diff(st.norm.cdf(x))
kern2d = np.outer(kern1d, kern1d)
return kern2d/kern2d.sum()

Testowanie na przykładzie na rysunku 3 z linku:
gkern(5,1)*273

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


Oryginalna (zaakceptowana) odpowiedź poniżej zaakceptowana jest nieprawidłowa

pierwiastek kwadratowy jest niepotrzebny, a definicja przedziału jest nieprawidłowa.
import numpy as np
import scipy.stats as stdef 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
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Sam użyłem zaakceptowanej odpowiedzi do przetwarzania obrazu, ale uważam ją (i inne odpowiedzi) za zbyt zależną od innych modułów. Ponadto zaakceptowana odpowiedź czasami tworzy jądra z dużą ilością pustych wpisów na końcu.
Oto moje kompaktowe rozwiązanie:
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)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Próbuję się poprawić

Odpowiedź FuzzyDuck
https://stackoverflow.com/a/29731818/4527807
tutaj. Myślę, że to podejście jest krótsze i łatwiejsze do zrozumienia. Tutaj używam
signal.scipy.gaussian
, aby uzyskać jądro 2D Gaussa.
import numpy as np
from scipy import signaldef 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

Plotowanie go za pomocą
matplotlib.pyplot
:
import matplotlib.pyplot as plt
plt.imshow(gkern(21), interpolation='none')

https://i.stack.imgur.com/lpPQe.png
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Możesz po prostu filtrować gaussowskie proste

Funkcja 2D Diraca
http://en.wikipedia.org/wiki/Dirac_delta_function, który będzie używał tej samej funkcji filtra:
import numpy as np
import scipy.ndimage.filters as fidef 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)
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Jądro macierzy 2D Gaussa można obliczyć za pomocą numpy broadcast,
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()

W przypadku małych rozmiarów jądra powinno to być wystarczająco szybkie.

Uwaga:

ułatwia to zmianę parametru sigma względem zaakceptowanej odpowiedzi.
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Próbowałem używać tylko numpy. Oto ten kod
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)

Możesz zwizualizować wynik za pomocą:
plt.imshow(get_gauss_kernel(5,1))

https://i.stack.imgur.com/X8VHo.png
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

linalg.norm
przyjmuje parametr
axis
. Po pewnym eksperymentowaniu stwierdziłem, że mogę obliczyć normę dla wszystkich kombinacji ciągów
np.linalg.norm(x[None,:,:]-x[:,None,:],axis=2)

Rozszerza
x
do trójwymiarowej tablicy wszystkich różnic i przejmuje ostatni wymiar.
Więc mogę zastosować to do twojego kodu, dodając parametr
axis
do twojego
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)

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

Połączenie:
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]])
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Już przygotowywałem się na odpowiedź Teddy'ego Hartanto. Możesz po prostu obliczyć swoje własne jednowymiarowe funkcje Gaussa, a następnie użyć
np.outer
do obliczenia funkcji dwuwymiarowej. Bardzo szybki i skuteczny sposób.
Za pomocą poniższego kodu możesz również użyć różnych Sigm dla każdego wymiaru
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
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Jeśli jesteś inżynierem wizji komputerowej i potrzebujesz mapy cieplnej dla określonego punktu w postaci rozkładu Gaussa (szczególnie do wykrywania kluczowych punktów na obrazie)
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


Użyj i wyjdź

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)

Maks. pod adresem: (2, 2)
forma jądra (10, 10)
https://i.stack.imgur.com/yBuLm.png
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)

maks. przy: (40, 25)
forma jądra (50, 100)
https://i.stack.imgur.com/GMEqj.png
Anonimowy użytkownik

Anonimowy użytkownik

Potwierdzenie od:

Ponieważ nie znalazłem tego, czego szukałem, zakodowałem własny jednowierszowy kod. Możesz go odpowiednio zmienić (zgodnie z wymiarami i odchyleniem standardowym).
Na przykład, oto funkcja jednowierszowa dla poprawki 3x5.
from scipy import signaldef gaussian2D(patchHeight, patchWidth, stdHeight=1, stdWidth=1):
gaussianWindow = signal.gaussian(patchHeight, stdHeight).reshape(-1, 1)@signal.gaussian(patchWidth, stdWidth).reshape(1, -1)
return gaussianWindowprint(gaussian2D(3, 5))

Otrzymasz takie wyniki:
[[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 ]]

Możesz przeczytać więcej o Gauss scipy

tutaj
https://docs.scipy.org/doc/sci ... .html
.

Aby odpowiedzieć na pytania, Zaloguj się lub Zarejestruj się