如果RGB值属于列表,如何替换图像中的所有RGB值

2024-09-19 23:37:01 发布

您现在位置:Python中文网/ 问答频道 /正文

我需要更改图像中的所有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列表中的所有值。但是我的名单太长了。有没有一种方法可以不用循环就可以做到这一点


Tags: 方法图像列表imgnprgball例子
3条回答

不幸的是,没有快速的方法可以做到这一点。无论您使用循环还是优化的numpy解决方案,在引擎盖下,您都必须根据rgbL的每个元素检查每个像素。考虑到所有这些,您可以使用^{}与数据的structured array^{}组合来执行正确的分组

诀窍是制作一个表示像素的custom type。这样,您可以比较整个元素,而不是颜色通道,这是默认情况下isin所做的

pixel = np.dtype([('r', img.dtype), ('g', img.dtype), ('b', img.dtype)])

不能将像素数据类型定义为这样的子数组类型pixel = np.dtype((img.dtype, img.shape[-1]))。这将在您尝试查看数据时导致错误

现在,您可以将img视为pixel元素的2D数组,而不是uint8float的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

如果要设置通道之间不同的值,请记住使用元组指定像素条目:

>>> 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的一个视图,所以就完成了

注意:仅当图像在三维中连续时,此操作才有效。否则,您将无法对两个阵列使用相同的数据类型。如果不是这样,则必须复制图像数据,使其至少在第三维中是连续的。对于大多数正常的阵列来说,它们不是超光谱图像或其他东西上的奇怪视图,你会没事的

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)

如果这适用于单一颜色:

img[np.all(img == (99, 121, 109), axis=-1)] = (255,255,255)

这应该适用于以下列表:

img[np.all(img in rgbL, axis=-1)] = (255,255,255)

使用cv2 LUT(查找表)-您可以定义自己的表,并通过这种方式直接指定替换表

相关问题 更多 >