如果图像中的 RGB 值在我的列表中且没有循环,我需要更改该图像中的所有 RGB 值。
我知道为了改变 RGB 值我只需要这样做:
img[np.all(img == (99, 121, 109), axis=-1)] = (255,255,255)
但是,例如,在我的例子中,值 (99, 121, 109)
属于一个列表
rgbL = [[99, 121, 109],
[102, 118, 107],
[102, 126, 114],
.......,
[105, 114, 101]]
为了更改属于我的 rgbL
列表的图像中的所有 RGB 值,我需要循环到我的 rgbL
的所有值。但我的 list 太长了。有没有一种方法可以在不循环的情况下做到这一点?
最佳答案
不幸的是,没有快速的方法可以做到这一点。无论您使用循环还是优化的 numpy 解决方案,在幕后您都必须对照 rgbL 的每个元素检查每个像素。鉴于此,您可以使用 isin
与 structured array 结合view
数据以执行正确的分组。
诀窍是制作一个 custom type代表像素。这样,您就可以比较整个元素而不是颜色 channel ,这是 isin
默认情况下所做的。
pixel = np.dtype([('r', img.dtype), ('g', img.dtype), ('b', img.dtype)])
您不能将像素数据类型定义为子数组类型,如 pixel = np.dtype((img.dtype, img.shape[-1]))
。当您尝试查看数据时,这将导致错误。
您现在可以将 img
视为 pixel
元素的 2D 数组,而不是 uint8
或 float< 的 3D 数组
,视情况而定:
data = img.view(pixel).squeeze(axis=-1)
您可以对列表执行相同的操作:
rgbA = np.array(rgbL).view(pixel).squeeze(axis=-1)
你也可以这样做
rgbA = np.array([tuple(p) for p in rgbL], dtype=pixel)
您不能使用np.array(rgbL, dtype=pixel)
,因为在这种情况下元素将无法正确初始化。
现在 isin
将为您提供您想要的掩码:
mask = np.isin(data, rgbA)
可以直接敷面膜:
data[mask] = 255
如果要设置 channel 之间不同的值,请记住使用元组来指定像素条目:
>>> data[mask] = (255, 255, 255) # OK
>>> data[mask] = [255, 255, 255]
ValueError: NumPy boolean array indexing assignment cannot assign 3 input values to the 1 output values where the mask is true
由于 data
是 img
的 View ,因此您已完成。
注意:仅当您的图像在三维空间中连续时,此方法才有效。否则,您将无法对两个数组使用相同的数据类型。如果不是这种情况,您将必须复制图像数据,以便它至少在三维空间中是连续的。对于大多数在高光谱图像或其他东西上不是奇怪 View 的正常阵列,你会没事的。
TL;DR
pixel = np.dtype([('r', img.dtype), ('g', img.dtype), ('b', img.dtype)])
def replace(img, pixels, value):
data = img.view(pixel).squeeze(-1)
pixels = np.array(pixels, dtype=img.dtype).view(pixel).squeeze(-1)
data[isin(data, pixels)] = tuple(value)
关于python - 如果该 RGB 值属于列表,如何替换图像中的所有 RGB 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61850743/