python循环非常慢

时间:2018-07-04 09:57:46

标签: python performance loops numpy

我有一个关于Python循环速度的问题。 我创建了以下循环来填充数组中的值,但这非常慢。 有没有办法使其处理更快?

winW = 1    
winH = 200    
runlength = np.zeros(shape=(img.shape[0], img.shape[1]))


for y in range(0, img.shape[0] - winH, 1):
   for x in range(0, img.shape[1] - winW, 1):
      runlength[y, x] += np.sum(img[y:y + winH, x:x + winW]) / (winH * winW)
      runlength[y + winH, x] += np.sum(img[y:y + winH, x:x + winW]) / (winH * winW)

感谢您的帮助

编辑:我精确地说,我只能使用numpy,而不能使用scipy

2 个答案:

答案 0 :(得分:2)

让我描述一下如何加快for循环中的第一个操作,该操作由

给出
runlength[y, x] += np.sum(img[y:y + winH, x:x + winW]) / (winH * winW)

基本上,您正在图像上移动一个宽度winW和高度winH的矩形。从图像的点(0,0)处的矩形的左上角开始,然后对图像中位于该矩形下方的所有值求和,然后将它们除以总点数。位置(0,0)的输出就是该数字。然后将矩形向右移动一个,然后重复该过程,直到位于图像的右端。您向下移动一行并重复。

在图像处理方面:将空间滤镜蒙版应用于图像。该过滤器是宽度winW和高度winH的平均过滤器。

要有效地实现此目的,可以使用scipy.ndimage.correlate函数。 input是您的图像,weights包含与矩形下面的元素相乘的权重。在这种情况下,这是一个维度为(winH, winW)的数组,其中每个元素都包含数字1 / (winH * winW)。因此,将位于矩形下方的图像的每个点乘以1 / (winH * winW),然后将所有内容相加。

要完全匹配您的算法,我们需要将origin设置为(-np.floor(winH/2), -np.floor(winW/2)),以指定将矩形的均值放置在输出中矩形的右上角。

最后,为了完全匹配您的算法,我们必须将(img.shape[0] - winH)以下或(img.shape[1] - winW)右边的所有点都设置为零。因此,可以将for循环替换为

runlength_corr = correlate(input=img,
                           weights=np.ones((winH, winW)) / (winW * winH),
                           origin=(-np.floor(winH/2), -np.floor(winW/2)))
runlength_corr[(img.shape[0] - winH):, :] = 0
runlength_corr[:, (img.shape[1] - winW):] = 0

我在大小为512 x 512的测试图像上比较了嵌套的for循环和correlate方法的运行时间:

For-loops: Elapsed time: 0.665 sec
Correlate: Elapsed time: 0.085 sec

因此,这可以很好地加速因子8。整个输出的绝对差之和低至7.04e-09,因此两种方法的输出基本上相同。

答案 1 :(得分:0)

对于初学者来说,您似乎在循环内计算了两次相同的数量。仅此一项就可以节省一半的运行时间。

第二,如果winW始终为1,则np.sum(img[y:y + winH, x:x + winW])np.sum(img[y:y + winH, x])。这样应该可以加快速度。

剩下的就是如何加快np.sum(img[y:y + winH, x])的速度。您可以先计算

sum0 = np.sum(img[0: 0 + winH, x])

现在,请注意数量

sum1 = np.sum(img[1: 1 + winH, x])

仅与前一个像素相差两个像素,因此等于sum0 - img[0, x] + img[1 + winH, x]。对于下一个y

sum2 = sum1 - img[1, x] + img[2 + winH, x]`

以此类推