Converting from RGB to Lαβ Color spaces and converting it back to RGB using OpenCV

邮差的信 提交于 2019-12-13 07:16:30

问题


I am currently trying to convert colors between RGB (red, green, blue) color space and Lαβ color space, Based on the details in the this paper. My difficulties are in reversing the conversion process. When the result is not as same as initial RGB Mat. I think I missing something in type castings between Mats but I can't tell what is it!
here is my code:

  <!-- language: lang-cc -->

Mat DetectTrackFace::RGB2LAlphBeta(Mat &src)
{
    Mat dest;
    Mat L_AlphBeta(src.rows, src.cols, CV_32FC3);
    //cvtColor(src,dest,CV_BGR2XYZ);
    float X,Y,Z,L,M,S,_L,Alph,Beta;
    int R,G,B;
    for(int i = 0; i < src.rows; i++)
      {
        for(int j = 0; j < src.cols; j++)
        {
            B = src.at<Vec3b>(i, j)[0];
            G = src.at<Vec3b>(i, j)[1];
            R = src.at<Vec3b>(i, j)[2];


            X = ( 0.4124 * R ) + ( 0.3576 * G ) + ( 0.1805 * B);
            Y = ( 0.2126 * R ) + ( 0.7152 * G ) + ( 0.0722 * B);
            Z = ( 0.0193 * R ) + ( 0.1192 * G ) + ( 0.9505 * B);

            L = (0.3897 * X) + (0.6890 * Y) + (-0.0787 * Z);
            M = (-0.2298 * X) + (1.1834* Y) + (0.0464 * Z);
            S = (0.0000 * X) + (0.0000 * Y) + (1.0000 * Z);

            //for handling log
            if(L == 0.0000) L=1.0000;
            if(M == 0.0000) M = 1.0000;
            if( S == 0.0000) S = 1.0000;


            //LMS to Lab
            _L = (1.0 / sqrt(3.0)) *((1.0000 * log10(L)) + (1.0000 * log10(M)) + (1.0000 * log10(S)));
            Alph =(1.0 / sqrt(6.0)) * ((1.0000 * log10(L)) + (1.0000 * log10(M)) + (-2.0000 * log10(S)));
            Beta = (1.0 / sqrt(2.0)) * ((1.0000 * log10(L)) + (-1.0000 * log10(M)) + (-0.0000 * log10(S)));

            L_AlphBeta.at<Vec3f>(i, j)[0] = _L;
            L_AlphBeta.at<Vec3f>(i, j)[1] = Alph;
            L_AlphBeta.at<Vec3f>(i, j)[2] = Beta;
        }
    }

    return L_AlphBeta;
}

Mat DetectTrackFace::LAlphBeta2RGB(Mat &src)
{
    Mat XYZ(src.rows, src.cols, src.type());
    Mat BGR(src.rows, src.cols, CV_8UC3);

    float X,Y,Z,L,M,S,_L,Alph,Beta, B,G,R;
    for(int i = 0; i < src.rows; i++)
      {
        for(int j = 0; j < src.cols; j++)
        {
            _L = src.at<Vec3f>(i, j)[0]*1.7321;
            Alph = src.at<Vec3f>(i, j)[1]*2.4495;
            Beta = src.at<Vec3f>(i, j)[2]*1.4142;



   /*Inv_Transform_logLMS2lab =

   0.33333   0.16667   0.50000
   0.33333   0.16667  -0.50000
   0.33333  -0.33333   0.00000*/
            L = (0.33333*_L) + (0.16667 * Alph) + (0.50000 * Beta);
            M = (0.33333 * _L) + (0.16667 * Alph) + (-0.50000 * Beta);
            S = (0.33333 * _L) + (-0.33333 * Alph) + (0.00000* Beta);

            L = pow(10 , L);
            if(L == 1) L=0;
            M = pow(10 , M);
            if(M == 1) M=0;
            S = pow(10 , S);
            if(S == 1) S=0;
    /*Inv_Transform_XYZ2LMS

   1.91024  -1.11218   0.20194
   0.37094   0.62905   0.00001
   0.00000   0.00000   1.00000*/

            X = (1.91024 *L ) + (-1.11218 * M ) +(0.20194 * S);
            Y = (0.37094 * L ) + (0.62905 * M ) +(0.00001 * S);
            Z = (0.00000 * L) + (0.00000 * M ) +(1.00000 * S);
    /*Inv_Transform_RGB2XYZ
    3.240625  -1.537208  -0.498629
    -0.968931   1.875756   0.041518
    0.055710  -0.204021   1.056996*/

            R = ( 3.240625 * X) + ( -1.537208 * Y) + ( -0.498629 * Z);
            G = ( -0.968931 * X) + ( 1.875756 * Y) + ( 0.041518 * Z);
            B = ( 0.055710 * X) + ( -0.204021 * Y) + ( 1.056996 * Z);
            if(R>255) R = 255;
            if(G>255) G = 255;
            if(B>255) B = 255;
            if(R<0) R = 0;
            if(G<0) G = 0;
            if(B<0) B = 0;
            if(R > 255 || G > 255 || B > 255 || R < 0 || G < 0 || B<0)
                cout<<"R = "<<R<<" G = "<<G <<" B = "<<B<<endl;


            BGR.at<Vec3b>(i, j)[0] = (uchar)B;
            BGR.at<Vec3b>(i, j)[1] = (uchar)G;
            BGR.at<Vec3b>(i, j)[2] = (uchar)R;

        }
    }
    //normalize(BGR,BGR, 255, 0, NORM_MINMAX, CV_8UC3 );
    return BGR;
}

回答1:


You have float to uchar truncation errors in the function LAlphBeta2RGB here:

BGR.at<Vec3b>(i, j)[0] = (uchar)B;
BGR.at<Vec3b>(i, j)[1] = (uchar)G;
BGR.at<Vec3b>(i, j)[2] = (uchar)R;

You can solve this using:

BGR(i, j)[0] = uchar(cvRound(B));
BGR(i, j)[1] = uchar(cvRound(G));
BGR(i, j)[2] = uchar(cvRound(R));

However, you shouldn't take care of conversion problems explicitly. You can use saturate_cast to handle this for you. You can declare R,G,B variables as uchar:

 uchar B, G, R;

and perform the conversion as:

R = saturate_cast<uchar>((3.240625 * X) + (-1.537208 * Y) + (-0.498629 * Z));
G = saturate_cast<uchar>((-0.968931 * X) + (1.875756 * Y) + (0.041518 * Z));
B = saturate_cast<uchar>((0.055710 * X) + (-0.204021 * Y) + (1.056996 * Z));

and then assign as:

BGR(i, j)[0] = B;
BGR(i, j)[1] = G;
BGR(i, j)[2] = R;

Or avoid using R,G,B entirely using:

BGR(i, j)[2] = saturate_cast<uchar>((3.240625 * X) + (-1.537208 * Y) + (-0.498629 * Z));
BGR(i, j)[1] = saturate_cast<uchar>((-0.968931 * X) + (1.875756 * Y) + (0.041518 * Z));
BGR(i, j)[0] = saturate_cast<uchar>((0.055710 * X) + (-0.204021 * Y) + (1.056996 * Z));

Here the full code. I took the liberty to use Mat_ instead of Mat as functions arguments, to avoid using at<type>() to access pixel values. In fact, you are already assuming that inputs of your functions are CV_8UC3 and CV_32FC3, respectively.

#include <opencv2\opencv.hpp>
#include <iostream>

using namespace std;
using namespace cv;

Mat RGB2LAlphBeta(Mat3b &src)
{
    Mat3f L_AlphBeta(src.rows, src.cols);
    //cvtColor(src,dest,CV_BGR2XYZ);
    float X, Y, Z, L, M, S, _L, Alph, Beta;
    int R, G, B;
    for (int i = 0; i < src.rows; i++)
    {
        for (int j = 0; j < src.cols; j++)
        {
            B = src(i, j)[0];
            G = src(i, j)[1];
            R = src(i, j)[2];


            X = (0.4124 * R) + (0.3576 * G) + (0.1805 * B);
            Y = (0.2126 * R) + (0.7152 * G) + (0.0722 * B);
            Z = (0.0193 * R) + (0.1192 * G) + (0.9505 * B);

            L = (0.3897 * X) + (0.6890 * Y) + (-0.0787 * Z);
            M = (-0.2298 * X) + (1.1834* Y) + (0.0464 * Z);
            S = (0.0000 * X) + (0.0000 * Y) + (1.0000 * Z);

            //for handling log
            if (L == 0.0000) L = 1.0000;
            if (M == 0.0000) M = 1.0000;
            if (S == 0.0000) S = 1.0000;


            //LMS to Lab
            _L = (1.0 / sqrt(3.0)) *((1.0000 * log10(L)) + (1.0000 * log10(M)) + (1.0000 * log10(S)));
            Alph = (1.0 / sqrt(6.0)) * ((1.0000 * log10(L)) + (1.0000 * log10(M)) + (-2.0000 * log10(S)));
            Beta = (1.0 / sqrt(2.0)) * ((1.0000 * log10(L)) + (-1.0000 * log10(M)) + (-0.0000 * log10(S)));

            L_AlphBeta(i, j)[0] = _L;
            L_AlphBeta(i, j)[1] = Alph;
            L_AlphBeta(i, j)[2] = Beta;
        }
    }

    return L_AlphBeta;
}

Mat LAlphBeta2RGB(Mat3f &src)
{
    Mat3f XYZ(src.rows, src.cols);
    Mat3b BGR(src.rows, src.cols);

    float X, Y, Z, L, M, S, _L, Alph, Beta;
    for (int i = 0; i < src.rows; i++)
    {
        for (int j = 0; j < src.cols; j++)
        {
            _L = src(i, j)[0] * 1.7321;
            Alph = src(i, j)[1] * 2.4495;
            Beta = src(i, j)[2] * 1.4142;

            /*Inv_Transform_logLMS2lab =

            0.33333   0.16667   0.50000
            0.33333   0.16667  -0.50000
            0.33333  -0.33333   0.00000*/
            L = (0.33333*_L) + (0.16667 * Alph) + (0.50000 * Beta);
            M = (0.33333 * _L) + (0.16667 * Alph) + (-0.50000 * Beta);
            S = (0.33333 * _L) + (-0.33333 * Alph) + (0.00000* Beta);

            L = pow(10, L);
            if (L == 1) L = 0;
            M = pow(10, M);
            if (M == 1) M = 0;
            S = pow(10, S);
            if (S == 1) S = 0;
            /*Inv_Transform_XYZ2LMS

            1.91024  -1.11218   0.20194
            0.37094   0.62905   0.00001
            0.00000   0.00000   1.00000*/

            X = (1.91024 *L) + (-1.11218 * M) + (0.20194 * S);
            Y = (0.37094 * L) + (0.62905 * M) + (0.00001 * S);
            Z = (0.00000 * L) + (0.00000 * M) + (1.00000 * S);
            /*Inv_Transform_RGB2XYZ
            3.240625  -1.537208  -0.498629
            -0.968931   1.875756   0.041518
            0.055710  -0.204021   1.056996*/

            BGR(i, j)[2] = saturate_cast<uchar>((3.240625 * X) + (-1.537208 * Y) + (-0.498629 * Z));
            BGR(i, j)[1] = saturate_cast<uchar>((-0.968931 * X) + (1.875756 * Y) + (0.041518 * Z));
            BGR(i, j)[0] = saturate_cast<uchar>((0.055710 * X) + (-0.204021 * Y) + (1.056996 * Z));
        }
    }
    //normalize(BGR,BGR, 255, 0, NORM_MINMAX, CV_8UC3 );
    return BGR;
}


int main()
{
    Mat3b img = imread("path_to_image");

    Mat3f labb = RGB2LAlphBeta(img);

    Mat3b rgb = LAlphBeta2RGB(labb);

    Mat3b diff;
    absdiff(img, rgb, diff);

    // Check if all pixels are equals
    cout << ((sum(diff) == Scalar(0, 0, 0, 0)) ? "Equals" : "Different");

    return 0;
}


来源:https://stackoverflow.com/questions/32696138/converting-from-rgb-to-l%ce%b1%ce%b2-color-spaces-and-converting-it-back-to-rgb-using-open

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!