2017-07-04 33 views
1

我正在使用C++,但python中的回答也很好。使用cvtColor轉換單個BGR顏色並使用結果從圖像中提取該顏色

我需要將已知的BGR顏色轉換爲HSV才能使用cv :: inRange方法,該方法允許您提取圖像的某個部分。我已經有了能夠估計我需要的BGR顏色的代碼,所以我認爲我應該能夠猜測它的範圍。

所以我推薦這個鏈接:Convert a single color with cvtColor這似乎工作轉換BGR HSV,雖然我仍然有一些奇怪的輸出,我會稍後解釋。

反正這裏是我的代碼:

//store BGR values and convert BGR to HSV 
cv::Mat3f hairColor(cv::Vec3f(averageBlue, averageGreen, averageRed)); 
cv::Mat3f finalHSV; 
cv::cvtColor(hairColor, finalHSV, CV_BGR2HSV); 

//change values to be valid with the cv::inRange function (find this part odd) 
finalHSV.ptr<float>(0)[0] /= 2; 
finalHSV.ptr<float>(0)[1] *= 255; 

//store hsv values as integers 
int averageHue = finalHSV.ptr<float>(0)[0]; 
int averageSat = finalHSV.ptr<float>(0)[1]; 
int averageValue = finalHSV.ptr<float>(0)[2]; 

//try to appromimate ranges. I'm trying to mess wtih these values but can't calibrate it whatsoever 
int hueMin = averageHue - 20; int hueMax = averageHue + 100; 
int saturationMin = averageSat - 20; int saturationMax = averageSat + 20; 
int valueMin = averageValue - 50; int valueMax = averageValue + 50; 


//bw is the output array for my mask. 
cv::inRange(hsv, cv::Scalar(hueMin, saturationMin, valueMin), cv::Scalar(hueMax, saturationMax, valueMax), bw); 

因此,這裏是簡單的例子:我的代碼確定近似BGR顏色我想具有值[126,105,98]。轉換爲HSV的初始形式給出[225,0.22,126],這似乎奇怪地是不正確的如何opencv存儲hsv(如色相是0-179我認爲),所以我做了2次轉換得到[112,56,126],我認爲應該是正確的?

無論如何,當我嘗試在我的inRange函數中修改數值時,我無法真正獲得任何好的提取,我傾向於只是得到一個黑色屏幕(我測試了我的面具的工作原理,並且這樣做的問題應該是提供的代碼)。

有沒有更好的方法去完成這項任務?

回答

0

你的第二次轉換是正確的(好吧,如果截斷爲int而不是四捨五入)。

您可以隨時對OpenCV docs for cvtColor中給出的值進行實際計算。

這是用Python編寫的精確公式。對不起這不是C++,但我寫它作爲基本的可能所以它是隨動的人在任何其他語言:

b, g, r = 126, 105, 98 

b = b/255 
g = g/255 
r = r/255 

v = max([b, g, r]) 

if v is 0: 
    s = 0 
else: 
    s = (v-min([b, g, r]))/v 


if v is r: 
    h = 60*(g-b)/(v-min([b,g,r])) 
elif v is g: 
    h = 120 + 60*(b-r)/(v-min([b,g,r])) 
elif v is b: 
    h = 240 + 60*(r-g)/(v-min([b,g,r])) 

if h < 0: 
    h = h + 360 

v = np.round(255*v).astype(int) 
s = np.round(255*s).astype(int) 
h = np.round(h/2).astype(int) 

print(h,s,v) 

有幾種不同的方法,你可以使用以獲得良好的顏色過濾自動值。我喜歡的一種方法是選擇一個您想要的顏色的區域,並找到這些顏色值的標準偏差和平均值。這樣,您可以輕鬆地將inRange()函數的下限和上限分別設置爲mean-stddevmean+stddev。或者你可以減少限制,並將標準偏差乘以某個標量,並且可以選擇哪個方向更多或更少選擇。例如,lowerb = mean - 3*stddevupperb = mean + 1.5*stddev

當你有一個對象在你關心的中間有多個ROI時,這可能是非常有用的。您可以使用邊界像素的平均值和標準偏差分別過濾出每個ROI邊框中的顏色!

+0

好吧我有這部分轉換和工作在c + +,但它似乎沒有得到我想要提取一貫的確切顏色。使用cvInRange真的是唯一的方法來提取特定的顏色,如果是的話,什麼是提供良好範圍的最佳方式? – Eango

+0

是的,爲了提取顏色,它正是你想要使用的。如果你想要一致地提取顏色,這取決於你的應用程序是什麼以及你的意思是一致的。例如,對於許多應用程序來說,一個穩健可靠的方法是使用該顏色在圖像中找到一個區域,找到該區域中顏色的平均值和標準偏差,然後用'inRange()'以下限平均值 - n * stddev'和上限'mean + n * stddev'其中'n'讓我們選擇您想要偏離特定顏色的標準偏差。 –

+0

真棒只是做了一個區域的標準偏差提示,似乎改善了很多我的圖像。感謝您的幫助:) – Eango