Numpy where() 创建与定义颜色不同的点

Numpy where() creates spots of different color than the ones defined

我正在编写一个为图像创建遮罩的脚本。我的输入图像如下所示:

原图只有40x40px,仅供参考:

我想为图像中心的紫色区域创建一个遮罩。这就是我所做的:

# read the 40x40 image and convert it to RGB
input_image = cv2.cvtColor(cv2.imread('image.png'), cv2.COLOR_BGR2RGB)
# get the value of the color in the center of the image
center_color = input_image[20, 20]
# create the mask: pixels with same color = 255 (white), other pixels = 0 (black)
mask_bw = np.where(input_image == center_color, 255, 0)
# show the image
plt.imshow(mask_bw)

大多数情况下,这工作得很好,但对于某些图像(比如我附在这个问题上的图像),我的蒙版中总是出现一些蓝色区域,如下图所示。这是可重现的,并且相同输入图像的区域始终相同。

这已经够奇怪了,但如果我尝试删除蓝色区域,这也不起作用。

mask_bw[mask_bw != (255, 255, 255)] = 0 # this doesn't change anything..

为什么会发生这种情况,我该如何解决?

附加信息

主要问题是您尝试比较三个通道,但只为一个通道设置值。这很可能导致面罩上出现蓝色区域。当您使用 np.where() 将其他像素设置为黑色时,您只是在第一个通道而不是所有三个通道上设置它。您可以通过拆分每个通道并打印 before/after 数组来可视化这一点,这将向您显示生成的数组值为 RGB(0,0,255)。因此,为了解决这个问题,我们需要比较每个单独的通道,然后将所需区域设置为白色,同时将所有三个通道的蒙版上的任何黑色区域设置为黑色。这是一种方法:

import numpy as np
import cv2

image = cv2.imread('1.png')
center_color = image[20, 20]

b, g, r = cv2.split(image)
mask = (b == center_color[0]) & (g == center_color[1]) & (r == center_color[2])
image[mask] = 255 
image[mask==0] = 0

cv2.imshow('image', image)
cv2.waitKey()

使用当前代码删除蓝色区域的修补程序是将图像转换为灰度(1 通道),然后将所有非白色像素更改为黑色。

import numpy as np
import cv2

# Load image, find color, create mask
image = cv2.imread('1.png')
center_color = image[20, 20]
mask = np.where(image == center_color, 255, 0)
mask = np.array(mask, dtype=np.uint8)

# Convert image to grayscale, convert all non-white pixels to black
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY)
mask[mask != 255] = 0

cv2.imshow('mask', mask)
cv2.waitKey()

这里有两种获取紫色区域遮罩的替代方法

方法 #1: 灰度工作 space

import numpy as np
import cv2

image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
center_color = gray[20, 20]

mask = np.array(np.where(gray == center_color, 255, 0), dtype=np.uint8)

cv2.imshow('mask', mask)
cv2.waitKey()

方法 #2: 颜色阈值

想法是将图像转换为 HSV 颜色 space 然后使用较低和较高的颜色范围来分割图像以创建二进制掩码

import numpy as np
import cv2

image = cv2.imread('1.png')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower = np.array([0, 124, 0])
upper = np.array([179, 255, 255])
mask = cv2.inRange(hsv, lower, upper)

cv2.imshow('mask', mask)
cv2.waitKey()

两种方法应该产生相同的结果

如果你有一个 3 通道图像(即 RGB 或 BGR 或类似的)并且你想为每个像素生成一个通道掩码(即你想要 0/1 或 True/False),那么你实际上需要使用 np.all() 将 3 个值组合成一个值,如下所示:

import cv2 
import numpy as np

# Load image and get centre colour
image = cv2.imread('40x40.png') 
cc = im[20, 20] 

print(image.shape)                                                                                
(40, 40, 3)

# Generate list of unique colours present in image so we know what we are dealing with
print(np.unique(im.reshape(-1,3), axis=0))

array([[140, 109, 142],
       [151, 106, 140],
       [160, 101, 137],
       [165, 134, 157],
       [175, 149, 171],
       [206,  87, 109],
       [206, 185, 193]], dtype=uint8)

# Generate mask of pixels matching centre colour
mask_bw = np.where(np.all(im==cc,axis=2), 255, 0)

# Check shape of mask - no 3rd dimension !!!
print(mask_bw.shape)

(40, 40)

# Check unique colours in mask
print(np.unique(mask_bw.reshape(-1,1), axis=0))

array([[  0],
       [255]])