影像色彩空間與應用轉換
- 2020 年 2 月 21 日
- 筆記
重新寫了一下影像色彩空間相關的知識,希望給大家多一點背景多點了解,不說別的,看完了肯定會漲知識。
RGB色彩空間
影像處理最基礎的知識點之一就是影像色彩跟顏色模型,對電腦來說表示一張影像,只是一些零壹的二進位值,但是對人眼來說看到的都是一些可見光,而且人眼只對三種可見光比較敏感,分別是紅色(red)、綠色(green)、藍色(blue)。這個就是最基本的RGB顏色模型,三種顏色的波長範圍表示如下:

Blue: 450–495 nm Green: 495–570 nm Yellow: 570–590 nm
針對人眼對顏色這個物理現象的生物感知表達模型,國際照明協會在1931年發布了一個顏色模型/色彩空間,表示如下:

因此就出現了對應顏色模型的色彩空間CIE XYZ模型,對於的表示色度跟亮度表示,圖示如下:

從這個上面看不到Z,其實Z是表示顏色得亮度,或者深度,所以CIE XYZ顏色模型的這個圖又被稱為CIE 色度圖。CIE XYZ顏色模型表示的範圍比較大,所以後來微軟跟惠普就提出了一個它的子集的顏色模型sRGB色彩空間,其中S是英文單詞標準的首字母,sRGB色彩空間的表示如下:

上面的黑色三角形區域就稱為sRGB色彩空間,被廣泛應用在個人電腦顯示器、印表機、數位相機中,佔據了大量市場份額、到了90年代的時候Adobe公司提出了一個新RGB色彩空間模型Adobe RGB色彩空間,它比sRGB色彩空間有更大的取值範圍,因此色彩更加細膩更加豐富,它的色彩空間圖示如下:

從圖中可以看成Adobe RGB色彩空間是比sRGB色彩空間大的,但是這個也有缺陷,就是不同色彩空間生成的彩色影像,在不同的設備上顯示或者瀏覽會出現色差,為了解決這個問題,需要對不同色彩空間之間建立轉換模型,實現不同色彩空間模型的轉。後來RGB色彩空間就被大家玩壞了,現在常用的RGB色彩空間如下:

其中值得關注的部分是sRGB跟CMYK之間的相互轉換,這個轉換之後會導致很明顯的色彩差異,原因在於CMYK色彩空間又一部分不在sRGB內部,所以這種情況下,需要對RGB色彩空間進行非線性變換,獲得顏色補償。原因在於多數商業印表機都是基於四色(Cyan, Yellow, Magenta and Black),無法列印一些sRGB範圍的顏色,所以必須進行非線性變換跟補償。這個其中最常見的就是Gamma校正。
非RGB色彩空間
RGB色彩空間比較豐富,但是它也是有缺點的,最大的缺點就是無法直觀的區分影像顏色、亮度、飽和度等值。所以我們需要一些更加直觀的影像色彩空間,排在第一位的就是HSV色彩空間,它直觀,容易理解,因此在影像處理非常有用。
HSV色彩空間
RGB立方圖色彩空間無法很好區分顏色與亮度的關係,要單獨調整顏色或者亮度不是很方便,這個時候HSV色彩空間是一個很好的選擇,它對顏色與亮度有著很好的區分度,HSV色彩空間圖示如下:

解釋如下:
- H(Hue) 表示顏色通道,不同的值表示不同的顏色範圍
- S表示飽和度通道,表示色澤
- V表示亮度通道,代表影像亮度高低級別
在H、S、V通道上對影像亮度跟顏色或者飽和度的調整就非常方便了,另外對一些特定的顏色值進行分離也比較方便了。
YCrCb色彩空間
YCrCb色彩空間被開發作為當時的數字分量影片的標準,它跟YUV色彩空間有著一定相似性,它的三個通道的取值範圍分別被定義為:
- Y通道:16~235
- Cr通道:16~240
- Cb通道:16~240
需要特別注意的是,RGB到YCrCb的色彩空間轉換時候,不同的YCrCb色彩空間標準會有不同,下面標清電視跟高清電視上YCrCb的色彩差異:

很顯然它們的轉換公式也會有所不同,所以千萬不用看到不同轉換公式就大驚小怪的!
LAB色彩空間
LAB色彩空間又名CIE Lab / LAB,它的圖示如下:

其中:
- L通道表示亮度值
- A通道表示紅色/綠色值
- B通道表示藍色/黃色值
在LAB色彩空間,L表示亮度分量、AB表示顏色通道,所以有時候LAB色彩空間處理影像也會必RGB色彩空間好用,會有意想不到的好結果。
OpenCV實現
OpenCV色彩空間相互轉換與操作的函數主要有兩個,其中支援色彩空間轉換的函數為:
void cv::cvtColor( InputArray src, OutputArray dst, int code, int dstCn = 0 )
參數解釋如下
- src 表示輸入影像
- dst 表示輸出影像
- code 表示空間轉換程式碼,支援常見的各種色彩空間轉換
從色彩空間中提取不同色顏色值函數:
void cv::inRange( InputArray src, InputArray lowerb, InputArray upperb, OutputArray dst )
參數解釋如下:
- src是輸入影像
- lowerb是取值範圍最小值
- upperb是取值範圍最大值
- dst是輸出的mask影像,二值的
一個例子,綠色背景對象上前景對象提取,先看一下效果:

相關程式碼如下:
#include <opencv2/opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main(int argc, const char *argv[]) { Mat src = imread("D:/vcprojects/images/cat.jpg"); if (src.empty()) { printf("could not load image...n"); return -1; } namedWindow("input", WINDOW_AUTOSIZE); imshow("input", src); // RGB to HSV Mat hsv; cvtColor(src, hsv, COLOR_BGR2HSV); imshow("hsv", hsv); // RGB to YUV Mat yuv; cvtColor(src, yuv, COLOR_BGR2YUV); imshow("yuv", yuv); // RGB to YUV Mat ycrcb; cvtColor(src, ycrcb, COLOR_BGR2YCrCb); imshow("ycrcb", ycrcb); Mat src2 = imread("D:/javaopencv/tinygreen.png"); imshow("src2", src2); cvtColor(src2, hsv, COLOR_BGR2HSV); Mat mask; inRange(hsv, Scalar(35, 43, 46), Scalar(99, 255, 255), mask); imshow("mask", mask); waitKey(0); return 0; }
