如何在Python中高效地计算两个高斯分布的热图?

如何在Python中高效地计算两个高斯分布的热图?,python,numpy,heatmap,gaussian,Python,Numpy,Heatmap,Gaussian,我试图生成一个热图,其中像素值由两个独立的二维高斯分布控制。让它们分别为Kernel1(muX1、muY1、sigmaX1、sigmaY1)和Kernel2(muX2、muY2、sigmaX2、sigmaY2)。更具体地说,每个内核的长度是其标准偏差的三倍。第一个内核的sigmaX1=sigmaY1,第二个内核的sigmaX2

我试图生成一个热图,其中像素值由两个独立的二维高斯分布控制。让它们分别为Kernel1(muX1、muY1、sigmaX1、sigmaY1)和Kernel2(muX2、muY2、sigmaX2、sigmaY2)。更具体地说,每个内核的长度是其标准偏差的三倍。第一个内核的sigmaX1=sigmaY1,第二个内核的sigmaX2 我尝试了以下两种方法,结果都不令人满意。有人能给我一些建议吗

方法1:

迭代贴图上的所有像素值对(i,j),并计算i(i,j)=p(i,j | Kernel1,Kernel2)=1-(1-p(i,j | Kernel1))*(1-p(i,j | Kernel2))给出的i(i,j)的值。然后我得到了以下结果,在平滑度方面是好的。但在我的电脑上运行需要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)

方法2:

分别生成对应于两个内核的两个图像,然后使用特定的alpha值将它们混合在一起。每幅图像由两个一维高斯滤波器的外积生成。然后我得到了以下结果,非常粗糙。但这种方法的优点是,由于在两个向量之间使用外积,因此速度非常快。

由于第一种方法比较慢,第二种方法比较粗糙,所以我试图找到一种新的方法,同时实现良好的平滑度和较低的时间复杂度。有人能给我一些帮助吗

谢谢

对于第二种方法,如前所述,可以容易地生成2D高斯贴图:


您的方法很好,只是不应该在
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()

这种方法不应该花费太长时间:

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

您的方法很好,只是不应该在
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()

这种方法不应该花费太长时间:

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

根据Paul的回答,我制作了一个函数,以高斯中心作为输入,制作高斯热图(这可能对其他人有帮助):

将numpy导入为np
将matplotlib.pyplot作为plt导入
从scipy.stats导入多变量_normal
def点到高斯热图(中心、高度、宽度、比例):
高斯=[]
对于中心的y和x:
s=np.眼(2)*刻度
g=多变量_正态(平均值=(x,y),cov=s)
高斯附加(g)
#创建(x,y)坐标的网格,在该网格上计算内核
x=np.arange(0,宽度)
y=np.arange(0,高度)
xx,yy=np.meshgrid(x,y)
xxyy=np.stack([xx.ravel(),yy.ravel()]).T
#计算网格点处的核
zz=总和(g.pdf(xxyy)表示g的高斯数)
img=zz.重塑((高度、宽度))
返回img
W=800#热图宽度
H=400#热图高度
比例=64#增加比例以产生更大的高斯
中心=[(100100),
(100,300), 
(300100)]#高斯中心点
img=点到高斯热图(中心、H、W、比例)
plt.imshow(img);plt.show()

根据Paul的回答,我制作了一个函数,以高斯中心作为输入,制作高斯热图(这可能对其他人有帮助):

将numpy导入为np
将matplotlib.pyplot作为plt导入
从scipy.stats导入多变量_normal
def点到高斯热图(中心、高度、宽度、比例):
高斯=[]
对于中心的y和x:
s=np.眼(2)*刻度
g=多变量_正态(平均值=(x,y),cov=s)
高斯附加(g)
#创建(x,y)坐标的网格,在该网格上计算内核
x=np.arange(0,宽度)
y=np.arange(0,高度)
xx,yy=np.meshgrid(x,y)
xxyy=np.stack([xx.ravel(),yy.ravel()]).T
#计算网格点处的核
zz=总和(g.pdf(xxyy)表示g的高斯数)
img=zz.重塑((高度、宽度))
返回img
W=800#热图宽度
H=400#热图高度
比例=64#增加比例以产生更大的高斯
中心=[(100100),
(100,300), 
(300100)]#高斯中心点
img=点到高斯热图(中心、H、W、比例)
plt.imshow(img);plt.show()