RGB圖像
RGB彩色空間主要有兩個彩色模型,一個是“加色(RGB)模型”,一個是“減色(CMY)模型”。加色模型又稱“三基色模型”:RGB(Red/Green/Blue,紅綠藍),三基色可以混合成任意顏色,如下圖示。減色模型主要是為了解決RGB模型對無源物體圖像處理的復雜(特別是黑色)。自然界物體按照顏色光可分為:發光物體和無源物體。舉個例子,在彩色印刷和彩色打印中,紙張不能發射光線而只能反射光線,因此,彩色印刷機和彩色打印機只能通過一些能夠吸收特定光波和反射其他光波的油墨和顏料以及它們的不同的比例混合出來印出千變萬化的顏色。油墨和顏料的三基色是CMY(Cyan/Magenta/Yellow,青/洋紅/黃),其特點是用料越多顏色越深。理論上講,等量的CMY可以合成黑色,但是實際上純黑色很難合成。因此打印機或印刷機要專門提供黑色油墨。這也稱為四色印刷,其模型也叫CMKY模型。如下圖示。
本文使用OpenCV寫了一個顯示一張彩色圖像的三通道分量圖像。
1 #include<opencv2/opencv.hpp> 2 #include<opencv2/highgui.hpp> 3 #include<opencv2/imgproc.hpp> 4 #include<iostream> 5 6 using namespace std; 7 using namespace cv; 8 9 const int blue[] = { 0,0 }, green[] = { 1,1 }, red[] = { 2,2 }; // 通道索引 10 11 int main(int argc, char** argv) 12 { 13 Mat img = imread("1.jpg"); 14 if (img.empty()) 15 { 16 cout << "could not load image!" << endl; 17 } 18 imshow("src_image", img); 19 20 /* 方法1 */ 21 Mat Rimg(img.rows, img.cols, CV_8UC3, Scalar(0, 0, 0)); 22 Mat Gimg(img.rows, img.cols, CV_8UC3, Scalar(0, 0, 0)); 23 Mat Bimg(img.rows, img.cols, CV_8UC3, Scalar(0, 0, 0)); 24 25 double time0 = static_cast<double>(getTickCount()); 26 27 mixChannels(&img, 1, &Rimg, 1, red, 1); 28 mixChannels(&img, 1, &Gimg, 1, green, 1); 29 mixChannels(&img, 1, &Bimg, 1, blue, 1); 30 31 time0 = ((double)getTickCount() - time0) / getTickFrequency(); 32 cout << "\t此方法運行時間為: " << time0 << "秒" << endl; //輸出運行時間 33 34 imshow("1.紅色分量圖像", Rimg); 35 imshow("1.綠色分量圖像", Gimg); 36 imshow("1.藍色分量圖像", Bimg); 37 38 /* 方法2 */ 39 Mat rimg(img.rows, img.cols, CV_8UC3, Scalar(0, 0, 0)); 40 Mat gimg(img.rows, img.cols, CV_8UC3, Scalar(0, 0, 0)); 41 Mat bimg(img.rows, img.cols, CV_8UC3, Scalar(0, 0, 0)); 42 43 double time1 = static_cast<double>(getTickCount()); 44 45 for (int i = 0; i < img.rows; i++) { 46 uchar* data = img.ptr<uchar>(i); //獲取第i行的首地址 47 uchar* rdata = rimg.ptr<uchar>(i); 48 uchar* gdata = gimg.ptr<uchar>(i); 49 uchar* bdata = bimg.ptr<uchar>(i); 50 for (int j = 0; j < img.cols*3; j += 3) { 51 bdata[j] = data[j]; 52 gdata[j + 1] = data[j + 1]; 53 rdata[j + 2] = data[j + 2]; 54 } 55 } 56 57 time1 = ((double)getTickCount() - time1) / getTickFrequency(); 58 cout << "\t此方法運行時間為: " << time1 << "秒" << endl; //輸出運行時間 59 60 imshow("2.紅色分量圖像", rimg); 61 imshow("2.綠色分量圖像", gimg); 62 imshow("2.藍色分量圖像", bimg); 63 64 waitKey(0); 65 return EXIT_SUCCESS; 66 }
運行示例如下:
HSI彩色空間
上述的RGB模型是工業界的一種顏色標准,它由顏色的發光原理設定,紅綠藍每個顏色通道各分為256階亮度。除此之外,從人類的色視覺機理出發提出的HSI彩色模型,對開發基於彩色描述的圖像處理方法也是一個較為理想的工具。HSI彩色模型指采用色調(Hue)、飽和度(Saturation)、強度(Intensity)來描述顏色的模型。該彩色空間是一個圓錐形的空間模型,圓錐型空間的豎直軸表示光強I,頂部最亮表示白色,底部最暗表示表示黑色,中間的為灰度。圓錐型空間中部的水平面圓周是表示色調H的角坐標。為了處理方便,經常要把RGB三基色表示的圖像數據轉換成HSI數據,其轉換公式如下:
借此說一句,與HSI彩色模型十分接近的HSV模型。HSV模型指色調(hue)、飽和度(saturation)、明度(value)。二者區別在於,一種純色的明度等於白色的明度,而純色的亮度等於中度灰的亮度。RGB數據轉換為HSV數據的公式如下:
上述兩個模型的一些圖表說明如下:
HSI彩色模型:
HSV模型:
OpenCV把RGB圖像轉化為HLS(HSI)圖像,並輸出HLS各通道的圖像,其代碼如下:
#include <opencv2/opencv.hpp> #include<iostream> using namespace std; using namespace cv; int main() { Mat img; img = imread("1.jpg"); imshow("原圖像", img); Mat hlsimg; //轉換為 HLS(HIS) 通道圖像 cvtColor(img, hlsimg, COLOR_RGB2HLS); imshow("hlsImg", hlsimg); Mat hImg = Mat(img.size(), CV_8UC1); Mat lImg = Mat(img.size(), CV_8UC1); Mat sImg = Mat(img.size(), CV_8UC1); Mat dst[] = { hImg,lImg,sImg }; int fromTo[] = { 0,0,1,1,2,2 }; mixChannels(&hlsimg, 1, dst, 3, fromTo, 3); imshow("hImg", hImg); imshow("lImg", lImg); imshow("sImg", sImg); waitKey(); }
運行示例如下:
OpenCV把RGB圖像轉化為HSV圖像,並輸出HSV各通道的圖像,其代碼如下:
#include <opencv2/opencv.hpp> #include<iostream> using namespace std; using namespace cv; int main() { Mat img; img = imread("1.jpg"); imshow("原圖像", img); Mat hsvImg; //轉換為 HSV 通道圖像 cvtColor(img, hsvImg, COLOR_BGR2HSV); imshow("hsvImg", hsvImg); Mat hImg = Mat(img.size(), CV_8UC1); Mat sImg = Mat(img.size(), CV_8UC1); Mat vImg = Mat(img.size(), CV_8UC1); Mat dst[] = { hImg,sImg,vImg }; int fromTo[] = { 0,0,1,1,2,2 }; mixChannels(&hsvImg, 1, dst, 3, fromTo, 3); imshow("hImg", hImg); imshow("sImg", sImg); imshow("vImg", vImg); waitKey();
}
運行示例:
【注】下面有一個頗為有趣的代碼,有興趣的可以試着玩一下:

#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <iostream> using namespace cv; using namespace std; int main() { int key = 0; Mat srcImage; Mat logoImage; vector<Mat> channels; Mat imageBlueChannel; // logoImage = imread("dota_logo.jpg", 0); logoImage = imread("dota_jugg.jpg",0); // 灰度 srcImage = imread("dota_jugg.jpg"); if (!logoImage.data) { printf("Oh,no,讀取logoImage錯誤~! \n"); return false; } if (!srcImage.data) { printf("Oh,no,讀取srcImage錯誤~! \n"); return false; } split(srcImage, channels);//分離色彩通道 imageBlueChannel = channels.at(2); addWeighted(imageBlueChannel(Rect(0, 0, logoImage.cols, logoImage.rows)), 1, logoImage, 1.0, 0, imageBlueChannel(Rect(0, 0, logoImage.cols, logoImage.rows))); merge(channels, srcImage); imshow("BlueImage", imageBlueChannel); namedWindow(" <1>游戲原畫+logo藍色通道"); imshow(" <1>游戲原畫+logo藍色通道", srcImage); waitKey(key); return 0; }
附錄
DICOM格式文件的資源網站: