2012-08-30 161 views
19

我試圖在使用OpenCV的視頻流中閾值紅色像素。我有其他顏色工作相當好,但紅色帶來了問題,因爲它圍繞着色相軸(即HSV(0,255,255)和HSV(179,255,255)都是紅色)。我現在使用的技術並不理想。基本上是:在OpenCV中使用HSV有效地使用HSV閾值

cvInRangeS(src, cvScalar(0, 135, 135), cvScalar(20, 255, 255), dstA); 
cvInRangeS(src, cvScalar(159, 135, 135), cvScalar(179, 255, 255), dstB); 
cvOr(dstA, dstB, dst); 

這是最理想的,因爲它比簡單的情況下藍的時候需要紅色代碼分支(潛在的bug)的兩個額外的圖像的分配,以及兩個額外的操作:

cvInRangeS(src, cvScalar(100, 135, 135), cvScalar(140, 255, 255), dst); 

對我來說,更好的選擇是「旋轉」圖像的顏色,使目標色調爲90度。例如。

int rotation = 90 - 179; // 179 = red 
cvAddS(src, cvScalar(rotation, 0, 0), dst1); 
cvInRangeS(dst1, cvScalar(70, 135, 135), cvScalar(110, 255, 255), dst); 

這使我能夠對待所有顏色。

但是,cvAddS操作在色階值低於0時不會將色調值迴繞到180,因此會丟失數據。我看着將圖像轉換爲CvMat,以便我可以從中減去,然後使用模數將負值回到範圍的頂部,但CvMat似乎不支持模數。當然,我可以迭代每個像素,但是我擔心這會很慢。


我讀過許多教程和代碼示例,但他們似乎都方便只看不周圍的色調譜換行甚至醜陋的(範圍,或使用的解決方案如:重新實現通過迭代每個像素並對彩色表進行手動比較)。

那麼,通常解決這個問題的方法是什麼?最好的方法是什麼?什麼是每個的權衡?迭代像素比使用內置CV函數慢得多?

+1

交換紅色和綠色通道,閾值綠色和交換回? – MSalters

回答

2

你不會相信,但我有完全相同的問題,我解決了它通過簡單的迭代通過色調(不是整個HSV)圖像。

迭代像素比使用內置CV函數慢得多嗎?

我剛剛試圖理解cv::inRange函數,但沒有得到它(似乎作者使用了一些特定的迭代)。

+0

好的,我是通過迭代來完成的。它允許我將幾個不同的數組操作組合成一個手動循環,因此性能可能相當或更好。它似乎並不慢,但我也沒有實際基準。你可以在這裏看到我的解決方案:https://gist.github.com/3562715 – Ian

0

cvAddS(...)是等價的,在元件的水平,到:

out = static_cast<dest> (in + shift); 

這是的static_cast的問題,因爲是剪輯/截斷值。

一個解決辦法是從(0-180)到(x 255)的數據移位,然後申請一個非削減與溢出補充:

out = uchar(in + (255-180) + rotation); 

現在你應該可以使用單InRange呼叫,只需根據上述公式移動紅色間隔

+0

是的,但是如果你要循環以進行元素色移,你可以在同一個循環中手動執行閾值。 – Ian

2

您可以使用CV_BGR2HSV_FULL計算範圍爲0..255的色調通道。的10您的原始色調差將成爲1410/180*256),即色相必須在範圍128-14..128+14

public void inColorRange(CvMat imageBgr, CvMat dst, int color, int threshold) { 
    cvCvtColor(imageBgr, imageHsv, CV_BGR2HSV_FULL); 
    int rotation = 128 - color; 
    cvAddS(imageHsv, cvScalar(rotation, 0, 0), imageHsv); 
    cvInRangeS(imageHsv, cvScalar(128-threshold, 135, 135), 
     cvScalar(128+threshold, 255, 255), dst); 
} 
+0

當原始色調是* 128以下時,這仍然可以工作嗎? (Like,20) – efaj

+1

是的,只需要計算'rotation = 128 - yourColor' – Oliv

5

這是有點晚了,但是這是我想嘗試。

進行轉換:cvCvtColor(imageBgr,imageHsv,CV_RGB2HSV);

請注意,RGB vs Bgr是故意穿過的。

這樣,紅色將在藍色通道中對待,並將以170爲中心。方向上也會有翻轉,但只要您知道期望它就可以。

+0

非常聰明。如果我需要再次使用,可以使用這個。 – Ian

+0

我喜歡這種方法!感謝分享 – Alexdm

0

有一個非常簡單的方法來做到這一點。

首先使兩種不同的顏色範圍

cv::Mat lower_red_hue_range; 
cv::Mat upper_red_hue_range; 
cv::inRange(hsv_image, cv::Scalar(0, 100, 100), cv::Scalar(10, 255, 255), lower_red_hue_range); 
cv::inRange(hsv_image, cv::Scalar(160, 100, 100), cv::Scalar(179, 255, 255), upper_red_hue_range); 

然後使用addWeighted

cv::Mat red_hue_mask; 
cv::addWeighted(lower_red_hue_range, 1.0, upper_red_hue_range, 1.0, 0.0, red_hue_mask); 

下面結合兩個口罩可以將面膜只適用於圖像

cv::Mat result; 
inputImageMat.copyTo(result, red_hue_mask); 

我來自a blog post的想法我發現