【问题标题】:Mask of an image with a list of pixel values具有像素值列表的图像掩码
【发布时间】:2021-04-17 01:47:39
【问题描述】:

我想用列表中的值创建图像的蒙版。例如,我有一个尺寸为 (2, 5) 的 RGB 图像:

a = (np.random.rand(2, 5, 3) * 10).astype(int)

array([[[0, 5, 8],
        [9, 0, 2],
        [2, 2, 9],
        [9, 2, 4],
        [2, 5, 3]],

       [[7, 5, 7],
        [1, 9, 3],
        [4, 3, 3],
        [9, 1, 1],
        [9, 5, 5]]]

b = np.array([[0, 5, 8], [7, 5, 7], [4, 3, 3]])

array([[[0, 5, 8],
        [7, 5, 7],
        [4, 3, 3]]])

我想要做的是创建一个图像蒙版 a 保留像素值(每个像素值在列表 b 中的像素值列表中)跨 3 个 RGB 通道(第三维)。给定 a 和 b 的示例结果是:

array([[[True, True, True],          # check if [0, 5, 8] is in b
        [False, False, False],       # check if [9, 0, 2] is in b
        [False, False, False],       # check if [2, 2, 9] is in b
        [False, False, False],       # check if [9, 2, 4] is in b
        [False, False, False]],      # check if [2, 5, 3] is in b

       [[True, True, True],
        [False, False, False],
        [True, True, True],
        [False, False, False],
        [False, False, False]]]

或者输出可以是这样的,因为我们用像素值屏蔽了图像,因此可以省略第三维

array([[True,
        False,
        False,
        False,
        False],

       [True,
        False,
        True,
        False,
        False]]

我已经尝试过这些,但它们对于我的需要来说太慢了:

# A naive way using list comprehension. Slowest I've tried
mask = [[True if np.any(b == a[r, c, :]) else False
          for c in range(a.shape[1])] for r in range(a.shape[0])]

# I've tried this but it's probably a wrong solution since in1d flatten the array to compare
#them. I need the pixel to be compared across the 3rd dimension
mask = np.in1d(a[:, :,  (?)], b, invert=True).reshape(image.shape[:2])

# Fastest I've tried. Took around 4 seconds on my machine on an image with dimension
# (3000, 3000, 3). But apparently it's not fast enough
mask = np.zeros(image.shape[:2], dtype=np.bool)
for val in b:
    mask |= (a == b).all(-1)

感谢任何帮助:D

【问题讨论】:

  • 请提供ab 在真实环境中的实际预期尺寸。
  • @rayryeng 在我的用例中,a 的形状是 (3000, 3000, 3),而 b 的形状是 (16, 3)

标签: python numpy opencv image-processing matrix


【解决方案1】:

您可以尝试将每个 RGB 像素与[1,256,65536] 的点积“flatten” 每个像素转换为单个 24 位整数,然后您可以使用 np.in1d()

# Get some deterministic randomness ;-)
np.random.seed(42)

# Synthesize (hopefully) representative image and 16 colours
a = np.random.randint(0,256,(3000, 3000, 3), np.uint8)
b = np.random.randint(0,256,(16, 3), np.uint8)

# "Flatten" third dimension to single 24-bit number
a24 = np.dot(a.astype(np.uint32),[1,256,65536])
b24 = np.dot(b.astype(np.uint32),[1,256,65536])

# Now use np.in1d()
mask = np.in1d(a24,b24)

在我的 Mac 上,时间安排如下:

%timeit a24 = np.dot(a.astype(np.uint32),[1,256,65536])
153 ms ± 1.43 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

%timeit mask = np.in1d(a24,b24)
93.4 ms ± 400 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

【讨论】:

  • 这比我的掩蔽方法快得多(大约快 6 倍)。我不知道即使在具有数百万个元素的矩阵上,点积也这么快
  • 使用点积的好主意。
【解决方案2】:

使用广播试试这个解决方案。

aa = a[:, :, None, :]
bb = b[None, None]
mask = (aa == bb).any(axis=2).all(axis=-1)

我们得到:

In [57]: mask
Out[57]:
array([[ True, False, False, False, False],
       [ True, False,  True, False, False]])

说明

广播在这里很有用,因为我们希望在不循环的情况下跨维度复制信息。我们首先在a 中获取您的图像,并在axis=2 维度中引入一个单一维度,然后将通道移动到axis=3 维度。这使我们的数组具有四个维度。与b 类似,我们通过为第一维和第二维引入单维来使数组具有四个维度。完成此操作后,执行aa == bb 将对a 中的每个RGB 像素和b 中的每个RGB 像素进行逐元素相等检查。使用axis=2any 计算将检查a 中的任何像素是否与b 中的所有 元素匹配。如果发生这种情况,该像素的每个 RGB 通道都应等于 True。为了最终完成检查,如果每个 RGB 像素都是True,我们应该输出True,所以我们用axis=-1 结合all 来完成这个。这对于大图像应该很快,因为您只是更改视图。如果没有,它至少应该比您创建的 for 循环方法快。

【讨论】:

  • 它给出了正确的结果,但是它的运行速度比我的掩蔽解决方案慢得多(5s vs 90s)。感谢您谈论引入单例维度,我以前从未知道过它
  • 嗯,太糟糕了。那么也许坚持使用for 循环解决方案。有时,一个不优雅的解决方案可能会更快 - 这看起来就是其中之一。
【解决方案3】:

如果我是正确的,您想检查 a 的任何像素值是否在 b 中。 作为一个快速的解决方案,您可以通过一个简单的技巧来做到这一点。

[[str(j) in str(b) for j in i] for i in a]


[[True, False, False, False, False], [True, False, True, False, False]]

【讨论】:

  • 我不认为这就是我的意思。我编辑了问题以进一步澄清。无论如何,我试图避免列表理解,因为它比 numpy 矩阵运算慢。
  • @Trac3rZ 我认为这正是我所做的!试试这个解决方案,我觉得很快。
  • @BillyBonaros 您的解决方案是正确的,但它没有我需要的那么快 :( 我需要它足够快以处理数千个 3000x3000x3 矩阵,而不是上面的简单矩阵
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-01-21
  • 2018-07-28
  • 1970-01-01
  • 2013-09-12
  • 1970-01-01
  • 2021-05-20
相关资源
最近更新 更多