2017-07-13 145 views
1

要提取的颜色,我们有这个功能python + opencv - 如何绘制hsv范围?

# define range of blue color in HSV 
lower_blue = np.array([110,50,50]) 
upper_blue = np.array([130,255,255]) 

# Threshold the HSV image to get only blue colors 
mask = cv2.inRange(hsv, lower_blue, upper_blue) 

我们究竟要如何想像范围(lower_blue,upper_blue)我定义的HSV空间? 另外我如何真正绘制一个hsv的颜色,但它不工作...? 我有这样的代码:

upper = np.array([60, 255, 255]) 
upper = cv2.cvtColor(upper, cv2.COLOR_HSV2BGR) 


upper = totuple(upper/-255) 
print(upper) 
plt.imshow([[upper]]) 
+0

你的意思是你想看到的所有颜色的曲线列入范围?要查看上限和下限,您可以简单地创建两个填充了这两种颜色的图像,以便至少了解这些图像的样子。但是否则要熟悉[HSV空间中的颜色圆柱模型](https://en.wikipedia.org/wiki/HSL_and_HSV#/media/File:Hsl-hsv_models.svg)。这些边界说“包括在220和260度之间的色调,在50和255之间的饱和度,以及在50和255之间的值(暗到振动)”。你可以想象得到这个圆柱体的大块。 –

+0

我想绘制范围内的所有可能值。可能吗? – pwan

+0

@AlexanderReynolds你能教我如何绘制这个圆柱体并想象切割该块体?只是更新了我的问题。 – pwan

回答

6

什么是HSV颜色

HSV,HSL等(或在OpenCV中,HLS),是圆柱形色彩空间中的一个。

cylindrical colorspaces

名称是某种描述的他们的价值观是如何引用。 (在OpenCV中,为了适应8位无符号整数格式,它们的度数除以2得到一个从0到179的数字;因此OpenCV中的110是220度)。如果您要采用色调值的“范围”,就像从蛋糕上切下一片。你只是吃了一些块蛋糕。

饱和通道距离您的中心有多远---您的半径。该中心绝对没有饱和度 - 只有从黑色到白色的灰色。如果您采用了这些值的范围,则类似于刮掉圆柱体的外部,或从中心切出一个圆。例如,如果范围是0到255,则范围0到127将是仅延伸到半径的一半的圆柱体; 127到255的范围将切割半径为半径的内圆柱体。

价值渠道是一个有点混乱的名字;它不是完全黑暗的亮度,因为最高值代表直接颜色,而最低值是黑色。这是圆柱体的高度。不难想象垂直切割圆柱体的切片。 HSV的

范围的值

功能cv2.inRange(image, lower_bound, upper_bound)发现lower_boundupper_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 of range values

现在这个GIF显示了一个新的H值每帧。从左到右,我们有最小值到最大值,而从上到下,我们有最小值到最大值V值。此动画中显示的每一种颜色都将从您的图像中选择,作为您的mask的一部分。

使自己INRANGE()函数

要充分认识OpenCV的功能,最简单的方法就是让自己的函数来完成任务。这并不难,也不是很多代码。

该功能背后的想法很简单:找到每个通道的值落在minmax之间,然后将所有通道连接在一起的&

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被使用,以证明:

Gif of cspaceThresh program

+0

谢谢!这是一个非常深入的解释。很有帮助。只是1个更愚蠢的问题,是否有可能在ipython中显示它内联?所以我可以将许多范围想象成一次进行比较。 – pwan

+0

Acutall,HSV更像是一个锥体。 https://i.stack.imgur.com/D5J3v.png – RobAu

+0

@RobAu两种表述都是正确的;他们通常被称为[圆柱坐标](https://en.wikipedia.org/wiki/HSL_and_HSV)。使用锥形或双锥形固体,每种颜色只有一种代表性,而HSV则有无限数量的黑点(值= 0,任何程度的H和任何饱和度S仍然会产生黑色)。但我发现圆柱模型更容易解释;一个坚实的圆锥三维部分是一个奇怪的事情想象。 –