在2d numpy数组中提高迭代性能

时间:2014-01-13 06:10:45

标签: python arrays loops numpy 2d

我有两个2d numpy数组(图像)。 由 图像 定义的第一个是在像素(i,j)处存储运动的总和

第二个由 nbCameras 定义,存储可以在此像素(i,j)处看到移动的摄像机数量

我想创建第三个图像 imgFinal ,它只存储像素(i,j)的值和它的邻居(3 x 3)蒙版,如果可以看到像素(i,j)的相机数量大于1.

现在我使用两个for循环,这不是最好的方法。我想提高计算的速度,但我还没有找到最好的方法。 此外,我有点被阻止,因为我想要转发像素的邻居(i,j)

我也试过使用bumpy.vectorize,但在这种情况下我可以保留像素的邻居。

提高此功能的最佳方法是什么?

感谢您的帮助!

maskWidth = 3
dstCenterMask = int( (maskWidth - 1) / 2)

imgFinal = np.zeros((image.shape),dtype = np.float32) 

 for j in range(dstCenterMask,image.shape[0] - dstCenterMask):
    for i in range(dstCenterMask,image.shape[1] - dstCenterMask):
        if nbCameras[j,i] > 1
           imgFinal[j - dstCenterMask : j + dstCenterMask + 1, i - dstCenterMask : i +     dstCenterMask + 1] =
           image[j - dstCenterMask : j + dstCenterMask + 1, i - dstCenterMask : i + dstCenterMask + 1]

3 个答案:

答案 0 :(得分:3)

使用skimage.morphology的binary_dilation函数,这非常优雅。它将采用二进制数组,并将任何真实像素扩展为真值(或任何其他大小)的3x3网格。这也应该处理边缘的情况。我认为你的实施没有。

使用这个掩码很容易计算imgFinal

from skimage.morphology import binary_dilation, square
mask = binary_dilation(nbCameras > 1, square(maskWidth))
imgFinal = np.where(mask, image, 0)

square(3)只是np.ones((3,3))

的简写

http://scikit-image.org/docs/dev/api/skimage.morphology.html?highlight=dilation#skimage.morphology.dilation

扩张的示例使用以更好地阐明它的作用:

In [27]: a
Out[27]:
array([[ 1.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  0.,  0.],
       [ 0.,  0.,  0.,  1.,  0.],
       [ 0.,  0.,  0.,  0.,  0.]])

In [28]: binary_dilation(a, square(3))
Out[28]:
array([[1, 1, 0, 0, 0],
       [1, 1, 0, 0, 0],
       [0, 0, 1, 1, 1],
       [0, 0, 1, 1, 1],
       [0, 0, 1, 1, 1]], dtype=uint8)

答案 1 :(得分:1)

选项1:尝试以矢量化方式重写代码。您可以使用这样的3x3模板进行卷积:

import numpy as np
from scipy.signal import convolve2d

image = np.random.random((100,100))
nbCameras = np.abs(np.random.normal(size=(100,100)).round())

maskWidth = 3
mask = np.ones((maskWidth, maskWidth))

visibilityMask = (nbCameras>1).astype(np.float)
visibilityMask = convolve2d(visibilityMask, mask, mode="same").astype(np.bool)

imgFinal = image.copy()
imgFinal[~visibilityMask] *= 0

import matplotlib.pyplot as plt
for i, (im, title) in enumerate([(image, "image"), 
                                 (nbCameras, "nbCameras"), 
                                 (visibilityMask, "visibilityMask"), 
                                 (imgFinal, "imgFinal")]):
    plt.subplot(2,2,i+1)
    plt.title(title)
    plt.imshow(im, cmap=plt.cm.gray)

plt.show()

这将导致此情节: Result

选项2:使用Numba。这使用了先进的即时优化技术,特别适用于加速循环。

答案 2 :(得分:1)

这不能处理数组边缘的摄像头,但你的代码也不会处理:

import numpy as np
from numpy.lib.stride_tricks import as_strided

rows, cols, mask_width = 10, 10, 3
mask_radius = mask_width // 2

image = np.random.rand(rows, cols)
nb_cameras = np.random.randint(3 ,size=(rows, cols))

image_view = as_strided(image, shape=image.shape + (mask_width, mask_width),
                        strides=image.strides*2)
img_final = np.zeros_like(image)
img_final_view = as_strided(img_final,
                            shape=img_final.shape + (mask_width, mask_width),
                            strides=img_final.strides*2)
copy_mask = nb_cameras[mask_radius:-mask_radius,
                       mask_radius:-mask_radius] > 1

img_final_view[copy_mask] = image_view[copy_mask]

运行上面的代码后:

>>> nb_cameras
array([[0, 2, 1, 0, 2, 0, 1, 2, 1, 0],
       [0, 1, 1, 1, 1, 2, 1, 1, 2, 1],
       [1, 2, 2, 2, 1, 2, 1, 0, 2, 0],
       [0, 2, 2, 0, 1, 2, 1, 0, 1, 0],
       [1, 2, 0, 1, 2, 0, 1, 0, 0, 2],
       [2, 0, 1, 1, 1, 1, 1, 1, 0, 1],
       [1, 0, 2, 2, 0, 1, 1, 1, 0, 0],
       [0, 0, 1, 0, 1, 0, 1, 0, 2, 2],
       [0, 1, 0, 1, 1, 2, 1, 1, 2, 2],
       [2, 2, 0, 1, 0, 0, 1, 2, 1, 0]])
>>> np.round(img_final, 1)
array([[ 0. ,  0. ,  0. ,  0. ,  0.7,  0.5,  0.6,  0.5,  0.6,  0.9],
       [ 0.1,  0.6,  1. ,  0.2,  0.3,  0.6,  0. ,  0.2,  0.9,  0.9],
       [ 0.2,  0.3,  0.3,  0.5,  0.2,  0.3,  0.4,  0.1,  0.7,  0.5],
       [ 0.9,  0.1,  0.7,  0.8,  0.2,  0.9,  0.9,  0.1,  0.3,  0.3],
       [ 0.8,  0.8,  1. ,  0.9,  0.2,  0.5,  1. ,  0. ,  0. ,  0. ],
       [ 0.2,  0.3,  0.5,  0.4,  0.6,  0.2,  0. ,  0. ,  0. ,  0. ],
       [ 0. ,  0.2,  1. ,  0.2,  0.8,  0. ,  0. ,  0.7,  0.9,  0.6],
       [ 0. ,  0.2,  0.9,  0.9,  0.3,  0.4,  0.6,  0.6,  0.3,  0.6],
       [ 0. ,  0. ,  0. ,  0. ,  0.8,  0.8,  0.1,  0.7,  0.4,  0.4],
       [ 0. ,  0. ,  0. ,  0. ,  0. ,  0.5,  0.1,  0.4,  0.3,  0.9]])

管理边缘的另一个选择是使用scipy.ndimage中的卷积函数:

import scipy.ndimage
mask = scipy.ndimage.convolve(nb_cameras > 1, np.ones((3,3)),
                              mode='constant') != 0
img_final[mask] = image[mask]
>>> np.round(img_final, 1)
array([[ 0.6,  0.8,  0.7,  0.9,  0.7,  0.5,  0.6,  0.5,  0.6,  0.9],
       [ 0.1,  0.6,  1. ,  0.2,  0.3,  0.6,  0. ,  0.2,  0.9,  0.9],
       [ 0.2,  0.3,  0.3,  0.5,  0.2,  0.3,  0.4,  0.1,  0.7,  0.5],
       [ 0.9,  0.1,  0.7,  0.8,  0.2,  0.9,  0.9,  0.1,  0.3,  0.3],
       [ 0.8,  0.8,  1. ,  0.9,  0.2,  0.5,  1. ,  0. ,  0.3,  0.8],
       [ 0.2,  0.3,  0.5,  0.4,  0.6,  0.2,  0. ,  0. ,  0.7,  0.6],
       [ 0.2,  0.2,  1. ,  0.2,  0.8,  0. ,  0. ,  0.7,  0.9,  0.6],
       [ 0. ,  0.2,  0.9,  0.9,  0.3,  0.4,  0.6,  0.6,  0.3,  0.6],
       [ 0.4,  1. ,  0.8,  0. ,  0.8,  0.8,  0.1,  0.7,  0.4,  0.4],
       [ 0.9,  0.5,  0.8,  0. ,  0. ,  0.5,  0.1,  0.4,  0.3,  0.9]])