NumPy 2D阵列迭代速度

2024-10-16 17:21:11 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个循环,它用像素信息填充一个二维NumPy数组,这个数组称为“阴影”。颜色不是白色就是蓝色。我想建立一个最终的形象,从这些白色占主导地位。 i、 e.如果循环中的一个图像在坐标x、y上有一个蓝色像素,而循环中的另一个图像在同一坐标上有一个白色像素,那么最终的像素将是白色的。你知道吗

目前由以下人员完成:

import math, random, copy
import numpy as np
from PIL import Image, ImageDraw

colours = {0: (255,255,255), 1: (0,0,255)}

#width and height of area of interest
w = 100 #100 meter
h = 200 #200 meter

NumberOfDots = 10
DotRadius = 20
NumberOfRuns = 3

Final = np.array([[colours[0] for x in range(w)] for y in range(h)])
Shadows = np.array([[colours[0] for x in range(w)] for y in range(h)])

for SensorNum in range(NumberOfRuns):

  Shadows = np.array([[colours[0] for x in range(w)] for y in range(h)])

  for dot in range(NumberOfDots):

    ypos = random.randint(DotRadius, h-DotRadius)
    xpos = random.randint(DotRadius, w-DotRadius)

    for i in range(xpos - DotRadius, xpos + DotRadius):
      for j in range(ypos - DotRadius, ypos + DotRadius):
          if math.sqrt((xpos - i)**2 + (ypos - j)**2) < DotRadius:
            Shadows[j][i] = colours[1]

  im = Image.fromarray(Shadows.astype('uint8')).convert('RGBA')
  im.save('result_test_image'+str(SensorNum)+'.png')

  #This for loop below is the bottle-neck. Can its speed be improved?
  if SensorNum > 0:
    for i in range(w):
      for j in range(h):
        #White space dominates.
        #(pixel by pixel) If the current images pixel is white and the unfinshed Final
        #images pixel is blue then set the final pixel to white.
        if np.all(Shadows[j][i]==colours[0]) and np.all(Final[j][i]==colours[1]):
          Final[j][i] = colours[0]
  else:
    Final = copy.deepcopy(Shadows)

im = Image.fromarray(Final.astype('uint8')).convert('RGBA')
im.save('result_final_test.png')

最后一个嵌套for循环是我感兴趣的改进之处。 这很好,但是迭代是一个巨大的瓶颈。是否有任何方法可以通过使用矢量等更快地实现这一点?你知道吗


Tags: theinfornprange像素finalpixel
1条回答
网友
1楼 · 发布于 2024-10-16 17:21:11

当然,可以对代码中的最后一个for循环进行矢量化,因为每次迭代都不依赖于之前在迭代中计算的值。 但老实说,这并不像我想象的那么容易。。。你知道吗

我的方法比你现在的循环快800到1000倍。我使用下划线将大写数组和变量名替换为小写名称。大写通常是为python中的类保留的。这就是为什么你的问题中出现奇怪的代码颜色。你知道吗

if sensor_num > 0:
    mask = (  # create a mask where the condition is True
        ((shadows[:, :, 0] == 255) &  # R=255
         (shadows[:, :, 1] == 255) &  # G=255
         (shadows[:, :, 2] == 255)) &  # B=255
        ((final[:, :, 0] == 0) &  # R=0
         (final[:, :, 1] == 0) &  # G=0
         (final[:, :, 2] == 255)))  # B=255
    final[mask] = np.array([255, 255, 255])  # set Final to white where mask is True
else:
    final = copy.deepcopy(shadows)

当然,RGB值可以替换为预定义值的查找,就像您的coloursdict。但我建议使用数组来存储颜色,特别是如果你打算用数字来索引它:

colours = np.array([[255, 255, 255], [0, 0, 255]])

所以面具看起来像:

mask = (  # create a mask where the condition is True
    ((shadows[:, :, 0] == colours[0, 0]) &  # R=255
     (shadows[:, :, 1] == colours[0, 1]) &  # G=255
     (shadows[:, :, 2] == colours[0, 2])) &  # B=255
    ((final[:, :, 0] == colours[1, 0]) &  # R=0
     (final[:, :, 1] == colours[1, 1]) &  # G=0
     (final[:, :, 2] == colours[1, 2])))  # B=255
final[mask] = colours[0]  # set Final to white where mask is True

当然,这也适用于使用dict。你知道吗

为了进一步加快速度,可以将掩蔽中的RGC比较替换为与数组本身的比较(模板计算)。对于您的数组大小,这大约快5%,速度差随着数组大小的增加而增加,但是您只需更改colours数组/dict中的条目,就失去了比较其他颜色的灵活性。 具有模具操作的遮罩如下所示:

mask = (  # create a mask where the condition is True
    ((shadows[:, :, 0] == shadows[:, :, 1]) &  # R=G
     (shadows[:, :, 1] == shadows[:, :, 2]) &  # G=B
     (shadows[:, :, 2] == colours[0, 2])) &  # R=G=B=255
    ((final[:, :, 0] == final[:, :, 1]) &  # R=G
     (final[:, :, 1] == colours[1, 1]) &  # G=0
     (final[:, :, 2] == colours[1, 2])))  # B=255

这将大大加快你的计算速度。你知道吗

其他部分代码也可以优化。当然,如果这不是瓶颈的话,这是值得的。 仅举一个例子:不必调用random.randint每个循环,您可以调用它一次,然后创建一个随机数组(以及+-DotRadius数组),然后在此数组上循环:

ypos = np.random.randint(DotRadius, h-DotRadius, size=NumberOfDots)
ypos_plus_dot_radius = ypos + DotRadius
ypos_minus_dot_radius = ypos - DotRadius
xpos = np.random.randint(DotRadius, w-DotRadius, size=NumberOfDots)
xpos_plus_dot_radius = xpos + DotRadius
xpos_minus_dot_radius = xpos - DotRadius
for dot in range(NumberOfDots):
    yrange = np.arange(ypos_minus_dot_radius[dot], ypos_plus_dot_radius[dot])  # make range instead of looping
    # looping over xrange imho can't be avoided without further matrix operations
    for i in range(xpos_minus_dot_radius[dot], xpos_plus_dot_radius[dot]):
        # make a mask for the y-positions where the condition is true and
        # index the y-axis of Shadows with this mask:
        Shadows[yrange[np.sqrt((xpos[dot] - i)**2 + (ypos[dot] - yrange)**2) < DotRadius], i] = colours[1]
        # colours[1] can of course be replaced with any 3-element array or single integer/float

相关问题 更多 >