从 Python 中的图像中提取特定颜色范围的简单方法?

Simple method to extract specific color range from an image in Python?

我正在尝试使用 cv2 模块从定义的 RGB 范围内的图像中提取特定颜色。在下面的示例中,我试图将火焰与黄色和白色 RGB 值之间的 space 穿梭机的排气隔离开来,然后打印出该范围内的 RGB 值与图像其余部分相比的百分比。

这是我的最小工作示例:

import cv2
import numpy as np
from matplotlib import pyplot as plt
import imageio

img = imageio.imread(r"shuttle.jpg")
plt.imshow(img)

这是输出图像。 Its from wikipedia.

img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

color1 = (255,255,0) #yellow
color2 = (255,255,255) #white
boundaries = [([color1[0], color1[1], color1[2]], [color2[0], color2[1], color2[2]])]
for (lower, upper) in boundaries:
    lower = np.array(lower, dtype=np.uint8)
    upper = np.array(upper, dtype=np.uint8)
    mask = cv2.inRange(img, lower, upper)
    output = cv2.bitwise_and(img, img, mask=mask)
    ratio = cv2.countNonZero(mask)/(img.size/3)
    print('pixel percentage:', np.round(ratio*100, 2))
    plt.imshow(mask)

但这似乎不起作用,因为我在黄色和白色值之间得到 0% 的像素。我不太确定哪里出错了:

[([255, 255, 0], [255, 255, 255])]
pixel percentage: 0.0

并且输出图似乎是空白的 blue/purple 图像:

请注意,我没有使用 cv2 的内置图像查看器,例如 cv2.imshow()、cv2.waitKey() 和 cv2.destroyAllWindows(),因为调用它们会使我的 IDE(Spyder 3.3.1)在 Windows 8.1 上。不确定这是否是图像出现的原因 blue/purple?

另外,当我尝试输出原始图像时,它以一种奇怪的反转颜色格式出现:

plt.imshow(img)

无论如何,我之前尝试过使用类似的方法来检测特定的颜色范围 described here 但是,当我尝试实施时,该特定方法在编译过程中给我带来了问题,并且使我的计算机死机并崩溃了好几次像这样:

imask = mask>0
exhaust_color = np.zeros_like(img, np.uint8)
green[imask] = img[exhaust_color]

我想我在这里试图实现的是像下面的图像,其中只显示黄色和白色之间的颜色,然后打印出由这些颜色组成的像素的百分比。对于下图,我只是使用基本图像处理软件过滤掉了 RGB (255, 255, 0) 以下的所有颜色。

有没有办法使用我已经编写的代码或类似的代码来实现这一点?

编辑 1: 按照下面的建议首先转换为 HSV 颜色 space。但是它仍然不起作用,黄色到白色的像素百分比仍然是 0%。输出图仍然相同,显示全黑或紫色。我还设法通过将 1 传递给 cs2.waitKey(1) 来使 cv2.imshow() 工作。 (由于某种原因不适用于 0。)

#CONVERT TO HSV COLORS
hsv_img = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
color1 = np.uint8([[[0, 255, 255 ]]]) #yellow
color2 = np.uint8([[[255, 255, 255]]]) #white
hsv_color1 = cv2.cvtColor(color1,cv2.COLOR_BGR2HSV)
hsv_color2 = cv2.cvtColor(color2,cv2.COLOR_BGR2HSV)

print(hsv_color1)
print(hsv_color2)

#Define threshold color range to filter
mask = cv2.inRange(hsv_img, hsv_color1, hsv_color2)

# Bitwise-AND mask and original image
res = cv2.bitwise_and(hsv_img, hsv_img, mask=mask)
ratio = cv2.countNonZero(mask)/(hsv_img.size/3)
print('pixel percentage:', np.round(ratio*100, 2))
#plt.imshow(mask)

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

输出

[[[ 30 255 255]]]
[[[  0   0 255]]]
pixel percentage: 0.0

这是一个非常简单的问题;您在 cv2.inRange 之前给了较大的颜色,所以没有有效的交集!这是一些显示输出的工作代码。这应该很容易适应您自己的脚本。

import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread('shuttle.jpg')   # you can read in images with opencv
img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)

hsv_color1 = np.asarray([0, 0, 255])   # white!
hsv_color2 = np.asarray([30, 255, 255])   # yellow! note the order

mask = cv2.inRange(img_hsv, hsv_color1, hsv_color2)

plt.imshow(mask, cmap='gray')   # this colormap will display in black / white
plt.show()