Question

I am having some problems converting from RGB to LAB and back again. I am trying my hand at experimenting with the LAB color space, but I want to make sure that I can convert it from RGB to XYZ to LAB and back again.

At first everything appeared well, but only if I was using the Lena test image, as soon as I started using other images I saw that blues and greens were completely cut off and I’m not sure where exactly the error is.

I tested an image with many colors and after conversion of RGB to LAB and back I got distorted colors.

Here’s my code:

{
    double fcolorspace = 255.0f;

    double* image1temp=new double[nWidth * nHeight * 4]; // this is our tempory buffer to hold image 1

    // convert to RGB to LAB
    for (int y = 0; y< nHeight; y++)
    {
        for (int x = 0; x< nWidth; x++)
        {
            int nIdx = x*4+y*4*nWidth;

            double red1;
            double green1;
            double blue1;

            double xyzX1;
            double xyzY1;
            double xyzZ1;

            double var_X1;
            double var_Y1;
            double var_Z1;

            double refX;
            double refY;
            double refZ;

            double var_X11;
            double var_Y12;
            double var_Z13;

            //read in image from array
            red1   = double(pBGRA_in1[nIdx + CHANNEL_R]) / fcolorspace;
            green1 = double(pBGRA_in1[nIdx + CHANNEL_G]) / fcolorspace;
            blue1  = double(pBGRA_in1[nIdx + CHANNEL_B]) / fcolorspace;

            //adjust gamma on image 1
            if (red1 > 0.04045f)
            {
                red1 = powf((red1 + 0.055f) / 1.055f, 2.4f);
            }
            else
            {
                red1 = red1 / 12.92f;
            }
            if (green1 > 0.04045f)
            {
                green1 = powf((green1 + 0.055f) / 1.055f, 2.4f);
            }
            else
            {
                green1 = green1 / 12.92f;
            }
            if (blue1 > 0.04045f)
            {
                blue1 = powf((blue1 + 0.055f) / 1.055f, 2.4f);
            }
            else
            {
                blue1 = blue1 / 12.92f;
            }

            //scale
            red1   = red1   * 100.0f;
            green1 = green1 * 100.0f;
            blue1  = blue1  * 100.0f;

            //first we will convert the RGB image to XYZ
            xyzX1 = (0.4124f * red1) + (0.3576f * green1) + (0.1805f * blue1);
            xyzY1 = (0.2126f * red1) + (0.7152f * green1) + (0.0722f * blue1);
            xyzZ1 = (0.0193f * red1) + (0.1192f * green1) + (0.9505f * blue1);

            //reference white
            refX = 95.047f; // Observer= 2°, Illuminant= D65
            refY = 100.000f;
            refZ = 108.883f;

            //adjust LAB to reference white
            var_X1 = xyzX1 / refX;
            var_Y1 = xyzY1 / refY;
            var_Z1 = xyzZ1 / refZ;

            //LAB Conversion
            if (var_X1 > 0.008856f)
            {
                var_X11 = powf(var_X1 , 1.0f/3.0f);
            }
            else
            {
                var_X11 = (7.787f * var_X1) + (16.0f/116.0f);
            }

            if (var_Y1 > 0.008856f)
            {
                var_Y12 = powf(var_Y1 , 1.0f/3.0f);
            }
            else
            {
                var_Y12 = (7.787f * var_Y1) + (16.0f/116.0f);
            }

            if (var_Z1 > 0.008856f)
            {
                var_Z13 = powf(var_Z1 , 1.0f/3.0f);
            }
            else
            {
                var_Z13 = (7.787f * var_Z1) + (16.0f/116.0f);
            }

            //adjust LAB scale
            double cieL1 = (116.0f * var_Y12) - 16.0f;
            double cieA1 = 500.0f * (var_X11 - var_Y12);
            double cieB1 = 200.0f * (var_Y12 - var_Z13);

            //we are now in the LAB colorspace
            f_outred   = CLAMP255(cieL1);
            f_outgreen = CLAMP255(cieA1);
            f_outblue  = CLAMP255(cieB1);

            //place LAB image in temp array
            image1temp[nIdx + CHANNEL_R] = int(f_outred);
            image1temp[nIdx + CHANNEL_G] = int(f_outgreen);
            image1temp[nIdx + CHANNEL_B] = int(f_outblue);
        }
    }

    //convert from LAB to XYZ
        for (int x = 0; x< nWidth; x++)
        {
            for (int y = 0; y< nHeight; y++)
            {
                int nIdx = x * 4 + y * 4 * nWidth;

                double refX;
                double refY;
                double refZ;

                double var_X;
                double var_Y;
                double var_Z;

                double cieX;
                double cieY;
                double cieZ;

                double red;
                double green;
                double blue;

                //reference white
                refX = 95.047f; // Observer= 2°, Illuminant= D65
                refY = 100.000f;
                refZ = 108.883f;

                double cieL = image1temp [nIdx + CHANNEL_R];
                double cieA = image1temp [nIdx + CHANNEL_G];
                double cieB = image1temp [nIdx + CHANNEL_B];

                var_Y = (cieL + 16.0f) / 116.0f;
                var_X = cieA / 500.0f + var_Y;
                var_Z = var_Y - cieB / 200.0f;

                if (powf(var_Y, 3.0f) > 0.008856)
                {
                    var_Y = powf(var_Y, 3.0f);
                }
                else
                {
                    var_Y = (var_Y - 16.0f / 116.0f) / 7.787f;
                }
                if (powf(var_X , 3.0f) > 0.008856f)
                {
                    var_X = powf(var_X, 3.0f);
                }
                else
                {
                    var_X = (var_X - 16.0f / 116.0f) / 7.787f;
                }
                if (powf(var_Z, 3.0f) > 0.008856)
                {
                    var_Z = powf(var_Z, 3.0f);
                }
                else
                {
                    var_Z = (var_Z - 16.0f / 116.0f) / 7.787f;
                }

                cieX = refX * var_X;
                cieY = refY * var_Y;
                cieZ = refZ * var_Z;

                var_X = cieX / 100.0f;
                var_Y = cieY / 100.0f;
                var_Z = cieZ / 100.0f;

                red   = var_X * 3.2406f  + var_Y * -1.5372f + var_Z * -0.4986f;
                green = var_X * -0.9689f + var_Y * 1.8758f  + var_Z * 0.0415f;
                blue  = var_X * 0.0557f  + var_Y * -0.2040f + var_Z * 1.0570f;

                if (red > 0.0031308f)
                {
                    red = 1.055f * powf(red , (1.0f / 2.4f)) - 0.055f;
                }
                else
                {
                    red = 12.92f * red;
                }
                if (green > 0.0031308f)
                {
                    green = 1.055f * powf(green , (1.0f / 2.4f)) - 0.055f;
                }
                else
                {
                    green = 12.92f * green;
                }
                if (blue > 0.0031308f)
                {
                    blue = 1.055f * powf(blue , (1.0f / 2.4f)) - 0.055f;
                }
                else
                {
                    blue = 12.92f * blue;
                }

                red = CLAMP255(red * fcolorspace);
                green = CLAMP255(green * fcolorspace);
                blue = CLAMP255(blue * fcolorspace);

                pBGRA_out[nIdx + CHANNEL_R] = red;
                pBGRA_out[nIdx + CHANNEL_G] = green;
                pBGRA_out[nIdx + CHANNEL_B] = blue;
            }
        }

    delete [] image1temp;//delete the array
    delete [] image2temp;//delete the array

}
Was it helpful?

Solution

You don't show the source for CLAMP255, but I'm guessing it clamps the values to between 0 and 255. For the Lab output this would be totally wrong as they use a different range; I know that a and b go below zero.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top