我在python中尝试一个简单的嵌套for循环来扫描阈值图像以检测白色像素并存储它们的位置。问题是虽然它正在读取的数组只有160 * 120(19200),但仍然需要大约6秒才能执行,我的代码如下,任何帮助或指导都将不胜感激:
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
答案 0 :(得分:2)
首先,它不应该花费6秒钟。在160x120图像上试用你的代码需要大约0.2秒。
也就是说,为了获得良好的numpy
性能,您通常希望避免循环。有时沿着除最小轴之外的所有向量进行矢量化并沿着它循环更简单,但是如果可能的话,你应该尝试一次完成所有事情。这通常会使事情变得更快(将循环推向C)并且更容易。
你的for循环本身对我来说有点奇怪 - 你似乎在开始存储结果的位置上有一个一个一个错误(你的第一个值放在z=1
,而不是z=0
)以及您所看到的距离(range(0, x-1)
不包括x-1
,所以您错过了最后一行/列 - 可能您想要{ {1}}。)
如果你想要的只是range(x)
而不是r > 120
和g > 100
的索引,那么有更简单的方法。我们可以创建布尔数组。例如,首先我们可以制作一些虚拟数据:
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])
,r
和g
来检查这些内容:
b
答案 1 :(得分:0)
你在python 2.x(2.6或2.7)上。在python 2中,每次调用range
时,您都会创建一个包含许多元素的列表。 (在这种情况下,您创建了一个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
长度列表。加快这一过程的一种方法是将每个列表提前一个时间和每次使用该列表。
例如
xrange
为了防止python必须创建任何一个列表,你可以使用for i in xrange(0, width - 1):
for j in xrange(0, height - 1):
# etc.
返回一个能节省内存和时间的生成器,例如,
filter
您还应该考虑使用{{1}}函数来获取函数并执行它。它将返回函数返回的项列表,但如果你正在做的只是递增全局计数器并修改全局数组,则不必返回任何内容或关注返回的列表。