從RGB 到 HSI 的空間轉換
給定一幅RGB彩色格式的圖像,每個RGB像素的H分量可用下式得到:
其中
等于
飽和度分量由下式給出:
強度分量下式得出:
上式已假定RGB歸一化到【0-1】,且角度是根據HSI空間的紅軸來度量。色調可以用6.2-2的結果除以360度歸一化到[0-1];
如果RGB已經歸一化到[0-1],那其他兩個分量已經歸一化到0-1了。
從 RGB 到 CMYK 轉換
藍綠色,深紅色,黃色是光的二次色,換句話說,是顔料的顔色;
轉換公式如下:
這裡假定RGB都歸一化到[0-1]了。
K是指黑色,這裡
草莓轉換 CMYK結果:
HSI結果:
RGB單獨通道結果:
代碼實作:
#include<opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/opencv.hpp>
#include<vector>
#define PI 3.1416
#define min(a,b) (a<b?a:b)
using namespace std;
using namespace cv;
int rgb2hsi(Mat &image,Mat &hsi)
{
if(!image.data){
cout<<"Miss Data"<<endl;
return -1;
}
int nl = image.rows;
int nc = image.cols;
if(image.isContinuous()){
nc = nc*nl;
nl = 1;
}
for(int i = 0;i < nl;i++){
uchar *src = image.ptr<uchar>(i);
uchar *dst = hsi.ptr<uchar>(i);
for(int j = 0;j < nc;j++){
float b = src[j*3]/255.0;
float g = src[j*3+1]/255.0;
float r = src[j*3+2]/255.0;
float num = (float)(0.5*((r-g)+(r-b)));
float den = (float)sqrt((r-g)*(r-g)+(r-b)*(g-b));
float H,S,I;
if(den == 0){ //分母不能為0
H = 0;
}
else{
double theta = acos(num/den);
if(b <= g)
H = theta/(PI*2);
else
H = (2*PI - theta)/(2*PI);
}
double minRGB = min(min(r,g),b);
den = r+g+b;
if(den == 0) //分母不能為0
S = 0;
else
S = 1 - 3*minRGB/den;
I = den/3.0;
//将S分量和H分量都擴充到[0,255]區間以便于顯示;
//一般H分量在[0,2pi]之間,S在[0,1]之間
dst[3*j] = H*255;
dst[3*j+1] = S*255;
dst[3*j+2] = I*255;
}
}
return 0;
}
uchar minimum(uchar a, uchar b)
{
return a <= b ? a : b;
}
cv::Mat bgr2cmyk(cv::Mat& rgb)
{
cv::Mat cmyk = cv::Mat::zeros(rgb.rows, rgb.cols, CV_8UC4);
int pixel_num = rgb.rows * rgb.cols;
for (int i = 0; i < pixel_num; i++)
{
uchar c = 255 - rgb.data[3 * i + 2];
uchar m = 255 - rgb.data[3 * i + 1];
uchar y = 255 - rgb.data[3 * i + 0];
uchar K = minimum(minimum(c, m), y);
cmyk.data[4 * i + 0] = c;
cmyk.data[4 * i + 1] = m;
cmyk.data[4 * i + 2] = y;
cmyk.data[4 * i + 3] = K;
}
return cmyk;
}
int rgb2cmyk( Mat &image,Mat &cmyk)
{
if(!image.data){
cout<<"Miss Data"<<endl;
return -1;
}
int nl = image.rows; //行數
int nc = image.cols; //列數
if(image.isContinuous()){ //沒有額外的填補像素
nc = nc*nl;
nl = 1; //It is now a 1D array
}
//對于連續圖像,本循環隻執行1次
for(int i=0;i<nl;i++){
uchar *data = image.ptr<uchar>(i);
uchar *dataCMYK = cmyk.ptr<uchar>(i);
for(int j = 0;j < nc;j++){
uchar c = 255 - data[3*j+2];
uchar m = 255 - data[3*j+1];
uchar y = 255 - data[3*j];
uchar k = min(min(c,m),y);
dataCMYK[4*j] = c ;
dataCMYK[4*j+1] = m ;
dataCMYK[4*j+2] = y ;
dataCMYK[4*j+3] = k;
}
}
return 0;
}
int main(){
Mat img = imread("630.tif");
if(!img.data){
cout<<"Miss Data"<<endl;
return -1;
}
resize(img,img,Size(), 0.5, 0.5);
Mat img_cmyk,img_hsi;
Mat img_hsv;
vector <Mat> vecRgb,vecHsi,vecHls,vecHsv,vecCmyk;
img_hsv.create(img.rows,img.cols,CV_8UC3);
Mat img_hls;
img_hls.create(img.rows,img.cols,CV_8UC3);
//生成與輸入圖像尺寸一樣的4通道cmyk圖像
split(img, vecRgb);
imshow( " src_b", vecRgb[0]);
imshow( " src_g", vecRgb[1]);
imshow( " src_r", vecRgb[2]);
img_cmyk.create(img.rows,img.cols,CV_8UC4);
img_hsi.create(img.rows,img.cols,CV_8UC3);
rgb2cmyk(img,img_cmyk);
rgb2hsi(img,img_hsi);
cvtColor(img,img_hsv,CV_BGR2HSV);
cvtColor(img,img_hls,CV_BGR2HLS);
split(img_cmyk,vecCmyk);
split(img_hsi,vecHsi);
cout<<"pixel(0,0) in RGB"<<endl;
for(int i=0;i<3;i++){
cout<<(int)img.at<Vec3b>(0,0)[i]<<" ";
}
cout<<endl<<"pixel(0,0) in CMYK"<<endl;
for(int i=0;i<4;i++){
cout<<(int)img_cmyk.at<Vec4b>(0,0)[i]<<" ";
}
int a = min(min(24,32),16);
cout<<endl<<a;
namedWindow("RGB_Image");
namedWindow("CMYK_Image");
//namedWindow("HSV_Image");
//namedWindow("HLS_Image");
namedWindow("HSI_Image");
namedWindow("CMYK_C");
namedWindow("CMYK_M");
namedWindow("CMYK_Y");
namedWindow("CMYK_K");
imshow("CMYK_C",vecCmyk[0]);
imshow("CMYK_M",vecCmyk[1]);
imshow("CMYK_Y",vecCmyk[2]);
imshow("CMYK_K",vecCmyk[3]);
imshow("HSI_H",vecHsi[0]);
imshow("HSI_S",vecHsi[1]);
imshow("HSI_I",vecHsi[2]);
imshow("RGB_Image",img);
imshow("CMYK_Image",img_cmyk);
//imshow("HSV_Image",img_hsv);
//imshow("HLS_Image",img_hls);
imshow("HSI_Image",img_hsi);
waitKey();
return 0;
}