OpenCV中的inRange()函数对RGB颜色空间有效,但对HSV颜色空间无效。

8
我已经生成了一张RGB和HSV格式的散点图,并使用inRange()函数从图中选取一个颜色进行阈值处理。
为了获得精确的RGB和HSV值,我使用paint.net的取色器获取RGB值,然后使用RGB to HSV转换器获取HSV值。

enter image description here

像素颜色和散点图是通过以下方式生成的:
img = cv2.imread('C:\\b_.jpg')
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)


pixel_colors = img.reshape((np.shape(img)[0]*np.shape(img)[1], 3))
norm = colors.Normalize(vmin=-1., vmax=1.)
norm.autoscale(pixel_colors)
pixel_colors = norm(pixel_colors).tolist()

h, s, v = cv2.split(img_hsv)
fig = plt.figure()
axis = fig.add_subplot(1, 1, 1, projection="3d")

axis.scatter(h.flatten(), s.flatten(), v.flatten(), facecolors=pixel_colors, marker=".")
axis.set_xlabel("Hue")
axis.set_ylabel("Saturation")
axis.set_zlabel("Value")
plt.show()

我需要从我的图片中提取黄色。如上所述,我正在使用paint.net颜色选择器获取浅黄和深黄的RGB值。然后使用转换器获取inRange()函数的HSV值。
light_yellow = (60, 89, 97)    # HSV VALUES
dark_yellow = (61, 36.6, 43.9)

mask = cv2.inRange(img_hsv, light_yellow, dark_yellow)
result = cv2.bitwise_and(img, img, mask=mask)

但是生成的结果是一张黑色的图像,但是如果我直接使用浅黄色和深黄色的RGB值,并使用RGB图像而不是HSV转换后的图像,则分割可以正常工作。
light_yellow = (249, 249, 125)    # RGB VALUES
dark_yellow = (111, 112, 71)

mask = cv2.inRange(img, light_yellow, dark_yellow)
result = cv2.bitwise_and(img, img, mask=mask)

enter image description here

尽管上述是RGB分割,但我觉得在HSV方面可能会有所改进。为什么我的HSV范围没有输出?

HSV 没有一个单一的一致定义。如果您想要比较颜色,您应该始终使用相同的软件进行转换。 - Cris Luengo
只是一个小建议,尝试使绘图的颜色更加统一(没有阴影),否则一些点在你进行筛选时将不可见。(例如左侧的灰色点与黄色点相比) - api55
1个回答

12

根据cvtColor文档中的说明,当输入参数为CV_8U时,H值通常从0到360,但会除以2变成0-180。而S和V值通常是百分比(0-100%),它们范围从0到255。

因此您的值:

light_yellow = (60, 89, 97)    # HSV VALUES
dark_yellow = (61, 36.6, 43.9)

应该更像:

# (H/2, (S/100) * 255, (V/100) * 255) 
light_yellow = (30, 227, 247)    # HSV VALUES
dark_yellow = (31, 93, 112)

现在你有另一个问题,inRanges 寻找低限和高限范围内的值,而不是浅黄色和深黄色。因此,您的限制应为:

low = (30,93,112)
high = (31, 227,247)

mask = cv2.inRange(img_hsv, low, high)

还有一件事,我会使用更大的H色值范围...30-31太小了,也许20-32更好?


你能详细解释一下,你是如何从第二步:light_yellow = (30, 227, 247) # HSV VALUES dark_yellow = (31, 93, 112)到第三步的吗?在第二步中,你只是根据openCV使用的范围“标准化”了这些值,但我不明白你是如何得出最后一部分的。 - Raleigh L.
1
@RaleighL. 抱歉回复晚了。我只是在两种颜色中取最小值来生成低值,并在两种颜色之间取最大值来生成高值。类似于: low =(min(light_yellow [0],dark_yellow [0]),min(light_yellow [1],dark_yellow [1]),min(light_yellow [2],dark_yellow [2])) 用于低值,高值也类似但使用max。 - api55

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接