Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/287.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python NumPy 2D阵列迭代速度_Python_Arrays_Python Imaging Library - Fatal编程技术网

Python NumPy 2D阵列迭代速度

Python NumPy 2D阵列迭代速度,python,arrays,python-imaging-library,Python,Arrays,Python Imaging Library,我有一个循环,它用PIL的像素信息填充二维NumPy数组,这个数组称为“阴影”。颜色不是白色就是蓝色。我想建立一个最终的形象,从这些地方的白色占主导地位。 i、 e.如果循环中的一个图像在坐标x、y上有一个蓝色像素,而循环中的另一个图像在同一坐标上有一个白色像素,则最终像素将为白色 这项工作目前由以下人员完成: import math, random, copy import numpy as np from PIL import Image, ImageDraw colours = {0:

我有一个循环,它用PIL的像素信息填充二维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')
导入数学、随机、复制
将numpy作为np导入
从PIL导入图像,ImageDraw
颜色={0:(255255),1:(0,0255)}
#感兴趣区域的宽度和高度
w=100#100米
h=200#200米
点数=10
点半径=20
运行次数=3
Final=np.数组([[颜色[0]表示范围内的x(w)]表示范围内的y(h)])
阴影=np.阵列([[范围内x的颜色[0](w)]范围内y的颜色[0](h)])
对于范围内的SensorNum(运行次数):
阴影=np.阵列([[范围内x的颜色[0](w)]范围内y的颜色[0](h)])
对于范围内的点(点数):
ypos=random.randint(点半径,h点半径)
xpos=random.randint(点半径,w点半径)
对于范围内的i(xpos-点半径,xpos+点半径):
对于范围内的j(ypos-点半径,ypos+点半径):
如果数学sqrt((xpos-i)**2+(ypos-j)**2)0:
对于范围(w)内的i:
对于范围(h)内的j:
#空白占主导地位。
#(逐像素)如果当前图像的像素为白色,且最终为未对齐的
#图像像素为蓝色,然后将最终像素设置为白色。
如果np.all(阴影[j][i]==颜色[0])和np.all(最终[j][i]==颜色[1]):
最终[j][i]=颜色[0]
其他:
最终=复制。深度复制(阴影)
im=Image.fromarray(Final.astype('uint8')).convert('RGBA'))
保存('result\u final\u test.png'))
最后一个嵌套for循环是我感兴趣的改进之处。
这很好,但是迭代是一个巨大的瓶颈。通过使用一些向量化等,是否可以更快地实现这一点?

当然,可以对代码中的最后一个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值可以替换为预定义值的查找,如使用
颜色
dict
。但我建议使用数组来存储颜色,特别是如果您计划使用数字对其进行索引:

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%,速度差随着数组大小的增加而增加,但是您只需更改
颜色
数组/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
这将有助于大大加快计算速度

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

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
ypos=np.random.randint(点半径,h点半径,大小=NumberOfDots)
ypos加上点半径=ypos+点半径
ypos_减去点_半径=ypos-点半径
xpos=np.random.randint(点半径,w点半径,大小=NumberOfDots)
xpos加上点半径=xpos加点半径
xpos\u减去\u点\u半径=xpos-点半径
对于范围内的点(点数):
yrange=np.arange(ypos_减去点半径[dot],ypos_加上点半径[dot])#生成范围而不是循环
#如果没有进一步的矩阵运算,就无法避免在xrange imho上循环
对于范围内的i(xpos_减点半径[dot],xpos_加点半径[dot]):
#为条件为真且正确的y位置制作遮罩
#使用此遮罩索引阴影的y轴:
阴影[yrange[np.sqrt((xpos[dot]-i)**2+(ypos[dot]-yrange)**2)
我无法复制您的代码。Numpy数组无法快速存储元组。因此,我猜与你所说的相比,阴影不是一个数组。你能给出一个包含所有导入模块的工作示例吗?我更新了代码,所以你应该能够运行它。除非我错过了什么,否则看起来Ndaray可以容纳元组:-)谢谢!当然,对于这种情况有一种矢量化方法。几分钟后我会发布一个解决方案。但否:
ndarrays
无法容纳
tuple
s。Numpy正在将
元组
转换为具有形状
(3,)
的数组。这种方法的计算时间是使用数组的近2倍?我的答案的性能提升有多大?很抱歉耽搁了。感谢您指出Ndarray不能容纳元组,我真的不知道…非常感谢您的支持,以及非常详细的解释:-)。它大大缩短了我的代码执行时间。这个瓶颈基本上已经完全消失了!改进的大致数量级是,如您所说,大约为x1000。这段代码大约花了100秒