2017-07-13 149 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仍然會產生黑色)。但我發現圓柱模型更容易解釋;一個堅實的圓錐三維部分是一個奇怪的事情想象。 –