2017-07-06 77 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