【问题标题】:OpenCV multicolor thresholdingOpenCV 多色阈值
【发布时间】:2014-02-18 15:24:57
【问题描述】:

我正在尝试对 opencv cv2 图像进行多色阈值处理。我要解决的问题如下:

  • R、G、B 各有一个“有效”列表
  • 如果一个像素的 R、G、B 都认为有效,则将该像素设为 (0,0,0),否则设为 (255,255,255)

例如

  • [221, 180, 50] 被认为在 R 通道中有效
  • [23,18,2]被认为在G通道有效
  • [84,22,48]在B通道被认为有效

那么如果一个像素有以下任何一个值(RGB顺序)

  • (221, 23, 84)
  • (221, 23, 22)
  • (221, 23, 48)
  • (221, 18, 84)
  • (221, 18, 22)
  • (221, 18, 48)
  • ...
  • (50, 2, 48)

将转化为 (0,0,0),否则为 (255,255,255)

目前,我正在使用嵌套的 for 循环来执行此操作:

for x in range(width):
    for y in range(height):
        imcv[y, x] = threshold(imcv[y, x])

其中threshold 函数执行上述逻辑。请注意,虽然我在原地进行了此操作,但不需要原地转换。

我目前使用的方法有效,但是速度很慢。我相信在 OpenCV/Numpy 中一定有更好的方法。我对这两个框架都很陌生,不知道怎么做。

我研究了 OpenCV 阈值函数,似乎它们只能在单通道灰度图像上工作,而且范围需要是连续范围。我需要的是对离散值的所有 3 个通道进行阈值处理。我想需要一个自定义函数才能传入,但我无法在他们的文档中找到正确的 API。

我还查找了我可以使用的可能 numpy API,例如 ufunc。似乎我无法在这里使用它实现我想要的,或者我没有看到如何。

感谢任何帮助。

编辑:

感谢 AbidRahmanK 和 HYRY,这两种解决方案的性能提升超过了 1500 倍。

ncalls  tottime  percall  cumtime  percall filename:lineno(function)
     1    1.576    1.576    1.576    1.576 test.py:48(preprocess_cv2_image)
     1    0.000    0.000    0.001    0.001 test.py:79(preprocess_cv2_image3)
     1    0.000    0.000    0.001    0.001 test.py:66(preprocess_cv2_image2)

【问题讨论】:

  • 首先,使用xrange 而不是range。后者实际上构建了一个指定大小的整个列表,然后您对其进行迭代,而前者返回一个生成器,它不必预先计算整个列表,并且允许您对其进行迭代。
  • 嗨@SchighSchagh,感谢您的建议。使用 range 的 C 实现肯定有帮助。我认为我的瓶颈是访问和更改 python 中的每个像素。我认为如果有一个 api 允许我将其推送到 numpy 或 opencv 的 C 实现中会大大加快速度。
  • [221,18,48] 也有效吗?
  • 嗨@AbidRahmanK 是的。

标签: python opencv numpy


【解决方案1】:

请试试这个:

z1 = np.dstack([np.in1d(img[...,0],B),np.in1d(img[...,1],G),np.in1d(img[...,2],R)]).reshape(img.shape)
q = np.all(z1,axis=2)
out = np.uint8(q)*255

np.in1d(a,b) 给你一个与 a 相同长度的布尔数组,如果该元素在 b 中,则 True,否则为 False。它只是 Python 中 in 方法的矢量化对应物。或者简而言之:

np.in1d(a,b) [True for i in a if i in b else False]

您对所有通道执行此操作,即检查第一个通道在 B 中的有效值,第二个使用 G,第三个使用 R。

然后使用np.dstack 在 z 方向上堆叠它们。为什么是z方向?因为我们想要 BGR-BGR-BGR... 格式。

但请记住,这是一维数组,因此我们使用X.reshape(img.shape) 方法将其重塑为原始图像形状。

所以现在你有一个布尔掩码,如果有效则为 True,否则为 False。

全部都在第一行代码中。

现在您想查看有效的 BGR 组合。如果所有 B、G、R 分量均为 True,则组合有效。所以你在 z 方向上应用 np.all() 。你再次得到一个布尔掩码 q

q 将是一个布尔掩码,有效颜色为 True,其他颜色为 False。

所以你转换成整数数据类型,True --> 1 和 False --> 0

然后你把它乘以255。如果你想要倒置的图像,你可以使用np.bitwise_not

【讨论】:

  • 嗨@AbidRahmanK,感谢您的回答!你能解释一下代码吗?我想让你的 sn-p 适应我的代码并测试性能,但我无法让它输出 cv2 图像。
  • 现在试试out = np.uint8(q)*255。我会尽快更新答案。
  • 如果它解决了您的问题,您可以投票并接受答案
【解决方案2】:

你可以为R、G、B做三个布尔数组,如果值对R有效,那么R[value]为True,那么你可以使用Rm[img[:, :, 2]] & Gm[img[:, :, 1]] & Bm[img[:, :, 0]]得到结果:

import numpy as np

img = np.random.randint(0, 256, (2000, 2000, 3))

def make_mask(idx):
    b = np.zeros(256, np.bool)
    b[idx] = True
    return b

R = [221, 180, 50]
G = [23, 18, 2]
B = [84, 22, 48]


Rm, Gm, Bm = [make_mask(v) for v in [R, G, B]]
a = Rm[img[:, :, 2]] & Gm[img[:, :, 1]] & Bm[img[:, :, 0]]

最后,得到结果图片:

v = np.array([[255,255,255], [0,0,0]], np.uint8)
v[a.astype(np.uint8)]

【讨论】:

  • 谢谢@HYRY,表现很棒。你的方法很容易理解。我给 AbidRahmanK 打分,因为他先回答。
猜你喜欢
  • 1970-01-01
  • 2016-11-15
  • 2014-05-07
  • 2019-12-03
  • 2019-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-24
相关资源
最近更新 更多