替代'numpy.tile`用于周期性掩模

时间:2013-01-22 19:30:41

标签: python numpy

我有一个图像,存储在uint8的n (planes, rows, cols)个n形状中,形状为uint8。我需要将它与存储在掩码中的值(也是(mask_rows, mask_cols)的形状(256, 256))进行比较。虽然图像可能非常大,但遮罩通常很小,通常为image,并且要平铺在rows = 100 * mask_rows上。为了简化代码,我们假装cols = 100 * mask_colsout = image >= np.tile(mask, (image.shape[0], 100, 100))

我目前处理这种阈值的方式是这样的:

MemoryError

在用(3, 11100, 11100)打脸之前,我可以通过这种方式处理的最大数组比image略大一些。我这样做的方式,以这种方式做事我在内存中共存最多三个巨大的数组:mask,平铺的out和我的返回(3, 13600, 13600)。但是,平铺的掩码是相同的小数组,复制超过10,000次。因此,如果我可以节省内存,我只会使用2/3的内存,并且应该能够处理大于3/2的图像,大小约为np.greater_equal(image, (image.shape[0], 100, 100), out=image) 。顺便说一下,如果我使用

进行阈值处理,这与我得到的结果一致
mask

我(失败)尝试利用mask的周期性来处理更大的数组,一直是使用周期性线性数组索引mask = mask[None, ...] rows = np.tile(np.arange(mask.shape[1], (100,))).reshape(1, -1, 1) cols = np.tile(np.arange(mask.shape[2], (100,))).reshape(1, 1, -1) out = image >= mask[:, rows, cols]

MemoryError

对于小型阵列,它确实产生与另一个阵列相同的结果,尽管速度减慢了20倍(!!!),但是对于较大的阵列来说,它的表现非常糟糕。而不是(planes, rows, cols)它最终会崩溃python,即使对于其他方法处理没有问题的值也是如此。

我认为正在发生的是numpy实际上构造了mask数组来索引int32,所以不仅没有内存保存,而且因为它是import numpy as np def halftone_1(image, mask) : return np.greater_equal(image, np.tile(mask, (image.shape[0], 100, 100))) def halftone_2(image, mask) : mask = mask[None, ...] rows = np.tile(np.arange(mask.shape[1]), (100,)).reshape(1, -1, 1) cols = np.tile(np.arange(mask.shape[2]), (100,)).reshape(1, 1, -1) return np.greater_equal(image, mask[:, rows, cols]) rows, cols, planes = 6000, 6000, 3 image = np.random.randint(-2**31, 2**31 - 1, size=(planes * rows * cols // 4)) image = image.view(dtype='uint8').reshape(planes, rows, cols) mask = np.random.randint(256, size=(1, rows // 100, cols // 100)).astype('uint8') #np.all(halftone_1(image, mask) == halftone_2(image, mask)) #halftone_1(image, mask) #halftone_2(image, mask) import timeit print timeit.timeit('halftone_1(image, mask)', 'from __main__ import halftone_1, image, mask', number=1) print timeit.timeit('halftone_2(image, mask)', 'from __main__ import halftone_2, image, mask', number=1) 的数组s,它实际上需要四倍的存储空间......

有关如何解决此问题的任何想法?为了免除麻烦,请在下面找到一些沙箱代码:

{{1}}

1 个答案:

答案 0 :(得分:6)

我几乎已经指出了一种rolling window类型的技巧,但对于这个简单的非重叠的东西,正常的重塑也是如此。 (这里的重塑是安全的,numpy 从不为他们制作副本)

def halftone_reshape(image, mask):
    # you can make up a nicer reshape code maybe, it is a bit ugly. The
    # rolling window code can do this too (but much more general then reshape).
    new_shape = np.array(zip(image.shape, mask.shape))
    new_shape[:,0] /= new_shape[:,1]
    reshaped_image = image.reshape(new_shape.ravel())

    reshaped_mask = mask[None,:,None,:,None,:]

    # and now they just broadcast:
    result_funny_shaped = reshaped_image >= reshaped_mask

    # And you can just reshape it back:
    return result_funny_shaped.reshape(image.shape)

因为时间安排就是一切(不是真的......):

In [172]: %timeit halftone_reshape(image, mask)
1 loops, best of 3: 280 ms per loop

In [173]: %timeit halftone_1(image, mask)
1 loops, best of 3: 354 ms per loop

In [174]: %timeit halftone_2(image, mask)
1 loops, best of 3: 3.1 s per loop