2017-07-06 112 views
0

我正在嘗試生成一個熱圖,其中像素值由兩個獨立的2D高斯分佈控制。讓它們分別是Kernel1(muX1,muY1,sigmaX1,sigmaY1)和Kernel2(muX2,muY2,sigmaX2,sigmaY2)。更具體地說,每個內核的長度是其標準偏差的三倍。第一個內核有sigmaX1 = sigmaY1,第二個內核有sigmaX2 < sigmaY2。兩個核的協方差矩陣都是對角線(X和Y是獨立的)。 Kernel1通常完全在Kernel2內部。如何高效地計算Python中兩個高斯分佈的熱圖?

我嘗試了以下兩種方法,結果都不令人滿意。有人可以給我一些建議嗎?

Approach1:

遍歷地圖上的所有像素值對(I,J),並通過I(I,J)= P(I,J計算的給定I(I,J)的值| Kernel1,Kernel2)= 1-(1-P(i,j | Kernel1))*(1-P(i,j | Kernel2))。然後我得到了以下結果,這在平滑性方面很好。但是在我的電腦上運行需要10秒,這太慢了。

代碼:

def genDensityBox(self, height, width, muY1, muX1, muY2, muX2, sigmaK1, sigmaY2, sigmaX2): 
    densityBox = np.zeros((height, width)) 
    for y in range(height): 
     for x in range(width): 
      densityBox[y, x] += 1. - (1. - multivariateNormal(y, x, muY1, muX1, sigmaK1, sigmaK1)) * (1. - multivariateNormal(y, x, muY2, muX2, sigmaY2, sigmaX2)) 
    return densityBox 

def multivariateNormal(y, x, muY, muX, sigmaY, sigmaX): 
    return norm.pdf(y, loc=muY, scale=sigmaY) * norm.pdf(x, loc=muX, scale=sigmaX) 

First approach

Approach2:

產生對應於兩個內核分別兩個圖像,然後使用某些α值一起混合它們。每個圖像通過取兩個一維高斯濾波器的外積來生成。然後我得到了如下結果,這非常粗糙。但是這種方法的優點是由於在兩個向量之間使用外部產品,所以速度非常快。 Second approach

由於第一個很慢,第二個是粗糙的,我試圖找到一個新的方法,同時實現良好的平滑度和低時間複雜性。有人能給我一些幫助嗎?

謝謝!

對於第二種方法中,2D高斯地圖可以很容易地提到here產生:

def gkern(self, sigmaY, sigmaX, yKernelLen, xKernelLen, nsigma=3): 
    """Returns a 2D Gaussian kernel array.""" 
    yInterval = (2*nsigma+1.)/(yKernelLen) 
    yRow = np.linspace(-nsigma-yInterval/2.,nsigma+yInterval/2.,yKernelLen + 1) 
    kernelY = np.diff(st.norm.cdf(yRow, 0, sigmaY)) 
    xInterval = (2*nsigma+1.)/(xKernelLen) 
    xRow = np.linspace(-nsigma-xInterval/2.,nsigma+xInterval/2.,xKernelLen + 1) 
    kernelX = np.diff(st.norm.cdf(xRow, 0, sigmaX))  
    kernelRaw = np.sqrt(np.outer(kernelY, kernelX)) 
    kernel = kernelRaw/(kernelRaw.sum()) 
    return kernel 

回答

0

你的做法是比罰款等你應該在norm.pdf不循環,但只是把所有的值上,你需要對內核進行評估,然後將輸出重塑爲所需的圖像形狀。

import numpy as np 
import matplotlib.pyplot as plt 
from scipy.stats import multivariate_normal 

# create 2 kernels 
m1 = (-1,-1) 
s1 = np.eye(2) 
k1 = multivariate_normal(mean=m1, cov=s1) 

m2 = (1,1) 
s2 = np.eye(2) 
k2 = multivariate_normal(mean=m2, cov=s2) 

# create a grid of (x,y) coordinates at which to evaluate the kernels 
xlim = (-3, 3) 
ylim = (-3, 3) 
xres = 100 
yres = 100 

x = np.linspace(xlim[0], xlim[1], xres) 
y = np.linspace(ylim[0], ylim[1], yres) 
xx, yy = np.meshgrid(x,y) 

# evaluate kernels at grid points 
xxyy = np.c_[xx.ravel(), yy.ravel()] 
zz = k1.pdf(xxyy) + k2.pdf(xxyy) 

# reshape and plot image 
img = zz.reshape((xres,yres)) 
plt.imshow(img); plt.show() 

enter image description here

這種做法不應過長:

In [26]: %timeit zz = k1.pdf(xxyy) + k2.pdf(xxyy) 
1000 loops, best of 3: 1.16 ms per loop