本文的主題實際上是圖像的顏色空間的轉換,借助一個顏色選取程序來說明OpenCV中顏色轉換函數的用法以及一些注意事項。
RGB顏色空間:RGB采用加法混色法,因為它是描述各種“光”通過何種比例來產生顏色。光線從暗黑開始不斷疊加 產生顏色。RGB描述的是紅綠藍三色光的數值。數字圖像存儲方面一般都是用RGB模式,值得注意的是OpenCV裡三通道的存儲順序是BGR。
HSV,HSI:這兩個顏色格式都是根據人眼對顏色的區分來定義的格式,其中H(hue)表示色相,S(saturation)表示飽和度,V(value)表示明度,I(intensity)代表了亮度。
Lab空間:模型中均勻改變對應於在感知顏色中的均勻改變,所以我們可以把Lab想像為顏色空間中的一個點,相鄰的點靠的越近說明兩者的顏色越接近,所以Lab空間常用來度量兩個顏色的相似性。
更多顏色空間的知識可以參考:http://en.wikipedia.org/wiki/Color_space
OpenCV裡通過cvtColor函數來完成圖片的顏色轉換,cvtColor是在opencv2/imgproc/imgproc.hpp頭文件中定義的,它的C++接口如下:
1void
cvtColor(InputArray src, OutputArray dst,
int
code,
int
dstCn=0 )
src:輸入圖像。
dst:輸出圖像。
code:顏色轉換類型,比如:CV_BGR2Lab,CV_BGR2HSV,CV_HSV2BGR,CV_BGR2RGB。
dstCn:輸出圖像的通道號,如果默認為0,則表示按輸入圖像的通道數。
把image圖像由BGR轉換為Lab:cvtColor(image,image,CV_BGR2Lab)
首先我們定義一個colorDetect類:
1 2 3 4 5 6 7 8 9 10 11 12class
colorDetect{
private
:
int
minDist;
//minium acceptable distance
Vec3b target;
//target color;
Mat result;
//the result
public
:
colorDetect();
void
SetMinDistance(
int
dist);
void
SetTargetColor(uchar red,uchar green,uchar blue);
void
SetTargetColor(Vec3b color);
//set the target color
Mat process(
const
Mat& image);
//main process
};
其中的minDist是我們定義的阈值用於限定兩種顏色之間的距離,相當於PhotoShop中魔術棒工具的阈值。
target是目標顏色,相當於種子顏色。result是存儲處理得到的結果。
process是主要的處理程序,下面我們來看process的內容。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29Mat colorDetect::process(
const
Mat& image)
{
Mat ImageLab=image.clone();
result.create(image.rows,image.cols,CV_8U);
//將image轉換為Lab格式存儲在ImageLab中
cvtColor(image,ImageLab,CV_BGR2Lab);
//將目標顏色由BGR轉換為Lab
Mat temp(1,1,CV_8UC3);
temp.at<Vec3b>(0,0)=target;
//創建了一張1*1的臨時圖像並用目標顏色填充
cvtColor(temp,temp,CV_BGR2Lab);
target=temp.at<Vec3b>(0,0);
//再從臨時圖像的Lab格式中取出目標顏色
// 創建處理用的迭代器
Mat_<Vec3b>::iterator it=ImageLab.begin<Vec3b>();
Mat_<Vec3b>::iterator itend=ImageLab.end<Vec3b>();
Mat_<uchar>::iterator itout=result.begin<uchar>();
while
(it!=itend)
{
//兩個顏色值之間距離的計算
int
dist=
static_cast
<
int
>(norm<
int
,3>(Vec3i((*it)[0]-target[0],
(*it)[1]-target[1],(*it)[2]-target[2])));
if
(dist<minDist)
(*itout)=255;
else
(*itout)=0;
it++;
itout++;
}
return
result;
}
程序中有2點需要特別注意:
1,在將圖像轉換為Lab空間後,目標顏色也需要進行轉換,做法是創建了一個臨時圖像。
2,判斷兩個顏色之間的距離運算了norm函數,它的運算是norm<typename,dim>(v)。其中v是一個dim維的向量。程序中是一個三維的適量,是兩個顏色值兩減後的結果。
那值得思考的是能不能把Vec3i((*it)[0]-target[0],(*it)[1]-target[1],(*it)[2]-target[2])替換為Vec3i((*it)-target)呢?答案是否的,因為(*it)-target在實際運算過程中會自動的把相減的結果進行類型限制。
我們對目標顏色和阈值進行這樣的設置後可以得到一個示例的效果:
1 2cdet.SetTargetColor(150,150,150);
cdet.SetMinDistance(50);