影像色彩空間與應用轉換

  • 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;  }

Tags: