【问题标题】:Filter numpy image array by multiple conditions as fast as possible尽可能快地按多个条件过滤 numpy 图像数组
【发布时间】:2021-07-23 16:22:29
【问题描述】:

我需要在游戏运行时找到特定像素(BGR 格式)的坐标,

(我保存截图只是为了测试,程序自己连续截图)。

这是我需要的一个工作循环示例

s = np.array(Image.open("image.png"))
cr = []
for y in range(338):
    for x in range(326):
        C = s[y, x]
        if C[1] < 25 and 20 <= C[0] < 25 and 130 < C[2] < 215:
            cr.append((y, x))

但是 for 循环需要 1.03 秒,这对我的任务来说非常慢,所以我尝试了

cr = s[(20 < s[:,][:,0]) & (s[:,][:,0] < 25) & (s[:,][:,1] < 25) & (130 < s[:,][:,2]) & (s[:,][:,2] < 215)]

但它返回错误IndexError: boolean index did not match indexed array along dimension 1; dimension is 415 but corresponding boolean dimension is 3

那么我需要如何以最快的方式完成它?

编辑:

示例图片:

【问题讨论】:

  • 您不能对numpy 使用链式比较。 (Numpy chain comparison with two predicates)
  • @HenryEcker 好的,我编辑了描述
  • 这需要一个最小的例子,因为我只是把那个单行代码放在我的解释器中,它没有抱怨,所以我们不得不看到它失败了。
  • 而且s[:,]s 不一样吗?
  • 最好的计划是分享您的实际图像和您实际寻找的内容,并说明您打算如何处理结果。

标签: python numpy


【解决方案1】:

我会这样写你的条件:

c = (s[...,1] < 25) & (20 < s[...,0]) & (s[...,0] < 25) & (130 < s[...,2]) & (s[...,2] < 215)
cr = np.argwhere(c)

您得到的错误是因为s 的形状与您放在括号内的任何形状不同。其他cmets:

  • 颜色轴是最后一个,而不是第二个
  • s[:,]s 相同

在您上面发布的示例图片中,我得到:

In [3]: s.shape
Out[3]: (326, 338, 3)

In [4]: (20 < s[:,:,0]).shape
Out[4]: (326, 338)

这是因为通过将一个维度的索引设置为一个固定值,您就可以摆脱该维度。那没关系,但你也摆脱了错误的维度。

【讨论】:

  • 这就是我需要的谢谢,但我想等待其他成员发布他们的答案(如果有的话)并接受最好的
  • @baronsec。现在你也有足够的声望来投票了!
【解决方案2】:

您可以使用广播显着减少这种情况。假设您有一个(M, N, 3) 数组s,带有M = 338N = 326。所有像素的上限阈值为[25, 25, 215]。通道 0 的阈值下限为 20(含),通道 2 的阈值为 130(不含)。你把这个表达为

cr = np.argwhere((s < [25, 25, 215]).all(-1) & (s[..., 0] >= 20) & (s[..., 2] > 130))

您必须在条件表达式周围加上括号,否则它们的优先级低于&amp;

表达式(s &lt; [25, 25, 215]) 由于广播而产生一个(M, N, 3) 布尔掩码。尺寸在右侧对齐,因此[25, 25, 215] 被视为(1, 1, 3),并有效地扩展为(M, N, 3)。沿最后一个轴的最终 all 通过检查给定像素的所有通道是否都通过各自的标准,将掩码减少到 (M, N)

您可以更进一步地采用这种方法,因为您使用的是整数。在这种情况下,x &gt;= 20 等价于x &gt; 19。所以你只需要两个条件:

cr = np.argwhere((s < [25, 25, 215]).all(-1) & (s[0::2] > [19, 130]).all(-1)

【讨论】:

  • 这比哈维尔的回答快两倍,但(s &lt; [25, 25, 215]).all(-1) 中实际发生了什么?
  • @baronsec。我已经大大更新了答案
【解决方案3】:

你必须使用numpy.argwherenumpy.logical_and

es:

matching_indexes = np.argwhere(np.logical_end(np.logical_and(s<3, s>50), s !=4))

【讨论】:

  • 这个并不完全有效,因为比较只针对其中一种颜色,但可以改进为分别处理这三个组件,然后再处理那些。
  • 它不应该完全正常工作。这只是展示如何使用np.argwherenp.logical_and 的示例。
猜你喜欢
  • 2022-09-24
  • 2015-06-12
  • 2018-11-23
  • 2021-10-20
  • 1970-01-01
  • 2016-12-19
  • 2015-07-12
  • 2018-04-20
相关资源
最近更新 更多