天天看點

OpenCV 顔色空間RGB 到HSI CMYK的轉換 C++

從RGB 到 HSI 的空間轉換

   給定一幅RGB彩色格式的圖像,每個RGB像素的H分量可用下式得到:

OpenCV 顔色空間RGB 到HSI CMYK的轉換 C++

其中

OpenCV 顔色空間RGB 到HSI CMYK的轉換 C++

 等于

OpenCV 顔色空間RGB 到HSI CMYK的轉換 C++

飽和度分量由下式給出:

OpenCV 顔色空間RGB 到HSI CMYK的轉換 C++

強度分量下式得出:

OpenCV 顔色空間RGB 到HSI CMYK的轉換 C++

上式已假定RGB歸一化到【0-1】,且角度是根據HSI空間的紅軸來度量。色調可以用6.2-2的結果除以360度歸一化到[0-1];

如果RGB已經歸一化到[0-1],那其他兩個分量已經歸一化到0-1了。

從 RGB 到 CMYK 轉換

藍綠色,深紅色,黃色是光的二次色,換句話說,是顔料的顔色;

轉換公式如下:

OpenCV 顔色空間RGB 到HSI CMYK的轉換 C++

這裡假定RGB都歸一化到[0-1]了。

K是指黑色,這裡

OpenCV 顔色空間RGB 到HSI CMYK的轉換 C++

草莓轉換 CMYK結果:

OpenCV 顔色空間RGB 到HSI CMYK的轉換 C++

HSI結果:

OpenCV 顔色空間RGB 到HSI CMYK的轉換 C++

RGB單獨通道結果:

OpenCV 顔色空間RGB 到HSI CMYK的轉換 C++

代碼實作:

#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;

}

繼續閱讀