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))
これが私の現在の方法です。これを行うために行列演算を使用する方法はありますか? Xはデータポイントです。
たとえば、ガウスカーネルを使用しますか?画像の平滑化?その場合、scipyには関数 gaussian_filter()
があります。
更新された回答
これは動作するはずです-100%正確ではありませんが、グリッドの各セル内の確率質量を考慮しようとします。特に小さなカーネルでは、各セルの中間点での確率密度の使用はわずかに精度が低いと思います。例については、 https://homepages.inf.ed.ac.uk/rbf/HIPR2/gsmooth.htm を参照してください。
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()
リンクから図3の例でテストします。
gkern(5, 2.5)*273
与える
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 ]])
以下の受け入れられた元の(受け入れられた)答えは間違っています平方根は不要であり、間隔の定義は正しくありません。
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
単純なガウスフィルターで単純な 2D dirac関数 を実行すると、結果は使用されていたフィルター関数になります。
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)
私自身は、画像処理に受け入れられた答えを使用しましたが、他のモジュールに依存しすぎていると感じました。したがって、ここに私のコンパクトなソリューションがあります:
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)
編集:側面の長さを均等に処理するために、範囲をlinspaceに変更しました
FuzzyDuckの答え を改善しようとしています。このアプローチは短く、理解しやすいと思います。ここでは、signal.scipy.gaussian
を使用して2Dガウスカーネルを取得しています。
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
matplotlib.pyplot
を使用してプロットする:
import matplotlib.pyplot as plt
plt.imshow(gkern(21), interpolation='none')
2Dガウスカーネルマトリックスは、numpyブロードキャストで計算できます。
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()
カーネルサイズが小さい場合、これはかなり高速です。
注:これにより、受け入れられた回答に関してsigmaパラメーターの変更が容易になります。
Teddy Hartantoの答えに基づいて構築。独自の1次元ガウス関数を計算して、np.outer
2次元を計算します。非常に高速で効率的な方法。
以下のコードを使用すると、ディメンションごとに異なるシグマを使用することもできます
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
Numpyのみを使用してみました。ここにコードがあります
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)
以下を使用して結果を視覚化できます。
plt.imshow(get_gauss_kernel(5,1))
linalg.norm
はaxis
パラメーターを取ります。少し実験して、行のすべての組み合わせのノルムを計算できることがわかりました
np.linalg.norm(x[None,:,:]-x[:,None,:],axis=2)
x
をすべての差分の3D配列に展開し、最後の次元でノルムを取ります。
axis
パラメーターを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)
生産する
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]])
マッチング:
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]])