在之前博文的基础上,我使用OpenCV2实现了RGB颜色空间向HIS、CMYK转换的代码。下列链接为各种经典颜色空间的介绍及转换公式的介绍。
http://blog.csdn.net/solomon1558/article/details/43772147
HSI与RGB颜色空间可以进行相互转换。RGB转换到HSI 的计算公式如下:首先给定RGB颜色空间的值(R,G,B),其中R,G,B∈[ 0,2 5 5],则转换到HSI 空间的(H,S,I)值的计算如下:设将(R ,G ,B)归一化得(R',G',B')为:
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; }【注】:
程序中将S分量和H分量都扩充到[0,255]区间以便于显示;
一般H分量在[0,2pi]之间,S在[0,1]之间。
给定RGB颜色空间的值(R,G,B),其中R,G ,B∈ [0, 2 5 5],则转换到CMYK 空间的(C,M,Y,K)值的计算如下:
【注】式中,maxG是每个矢量分量的最大允许值(255);C , M , Y , K ∈ [ 0,255]。
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 b = data[3*j]; uchar g = data[3*j+1]; uchar r = data[3*j+2]; uchar c = 255 - r; uchar m = 255 - g; uchar y = 255 - b; uchar k = min(min(c,m),y); dataCMYK[4*j] = c - k; dataCMYK[4*j+1] = m - k; dataCMYK[4*j+2] = y - k; dataCMYK[4*j+3] = k; } } return 0; }
#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; } 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 b = data[3*j]; uchar g = data[3*j+1]; uchar r = data[3*j+2]; uchar c = 255 - r; uchar m = 255 - g; uchar y = 255 - b; uchar k = min(min(c,m),y); dataCMYK[4*j] = c - k; dataCMYK[4*j+1] = m - k; dataCMYK[4*j+2] = y - k; dataCMYK[4*j+3] = k; } } return 0; } int main(){ Mat img = imread("E:\\CV视频处理工作室\\Test_Photo\\lena_1.jpg"); if(!img.data){ cout<<"Miss Data"<<endl; return -1; } 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图像 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; }