将二维数组分成更小的数组,获取块均值,并绘制热图

Chunk 2D array into smaller arrays, get the chunk means, and plot a heatmap

我想使用 seaborn 制作热图。我有一个 1920x1080 二维数组,其中包含从 0 到 1 的图像每个像素的显着性值(0 = 最低显着性 - 蓝色,1 = 最高显着性 - 红色)。我已将我的图像分成 80x90 像素的较小网格。我得到下面的图片:

到目前为止一切顺利。我接下来要做的是创建一个 seaborn 热图,这样每个网格都被平均并只用一种颜色表示(蓝色网格代表低显着性区域,暖色网格代表高显着性区域),如下所示:

但是,使用此代码:

import numpy as np

plt.figure(figsize= (16,9)) 
xticklabels=range(0,1920,80)
yticklabels=range(0,1080,90)
xticks[80,160,240,320,400,480,560,640,720,800,880,960,1040,1120,1200,1280,1360,1440,1520,1600,1680,1760,1840,1920]
yticks=[90,180,270,360,450,540,630,720,810,900,990,1080]

normalized_saliency_map=np.random.random((1080,1920))

ax=sns.heatmap(normalized_saliency_map, 
               cmap='jet',
               linewidth=0.5,
               xticklabels = xticklabels, 
               yticklabels = yticklabels)
ax.set_xticks(xticks)
ax.set_yticks(yticks)
plt.title(f'Image: {i}')
plt.show()

我得到这个空图:

如果我注释掉 ax.set_xticks(xticks)ax.set_yticks(yticks),我会得到这个:

我在这里错过了什么?

主阵

  • 删除linewidth
  • 添加 set_xticklabelsset_yticklabels
# test data
np.random.seed(365)
data = np.random.random((1080,1920))

ax = sns.heatmap(data, cmap='jet')
ax.set_xticks(xticks)  # this is only the tick location, not the label
ax.set_xticklabels(xticks)  # this adds the labels, after setting the ticks
ax.set_yticks(yticks)
ax.set_yticklabels(yticks)

ax.invert_yaxis()  # use if desired to swap the direction of the y-axis values
ax.grid(color='k')

plt.show()

划分数组

  • 我使用了这个 answer 中的函数将数据分块到一个数组中 (288, 90, 80)
# using function from other answer
chunked = blockshaped(data, 90, 80)

# get the means of each chunk and then reshape
means = np.array([v.mean() for v in chunked]).reshape(12, 24)

# plot the chunks
fig, ax = plt.subplots(figsize= (16,9)) 

p = sns.heatmap(means, cmap='jet', ax=ax)

p.set_xticks(range(25))
p.set_xticklabels([0] + xticks)
p.set_yticks(range(13))
p.set_yticklabels([0] + yticks)

p.invert_yaxis()
p.grid(color='k')

plt.show()

blockshaped

  • 这是另一个答案中用于重塑数组的函数
def blockshaped(arr, nrows, ncols):
    """
    Return an array of shape (n, nrows, ncols) where
    n * nrows * ncols = arr.size

    If arr is a 2D array, the returned array should look like n subblocks with
    each subblock preserving the "physical" layout of arr.
    """
    h, w = arr.shape
    assert h % nrows == 0, f"{h} rows is not evenly divisible by {nrows}"
    assert w % ncols == 0, f"{w} cols is not evenly divisible by {ncols}"
    return (arr.reshape(h//nrows, nrows, -1, ncols)
               .swapaxes(1,2)
               .reshape(-1, nrows, ncols))