简体   繁体   English

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

[英]How to replace all RGB values in an image if that RGB value belongs to a list

I need to change all RGB values in an image if that RGB value is on my list without a loop.如果 RGB 值在我的列表中没有循环,我需要更改图像中的所有 RGB 值。

I know that in order to change a RGB value I just need to do this:我知道为了更改 RGB 值我只需要这样做:

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

But the value (99, 121, 109) in my case belongs to a list, for example但是我的值(99, 121, 109)属于一个列表,例如

   rgbL = [[99, 121, 109], 
           [102, 118, 107], 
           [102, 126, 114], 
                   .......,
           [105, 114, 101]]

In order to change ALL RGB values in an image that belongs to my rgbL list, I need to loop to ALL values of my rgbL .为了更改属于我的rgbL列表的图像中的所有 RGB 值,我需要循环到我的rgbL的所有值。 But my list is too long.但是我的清单太长了。 Is there a way that I can do this without a loop?有没有办法不用循环就可以做到这一点?

Unfortunately there is no fast way to do this.不幸的是,没有快速的方法可以做到这一点。 Whether you use a loop or an optimized numpy solution, under the hood you have to check each pixel against each element of rgbL .无论您使用循环还是优化的 numpy 解决方案,在幕后您都必须针对rgbL的每个元素检查每个像素。 Given all that, you can use isin combined with a structured array view of the data to perform the correct grouping.考虑到所有这些,您可以使用isin结合数据的结构化数组view来执行正确的分组。

The trick is to make a custom type that represents pixels.诀窍是创建一个表示像素的自定义类型 That way, you can compare entire elements rather than color channels, which is what isin does by default.这样,您就可以比较整个元素而不是颜色通道,这是默认情况下isin所做的。

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

You can not define the pixel datatype as a sub-array type like this pixel = np.dtype((img.dtype, img.shape[-1])) .您不能将像素数据类型定义为像这样的子数组类型pixel = np.dtype((img.dtype, img.shape[-1])) That will cause an error when you try to view the data.当您尝试查看数据时,这将导致错误。

You can now view img as a 2D array of pixel elements, rather than a 3D array of uint8 or float , as the case may be:您现在可以将img视为pixel元素的二维数组,而不是 3D 数组uint8float ,视情况而定:

data = img.view(pixel).squeeze(axis=-1)

You can do the same with your list:您可以对列表执行相同的操作:

rgbA = np.array(rgbL).view(pixel).squeeze(axis=-1)

You can also do你也可以做

rgbA = np.array([tuple(p) for p in rgbL], dtype=pixel)

You can't use np.array(rgbL, dtype=pixel) because the elements will not be initialized correctly in this case.您不能使用np.array(rgbL, dtype=pixel)因为在这种情况下元素不会被正确初始化。

Now isin will give you the mask you want:现在isin会给你你想要的面具:

mask = np.isin(data, rgbA)

You can apply the mask directly:您可以直接敷面膜:

data[mask] = 255

If you want to set a value that differs between channels, remember to use a tuple to specify pixel entries:如果要设置不同通道的值,请记住使用元组来指定像素条目:

>>> 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

Since data is a view into img , you are done.由于dataimg的视图,因此您已完成。

Note: This will only work if your image is contiguous in the third dimension.注意:这仅在您的图像在三维空间中是连续的时才有效。 Otherwise, you will not be able to use the same datatype for both arrays. If that is not the case, you will have to copy the image data so that it is contiguous at least in the third dimension.否则,您将无法对两个 arrays 使用相同的数据类型。如果不是这种情况,您将必须复制图像数据,使其至少在三维上是连续的。 For most sane arrays that aren't weird views across a hyperspectral image or something, you will be OK.对于大多数理智的 arrays 不是高光谱图像或其他东西的奇怪视图,你会没事的。

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)

if this works for a single colour:如果这适用于单一颜色:

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

this should work for a list:这应该适用于列表:

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

use a cv2 LUT (look up table) - you can define your own and specify your replacements directly that way.使用 cv2 LUT(查找表)——您可以定义自己的 LUT 并直接指定您的替换项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM