0

我正在python中尝试一个简单的嵌套for循环来扫描阈值图像以检测白色像素并存储它们的位置。问题是,虽然它正在读取的数组只有 160*120 (19200),但它仍然需要大约 6s 才能执行,我的代码如下,任何帮助或指导将不胜感激:

im = Image.open('PYGAMEPIC')

r, g, b = np.array(im).T
x = np.zeros_like(b)

height = len(x[0])
width = len(x)

x[r > 120] = 255                                        
x[g > 100] = 0                                      
x[b > 100] = 0              

row_array = np.zeros(shape = (19200,1))
col_array = np.zeros(shape = (19200,1))

z = 0
for i in range (0,width-1):
    for j in range (0,height-1):
        if x[i][j] == 255:
            z = z+1
            row_array[z] = i

            col_array[z] = j
4

2 回答 2

2

首先,它不应该花费 6 秒。在 160x120 图像上尝试您的代码对我来说大约需要 0.2 秒。

也就是说,为了获得良好的numpy性能,您通常希望避免循环。有时沿除最小轴外的所有轴进行矢量化并沿该轴循环会更简单,但如果可能,您应该尝试一次完成所有操作。这通常会使事情变得更快(将循环向下推到 C)和更容易。

你的 for 循环本身对我来说似乎有点奇怪——你似乎在开始存储结果的位置(你的第一个值放在z=1,而不是z=0)和如何您正在寻找的距离(range(0, x-1)不包括x-1,因此您缺少最后一行/列-可能是您想要range(x)的。)

如果您想要的只是索引 wherer > 120但既不是g > 100nor b > 100,还有更简单的方法。我们可以创建布尔数组。例如,首先我们可以制作一些虚拟数据:

>>> r = np.random.randint(0, 255, size=(8,8))
>>> g = np.random.randint(0, 255, size=(8,8))
>>> b = np.random.randint(0, 255, size=(8,8))

然后我们可以找到满足我们条件的地方:

>>> (r > 120) & ~(g > 100) & ~(b > 100)
array([[False,  True, False, False, False, False, False, False],
       [False, False,  True, False, False, False, False, False],
       [False,  True, False, False, False, False, False, False],
       [False, False, False,  True, False,  True, False, False],
       [False, False, False, False, False, False, False, False],
       [False,  True, False, False, False, False, False, False],
       [False, False, False, False, False, False, False, False],
       [False, False, False, False, False, False, False, False]], dtype=bool)

然后我们可以np.where用来获取坐标:

>>> r_idx, c_idx = np.where((r > 120) & ~(g > 100) & ~(b > 100))
>>> r_idx
array([0, 1, 2, 3, 3, 5])
>>> c_idx
array([1, 2, 1, 3, 5, 1])

我们可以通过索引回 、 和 来对这些进行健全rg检查b

>>> r[r_idx, c_idx]
array([166, 175, 155, 150, 241, 222])
>>> g[r_idx, c_idx]
array([ 6, 29, 19, 62, 85, 31])
>>> b[r_idx, c_idx]
array([67, 97, 30,  4, 50, 71])
于 2013-05-04T15:44:02.420 回答
0

e 您使用的是 python 2.x(2.6 或 2.7)。在 python 2 中,每次调用时,range您都会创建一个包含这么多元素的列表。(在这种情况下,您要创建 1 个width - 1长度列表,然后width - 1是长度列表height - 1。加快此过程的一种方法是提前制作每个列表并每次使用该列表。

例如

height_indices = range(0, height - 1)
for i in range(0, width - 1):
    for j in height_indices:
        # etc

为了防止 python 必须创建任何一个列表,您可以使用xrange返回一个生成器,这将节省内存和时间,例如,

for i in xrange(0, width - 1):
    for j in xrange(0, height - 1):
        # etc.

您还应该考虑使用filter接受一个函数并执行它的函数。它将返回该函数返回的项目列表,但如果您所做的只是增加全局计数器并修改全局数组,则您不必返回任何内容或关注返回的列表。

于 2013-05-04T15:27:29.363 回答