Dit is mijn huidige manier. Is er een manier waarop ik matrixbewerking kan gebruiken om dit te doen? X zijn de gegevenspunten.
Antwoord 1, autoriteit 100%
Wilt u de Gauss-kernel gebruiken voor b.v. beeld gladstrijken? Zo ja, dan is er een functie gaussian_filter()
in scipy:
Bijgewerkt antwoord
Dit zou moeten werken – hoewel het nog steeds niet 100% nauwkeurig is, probeert het rekening te houden met de waarschijnlijkheidsmassa binnen elke cel van het raster. Ik denk dat het gebruik van de kansdichtheid in het midden van elke cel iets minder nauwkeurig is, vooral voor kleine kernels. Zie https://homepages.inf.ed.ac.uk/rbf /HIPR2/gsmooth.htmvoor een voorbeeld.
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()
Testen op het voorbeeld in Afbeelding 3 van de link:
gkern(5, 2.5)*273
geeft
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 ]])
Het originele (geaccepteerde) antwoord hieronder is fout
De vierkantswortel is niet nodig en de definitie van het interval is onjuist.
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
Antwoord 2, autoriteit 90%
Ik heb zelf het geaccepteerde antwoord gebruikt voor mijn beeldverwerking, maar ik vind het (en de andere antwoorden) te afhankelijk van andere modules. Daarom is hier mijn compacte oplossing:
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)
Bewerken: Arange gewijzigd in linspace om even zijdelingse lengtes te verwerken
Antwoord 3, autoriteit 83%
Ik probeer het antwoord van FuzzyDuck’s antwoordhier te verbeteren. Ik denk dat deze benadering korter en gemakkelijker te begrijpen is. Hier gebruik ik signal.scipy.gaussian
om de 2D Gauss-kernel te krijgen.
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 met matplotlib.pyplot
:
import matplotlib.pyplot as plt
plt.imshow(gkern(21), interpolation='none')
Antwoord 4, autoriteit 62%
U kunt eenvoudig een eenvoudige 2D dirac-functiefilteren, het resultaat is dan het filter functie die werd gebruikt:
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)
Antwoord 5, autoriteit 21%
Een 2D Gauss-kernelmatrix kan worden berekend met 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()
Voor kleine kernelgroottes zou dit redelijk snel moeten zijn.
Opmerking:dit maakt het wijzigen van de sigma-parameter eenvoudiger ten opzichte van het geaccepteerde antwoord.
Antwoord 6, autoriteit 17%
Ik heb geprobeerd alleen numpy te gebruiken. Hier is de 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)
U kunt het resultaat visualiseren met:
plt.imshow(get_gauss_kernel(5,1))
Antwoord 7, autoriteit 17%
Als u een computer vision-ingenieur bent en u een heatmap nodig heeft voor een bepaald punt als Gauss-distributie (vooral voor keypoint-detectie op afbeelding)
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
het gebruik en uitvoer
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 op: (2, 2)
Kernelvorm (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 op: (40, 25)
Kernel-vorm (50, 100)
Antwoord 8, Autoriteit 14%
linalg.norm
neemt een axis
parameter. Met een beetje experimenteren vond ik dat ik de norm kon berekenen voor alle combinaties van rijen met
np.linalg.norm(x[None,:,:]-x[:,None,:],axis=2)
Het breidt x
uit in een 3D-reeks van alle verschillen en neemt de norm op de laatste dimensie.
Dus ik kan dit toepassen op uw code door de axis
Parameter toe te voegen aan uw 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)
produceert
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]])
Overeenkomst:
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]])
Antwoord 9, autoriteit 10%
Voortbouwend op het antwoord van Teddy Hartanto. Je kunt gewoon je eigen eendimensionale Gauss-functies berekenen en vervolgens np.outer
gebruiken om de tweedimensionale te berekenen. Zeer snelle en efficiënte manier.
Met onderstaande code kun je ook voor elke dimensie verschillende Sigma’s gebruiken
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
Antwoord 10, autoriteit 3%
Het door FuzzyDuck geaccepteerde antwoord aanpassen aan de resultaten van deze website: http:// dev.theomader.com/gaussian-kernel-calculator/Ik presenteer u nu deze definitie:
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))
uitvoer:
[[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 ]]
Antwoord 11, autoriteit 3%
Een goede manier om dat te doen is door de functie gaussian_filter te gebruiken om de kernel te herstellen.
Bijvoorbeeld:
indicatrice = np.zeros((5,5))
indicatrice[2,2] = 1
gaussian_kernel = gaussian_filter(indicatrice, sigma=1)
gaussian_kernel/=gaussian_kernel[2,2]
Dit geeft
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]]
Antwoord 12
Omdat ik niet vond wat ik zocht, heb ik mijn eigen oneliner gecodeerd. U kunt het dienovereenkomstig aanpassen (volgens de afmetingen en de standaarddeviatie).
Hier is bijvoorbeeld de one-liner-functie voor een 3×5 patch.
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))
Je krijgt een uitvoer als volgt:
[[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 ]]
Je kunt meer lezen over scipy’s Gaussiaanse hier.
Antwoord 13
Weer een implementatie.
Dit is genormaliseerd zodat voor sigma > 1
en voldoende grote win_size
, de totale som van de kernelelementen is gelijk aan 1
.
def gaussian_kernel(win_size, sigma):
t = np.arange(win_size)
x, y = np.meshgrid(t, t)
o = (win_size - 1) / 2
r = np.sqrt((x - o)**2 + (y - o)**2)
scale = 1 / (sigma**2 * 2 * np.pi)
return scale * np.exp(-0.5 * (r / sigma)**2)
Een 5×5 kernel genereren:
gaussian_kernel(win_size=5, sigma=1)