什么是HSV颜色
HSV,HSL等(或在OpenCV中,HLS),是圆柱形色彩空间中的一个。
名称是某种描述的他们的价值观是如何引用。 (在OpenCV中,为了适应8位无符号整数格式,它们的度数除以2得到一个从0到179的数字;因此OpenCV中的110是220度)。如果您要采用色调值的“范围”,就像从蛋糕上切下一片。你只是吃了一些块蛋糕。
饱和通道距离您的中心有多远---您的半径。该中心绝对没有饱和度 - 只有从黑色到白色的灰色。如果您采用了这些值的范围,则类似于刮掉圆柱体的外部,或从中心切出一个圆。例如,如果范围是0到255,则范围0到127将是仅延伸到半径的一半的圆柱体; 127到255的范围将切割半径为半径的内圆柱体。
价值渠道是一个有点混乱的名字;它不是完全黑暗的亮度,因为最高值代表直接颜色,而最低值是黑色。这是圆柱体的高度。不难想象垂直切割圆柱体的切片。 HSV的
范围的值
功能cv2.inRange(image, lower_bound, upper_bound)
发现lower_bound
和upper_bound
之间的图像的所有值。举例来说,如果你的形象是一个3×3的图像(仅适用于简单演示的目的)与3通道,它可能是这个样子:
# h channel # s channel # v channel
100 150 250 150 150 100 50 75 225
50 100 125 75 25 50 255 100 50
0 255 125 100 200 250 50 75 100
如果我们想要选择100和200,然后我们lower_b
之间色调应该是[100, 0, 0]
和upper_b
应该是[200, 255, 255]
。这样我们的掩码只会考虑色调通道中的值,而不会受到饱和度和值的影响。这就是HSV如此受欢迎的原因---您可以通过色调来选择颜色,无论它们的亮度或黑度如何,只需指定色调通道的最小值和最大值即可选择深红色和鲜红色。
但是我们只想选择明亮的白色。回顾一下圆柱体模型---我们看到圆柱体的顶部中心处出现白色,因此其中s
值较低,而v
值较高,并且颜色角度无关紧要。所以lower_b
看起来像[0, 0, 200]
和upper_b
看起来像[255, 50, 255]
。这意味着所有的H
值将被包括在内,并不会影响我们的面具。但是只有S
值包括在0到50之间(朝向圆柱体的中心),并且只包括从200到255的V
值(朝向圆柱体的顶部)。
从HSV
一种方式来可视化的范围内的所有颜色可视化的颜色范围是创建梯度去两个方向为每两个信道的长度,然后进行动画通过改变第三通道。
例如,你从左至右为S
值的范围,由上到下为V
值的范围,然后遍历每个H
值可以创造价值的梯度。这整个程序可能是这个样子:
import numpy as np
import cv2
lower_b = np.array([110,50,50])
upper_b = np.array([130,255,255])
s_gradient = np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8)
v_gradient = np.rot90(np.ones((500,1), dtype=np.uint8)*np.linspace(lower_b[1], upper_b[1], 500, dtype=np.uint8))
h_array = np.arange(lower_b[0], upper_b[0]+1)
for hue in h_array:
h = hue*np.ones((500,500), dtype=np.uint8)
hsv_color = cv2.merge((h, s_gradient, v_gradient))
rgb_color = cv2.cvtColor(hsv_color, cv2.COLOR_HSV2BGR)
cv2.imshow('', rgb_color)
cv2.waitKey(250)
cv2.destroyAllWindows()
现在这个GIF显示了一个新的H
值每帧。从左到右,我们有最小值到最大值,而从上到下,我们有最小值到最大值V
值。此动画中显示的每一种颜色都将从您的图像中选择,作为您的mask
的一部分。
使自己INRANGE()函数
要充分认识OpenCV的功能,最简单的方法就是让自己的函数来完成任务。这并不难,也不是很多代码。
该功能背后的想法很简单:找到每个通道的值落在min
和max
之间,然后将所有通道连接在一起的&
。
def inRange(img, lower_b, upper_b):
ch1, ch2, ch3 = cv2.split(img)
ch1m = (lower_b[0] <= ch1) & (ch1 <= upper_b[0])
ch2m = (lower_b[1] <= ch2) & (ch2 <= upper_b[1])
ch3m = (lower_b[2] <= ch3) & (ch3 <= upper_b[2])
mask = ch1m & ch2m & ch3m
return mask.astype(np.uint8)*255
可以读取OpenCV docs看,这确实是使用的公式。我们也可以验证它。
lower_b = np.array([200,200,200])
upper_b = np.array([255,255,255])
mask = cv2.inRange(img, lower_b, upper_b) # OpenCV function
mask2 = inRange(img, lower_b, upper_b) # above defined function
print((mask==mask2).all()) # checks that the masks agree on all values
# True
如何找到正确的颜色
它可以是一个有点棘手找到正确值使用特定形象。尽管如此,还是有一种简单的实验方法。您可以在OpenCV中创建轨迹条,并使用它们来控制每个通道的最小值和最大值,并在每次更改值时让Python程序更新掩码。我为此制作了一个程序,您可以在GitHub here上抓取该程序。下面是一个动画它.gif
被使用,以证明:
你的意思是你想看到的所有颜色的曲线列入范围?要查看上限和下限,您可以简单地创建两个填充了这两种颜色的图像,以便至少了解这些图像的样子。但是否则要熟悉[HSV空间中的颜色圆柱模型](https://en.wikipedia.org/wiki/HSL_and_HSV#/media/File:Hsl-hsv_models.svg)。这些边界说“包括在220和260度之间的色调,在50和255之间的饱和度,以及在50和255之间的值(暗到振动)”。你可以想象得到这个圆柱体的大块。 –
我想绘制范围内的所有可能值。可能吗? – pwan
@AlexanderReynolds你能教我如何绘制这个圆柱体并想象切割该块体?只是更新了我的问题。 – pwan