Python(Numpy)数组相等的函数很慢......有更快的方法吗?

时间:2017-02-05 09:15:40

标签: python numpy

我是一名正在学习Python的视觉艺术家,以创建一套指定的艺术作品。在一个方面,我使用2160x3840网格编写Conway经典的生命游戏。

然而,该程序运行速度比我希望的要慢:它已经在我三岁的iMac上运行了24小时,我只处理了两个半“帧”。运行需要数周时间,我还有几次运行。

我运行了SnakeViz并且我的程序时间的93%用于单个功能,其中主要活动是一系列比较。根据康威的规则,所有“雀色”颜色和flashOfLifeColor都被视为“实时”单元格。

def isLive (theColor):

    isCellLive = False
    finchColor_1 = numpy.array([247, 238, 214])
    finchColor_2 = numpy.array([202, 184, 88])
    finchColor_3 = numpy.array([103, 81, 68])
    flashOfLifeColor = numpy.array([249, 192, 0])

    if (numpy.array_equal(theColor, finchColor_1)) or
       (numpy.array_equal(theColor, finchColor_2)) or
       (numpy.array_equal(theColor,     finchColor_3)) or 
       (numpy.array_equal(theColor, flashOfLifeColor)):

        isCellLive = True

    return isCellLive

是否有更好(更快)的方式来编写if语句?除了优化之外我还能做些什么来加快速度吗?

谢谢,

- 达林

编辑:

这是调用isLive的函数,以帮助理解我在做什么。我还想再次提到我在Python编程方面很陌生,并且根本不了解对象编程,而不是任何高级技术 - 很难解读我所看到的Conway规则的一些实现。网络。

def countNeighborsNine(theArray, row, column):

    numberOfNeighbors = 0
    maxRow, maxColumn, depth = theArray.shape
    for rowModifier in range (-1,2):
        for columnModifier in range (-1, 2):

            rowNeighborPointer = (row + rowModifier) % maxRow
            columnNeighborPointer = (column + columnModifier) % maxColumn

            thePixel = theArray[rowNeighborPointer, columnNeighborPointer]

            if isLive(thePixel):
                numberOfNeighbors = numberOfNeighbors + 1

    return numberOfNeighbors

2 个答案:

答案 0 :(得分:2)

这是一个可能的解决方案。 R,G和B各自的图像颜色可能在0..255范围内。我会先将其转换为整个图像的唯一“颜色ID”(易于处理)。

cid = grid_r * 256 * 256 + grid_g * 256 + grid_b

对你的生死名单做同样的事情:

def get_id(a):
     return a[0] * 256 * 256 + a[1] * 256 + a[2]
live_colours = np.array([get_id(finchColor_1), get_id(finchColor_2), get_id(finchColor_3), get_id(flashOfLifeColor)])

现在,您可以在一个命令中获取所有“实时”单元格:

alive = np.in1d(cid, live_colours).reshape(cid.shape)

此处,alive将是TrueFalse元素的2160x3840数组。 np.in1d获取cid中的每个元素,如果它位于True,则返回live_colours。返回的数组是1-d,因此您需要将其重新整形为与原始图像相同的形状。

编辑 - 现在使用它来计算每个单元格的活动邻居数量。首先,我定义了一个二维滚动功能。

def shifter(x, a, b):
   return np.roll(np.roll(x, a, axis=0), b, axis=1)

我取alive数组,并在所有4个方面用“死”单元填充它:

width = 2160
height = 3840
biglive = np.zeros((width + 2, height + 2))
biglive[1:-1, 1:-1] = alive.astype(int)
live_count = shifter(biglive, -1, -1) + shifter(biglive, -1, 0) + shifter(biglive, -1, 1) + shifter(biglive, 0, -1) + shifter(biglive, 0, 1) + shifter(biglive, 1, -1) + shifter(biglive, 1, 0) + shifter(biglive, 1, 1)

我们忽略了最后填充的零个单元格。

live_count = live_count[1:-1, 1:-1]

这是一个2160x3840网格,其中每个单元格包含活动邻居的数量。我生成了一个随机图像,整个过程需要几秒钟来计算完整的2160x3840集的活动邻居数。

答案 1 :(得分:1)

只是有人建议你自己找到最好的方法。

  • 从一个纯粹的python项目开始,然后是一个numpy项目。

  • 分离游戏逻辑和可视化。

    例如,一个数组用于区分alive / dead,另一个用于计算邻居。 使用imshow(neighbors,cmap = my_conway_map)进行可视化。

  • 永远不要在numpy数组上使用for循环,它很慢。

最小例子:

world=randint(0,2,(5,5))
mask=ones((3,3))
mask[1,1]=0
neighb=scipy.signal.convolve2d(world,mask,'same')
subplot(121)
a=imshow(world,interpolation='none',cmap=cm.Greys)
subplot(122) 
colorbar()
b=imshow(neighb,interpolation='none')
show()

conway