首页 > 解决方案 > 将numpy 2d数组分成相等的部分

问题描述

我有一个 30*30px 的图像,并将其转换为 NumPy 数组。现在我想把这个 30*30 的图像分成 9 个相等的部分(想象一个井字游戏)。我为此目的编写了下面的代码,但我的代码的问题是它有两个嵌套循环,在 python 中,这意味着直接进入低性能城镇(特别是对于大量数据)。那么使用 NumPy 和 Numpy 索引有没有更好的方法呢?

#Factor is saing that the image should be divided into 9 sections 3*3 = 9 (kinda like 3 rows 3 columns)
def section(img , factor = 3):
    secs = []

    #This basicaly tests if the image can actually get divided into equal sections
    if (img.shape[0] % factor != 0):
        return False

    #number of pixel in each row and column of the sections
    pix_num = int(img.shape[0] / factor)

    ptr_x_a = 0
    ptr_x_b = pix_num -1


    for i in range(factor):

        ptr_y_a = 0
        ptr_y_b = pix_num - 1
        
        for j in range(factor):

            secs.append( img[ptr_x_a :ptr_x_b , ptr_y_a : ptr_y_b] )
            ptr_y_a += pix_num
            ptr_y_b += pix_num
    
        ptr_x_a += pix_num
        ptr_x_b += pix_num
    
    return np.array(secs , dtype = "int16"‍‍‍‍‍‍‍)

PS:不介意阅读整个代码,只要知道它使用指针来选择图像的不同区域即可。

P.S2:请参阅下图以了解正在发生的事情。它是一个 6*6 的图像,分为 9 块 ( factor = 3) 在此处输入图像描述

标签: pythonarraysnumpy

解决方案


如果您有一个 shape 数组,您可以使用and(K * M, K * N)将其转换为某种形状。例如,如果你有,你想转换(K * K, M, N)reshapetransposeK = M = N = 3

>>> a = np.arange(81).reshape(9, 9)

进入

[[[ 0,  1,  2],
  [ 9, 10, 11],
  [18, 19, 20]],
 [[ 3,  4,  5],
  [12, 13, 14],
  [21, 22, 23]],
 [[ 6,  7,  8],
  [15, 16, 17],
  [24, 25, 26]],
 ...
 ]]]

这个想法是您需要按照此处显示的顺序(即0, 1, 2, 9, 10, 11, 18, ...)将元素排列在内存中。您可以通过添加适当的辅助尺寸和转置来做到这一点:

b = a.reshape(K, M, K, N)
c = b.transpose(0, 2, 1, 3)
d = c.reahape(-1, M, N)

作为一个单行:

a.reshape(K, M, K, N).transpose(0, 2 1, 3).reshape(-1, M, N)

转置的顺序决定了块的顺序。前两个维度0, 2表示您的内部循环迭代列的速度快于行的事实。如果您想按列排列块(更快地迭代行),您可以这样做

c = b.transpose(2, 0, 1, 3)

重塑不会改变元素的内存布局,但必要时转置会复制数据。

在您的特定示例中,K = 3并且M = N = 10. 除此之外,上面的代码没有任何变化。

顺便说一句,可以通过将范围直接设置在您想要的索引上而不是辅助量以及预先分配输出来改进循环:

result = np.zeros(factor * factor, pix_num, pix_num)
n = 0
for r in range(0, img.shape[0], pix_num):
    for c in range(0, img.shape[1], pix_num):
         result[n, :, :] = img[r:r + pix_num, c:c + pix_num]
         n += 1

推荐阅读