简体   繁体   English

python + opencv - 如何绘制hsv范围?

[英]python+opencv - How to plot hsv range?

To extract the color, we have this function 为了提取颜色,我们有这个功能

# 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)

How do we actually visualize the range(lower_blue,upper_blue) I define on hsv space? 我们如何实际可视化我在hsv空间定义的范围(lower_blue,upper_blue)? Also How do I actually plot a hsv color,but it is not working...? 另外我如何实际绘制hsv颜色,但它不起作用......? I have this code: 我有这个代码:

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


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

What are HSV colors 什么是HSV颜色

HSV, like HSL (or in OpenCV, HLS), is one of the cylindrical colorspaces. HSV与HSL(或OpenCV,HLS)一样,是圆柱形颜色空间之一。

圆柱形色彩空间

The name is somewhat descriptive of how their values are referenced. 该名称在某种程度上描述了它们的值是如何被引用的。

The hue is represented as degrees from 0 to 360 (in OpenCV, to fit into the an 8-bit unsigned integer format, they degrees are divided by two to get a number from 0 to 179; so 110 in OpenCV is 220 degrees). 色调表示为从0到360的度数(在OpenCV中,为了适合8位无符号整数格式,它们将度数除以2得到0到179之间的数字;因此OpenCV中的110是220度)。 If you were to take a "range" of hue values, it's like cutting a slice from a cake. 如果你要采用“范围”的色调值,就像从蛋糕上切下一片。 You're just taking some angle chunk of the cake. 你只是拿了一大块蛋糕。

The saturation channel is how far from the center you are---the radius you're at. 饱和通道距离您的中心有多远---您所在的半径。 The center has absolutely no saturation---only gray colors from black to white. 中心绝对没有饱和度 - 只有从黑色到白色的灰色。 If you took a range of these values, it is akin to shaving off the outside of the cylinder, or cutting out a circle from the center. 如果您采用了这些值的范围,则类似于从圆柱体的外部剃掉,或从中心切出一个圆圈。 For example, if the range is 0 to 255, then the range 0 to 127 would be a cylinder only extending to half the radius; 例如,如果范围是0到255,则范围0到127将是仅延伸到半径的圆柱体; the range 127 to 255 would be cutting an inner cylinder with half the radius out. 范围127到255将切割半径为半径的内圆柱。

The value channel is a slightly confusing name; 价值渠道是一个有点混乱的名称; it's not exactly darkness-to-brightness because the highest value represents the direct color, while the lowest value is black. 它不是完全黑暗的亮度,因为最高值代表直接颜色,而最低值代表黑色。 This is the height of the cylinder. 这是圆柱体的高度。 Not too hard to imagine cutting a slice of the cylinder vertically. 不难想象垂直切割圆柱片。

Ranges of HSV values HSV值的范围

The function cv2.inRange(image, lower_bound, upper_bound) finds all values of the image between lower_bound and upper_bound . 函数cv2.inRange(image, lower_bound, upper_bound)查找lower_boundupper_bound之间的图像的所有值。 For instance, if your image was a 3x3 image (just for simple demonstration purposes) with 3-channels, it might look something like this: 例如,如果您的图像是3个通道的3x3图像(仅用于简单的演示目的),它可能看起来像这样:

# 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

If we wanted to select hues between 100 and 200, then our lower_b should be [100, 0, 0] and upper_b should be [200, 255, 255] . 如果我们想要选择100到200之间的色调,那么我们的lower_b应该是[100, 0, 0] upper_b [100, 0, 0]upper_b应该是[200, 255, 255] upper_b [200, 255, 255] That way our mask would only take into account values in the hue channel, and not be affected by the saturation and value. 这样我们的掩码只会考虑色调通道中的值,而不受饱和度和值的影响。 That's why HSV is so popular---you can select colors by hue regardless of their brightness or darkness, so a dark red and bright red can be selected just by specifying the min and max of the hue channel. 这就是HSV如此受欢迎的原因---无论亮度或暗度如何,你都可以通过色调选择颜色,因此只需指定色调通道的最小值和最大值就可以选择暗红色和亮红色。

But say we only wanted to select bright white colors. 但是说我们只想选择明亮的白色。 Take a look back at the cylinder model---we see that white is given at the top-center of the cylinder, so where s values are low, and v values are high, and the color angle doesn't matter. 回顾一下圆柱体模型---我们看到在圆柱体的顶部中心给出了白色,因此s值较低, v值较高,颜色角度无关紧要。 So the lower_b would look something like [0, 0, 200] and upper_b would look something like [255, 50, 255] . 所以lower_b看起来像[0, 0, 200] upper_b [0, 0, 200]upper_b看起来像[255, 50, 255] upper_b [255, 50, 255] That means all H values will be included and won't affect our mask. 这意味着将包含所有H值,并且不会影响我们的掩码。 But then only S values between 0 and 50 would be included (towards the center of the cylinder) and only V values from 200 to 255 will be included (towards the top of the cylinder). 但是,仅包括0到50之间的S值(朝向圆柱体的中心),并且将仅包括从200到255的V值(朝向圆柱体的顶部)。

Visualizing a range of colors from HSV 可视化HSV的一系列颜色

One way to visualize all the colors in a range is to create gradients going the length of both directions for each of two channels, and then animate over the changing third channel. 可视化范围内所有颜色的一种方法是为两个通道中的每个通道创建沿两个方向的长度的渐变,然后在更改的第三个通道上设置动画。

For instance, you could create a gradient of values from left to right for the range of S values, from top to bottom for the range of V values, and then loop over each H value. 例如,您可以为S值范围从左到右创建一个渐变值,从上到下为V值范围创建一个渐变值,然后循环遍历每个H值。 This whole program could look something like this: 整个程序看起来像这样:

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

Now this gif shows a new H value every frame. 现在这个gif每帧显示一个新的H值。 And from left to right we have the min to max S values, and from top to bottom we have the min to max V values. 从左到右,我们有最小值到最大值S值,从上到下我们有最小值到最大值V值。 Every single one of the colors showing up in this animation will be selected from your image to be part of your mask . 此动画中显示的每种颜色都将从您的图像中选择,作为mask一部分。

Make your own inRange() function 制作自己的inRange()函数

To fully understand the OpenCV function, the easiest way is just to make your own function to complete the task. 要完全理解OpenCV函数,最简单的方法就是使自己的函数完成任务。 It's not difficult at all, and not very much code. 这根本不难,也不是很多代码。

The idea behind the function is simple: find where the values of each channel fall between min and max , and then & all the channels together. 功能背后的想法是简单的:找到其中之间的每个信道下降的值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

You can read the OpenCV docs to see that this is indeed the formula used. 您可以阅读OpenCV文档 ,看看这确实是使用的公式。 And we can verify it too. 我们也可以验证它。

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

How to find the right colors 如何找到合适的颜色

It can be a little tricky to find the correct values to use for a particular image. 找到用于特定图像的正确值可能有点棘手。 There is an easy way to experiment, though. 不过,有一种简单的实验方法。 You can create trackbars in OpenCV and use them to control the min and max for each channel and have the Python program update your mask every time you change the values. 您可以在OpenCV中创建跟踪栏,并使用它们来控制每个通道的最小值和最大值,并在每次更改值时让Python程序更新您的掩码。 I made a program for this which you can grab on GitHub here . 我为此制作了一个程序,你可以在这里抓住GitHub。 Here's an animated .gif of it being used, to demonstrate: 这是一个使用它的动画.gif ,用于演示:

cspaceThresh程序的Gif

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM