CieLab to RGB conversion not plausible

I am trying to convert (brownish) CieLab values to RGB.
The L*AB component does not seem to work for me.

Question 1.):
CieLab color space has very distinct ranges per axis.

  • L: 0 to 100
  • a: -127 to 128
  • b -127 to 128

The L*AB-components expects 0.-1. as input. I would have to remap the input values for actual Lab range to 0.-1. (see screenshot / definition)
It does not seem logical to me. Why does L*AB not just take the ranges defined to the CieLab model?

Question 2.)
Why are so many “G” and “B” values = “0” as a result of the conversion?

Any help to get this conversion to work would be much appreciated.

CieLab_test_01.gh (21.2 KB)

Hi @DavidRutten, as this is likely quite a niche topic, I have a hunch you might be one of the few individuals to help me out here. Sorry to bother and apologies in case I overlooked something obvious :slight_smile:

Hi @FrankS,

Can’t help with what the component is or isn’t doing, I’m afraid, But I noticed a couple of typos: in two of your domain remappings you have set the starting range as -128 to 127, instead of -127 to 128.

Regards
Jeremy

Thank you, Jeremy!
Indeed, I got that wrong. Fixed it, but it does not have an effect on the conversion.
I am still in the dark on this one.

I would try converting a bunch of LAB colors from the list into RGB using some online color-translator, and check if they are the same RGB values GH outputs
(btw I also think I see too many 0s :slight_smile: )

hi,

it seems to be quite well documented here :Math | EasyRGB

this might helps, i found some apparently working c++ examples on stackoverflow, that make the conversion in two steps: lab to xyz then xyz to rgb:
‘’’ ```
// using http://www.easyrgb.com/index.php?X=MATH&H=01#text1
void rgb2lab( float R, float G, float B, float & l_s, float &a_s, float &b_s )
{
float var_R = R/255.0;
float var_G = G/255.0;
float var_B = B/255.0;

if ( var_R > 0.04045 ) var_R = pow( (( var_R + 0.055 ) / 1.055 ), 2.4 );
else                   var_R = var_R / 12.92;
if ( var_G > 0.04045 ) var_G = pow( ( ( var_G + 0.055 ) / 1.055 ), 2.4);
else                   var_G = var_G / 12.92;
if ( var_B > 0.04045 ) var_B = pow( ( ( var_B + 0.055 ) / 1.055 ), 2.4);
else                   var_B = var_B / 12.92;

var_R = var_R * 100.;
var_G = var_G * 100.;
var_B = var_B * 100.;

//Observer. = 2°, Illuminant = D65
float X = var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805;
float Y = var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722;
float Z = var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505;


float var_X = X / 95.047 ;         //ref_X =  95.047   Observer= 2°, Illuminant= D65
float var_Y = Y / 100.000;          //ref_Y = 100.000
float var_Z = Z / 108.883;          //ref_Z = 108.883

if ( var_X > 0.008856 ) var_X = pow(var_X , ( 1./3. ) );
else                    var_X = ( 7.787 * var_X ) + ( 16. / 116. );
if ( var_Y > 0.008856 ) var_Y = pow(var_Y , ( 1./3. ));
else                    var_Y = ( 7.787 * var_Y ) + ( 16. / 116. );
if ( var_Z > 0.008856 ) var_Z = pow(var_Z , ( 1./3. ));
else                    var_Z = ( 7.787 * var_Z ) + ( 16. / 116. );

l_s = ( 116. * var_Y ) - 16.;
a_s = 500. * ( var_X - var_Y );
b_s = 200. * ( var_Y - var_Z );

}

//http://www.easyrgb.com/index.php?X=MATH&H=01#text1
void lab2rgb( float l_s, float a_s, float b_s, float& R, float& G, float& B )
{
float var_Y = ( l_s + 16. ) / 116.;
float var_X = a_s / 500. + var_Y;
float var_Z = var_Y - b_s / 200.;

if ( pow(var_Y,3) > 0.008856 ) var_Y = pow(var_Y,3);
else                      var_Y = ( var_Y - 16. / 116. ) / 7.787;
if ( pow(var_X,3) > 0.008856 ) var_X = pow(var_X,3);
else                      var_X = ( var_X - 16. / 116. ) / 7.787;
if ( pow(var_Z,3) > 0.008856 ) var_Z = pow(var_Z,3);
else                      var_Z = ( var_Z - 16. / 116. ) / 7.787;

float X = 95.047 * var_X ;    //ref_X =  95.047     Observer= 2°, Illuminant= D65
float Y = 100.000 * var_Y  ;   //ref_Y = 100.000
float Z = 108.883 * var_Z ;    //ref_Z = 108.883


var_X = X / 100. ;       //X from 0 to  95.047      (Observer = 2°, Illuminant = D65)
var_Y = Y / 100. ;       //Y from 0 to 100.000
var_Z = Z / 100. ;      //Z from 0 to 108.883

float var_R = var_X *  3.2406 + var_Y * -1.5372 + var_Z * -0.4986;
float var_G = var_X * -0.9689 + var_Y *  1.8758 + var_Z *  0.0415;
float var_B = var_X *  0.0557 + var_Y * -0.2040 + var_Z *  1.0570;

if ( var_R > 0.0031308 ) var_R = 1.055 * pow(var_R , ( 1 / 2.4 ))  - 0.055;
else                     var_R = 12.92 * var_R;
if ( var_G > 0.0031308 ) var_G = 1.055 * pow(var_G , ( 1 / 2.4 ) )  - 0.055;
else                     var_G = 12.92 * var_G;
if ( var_B > 0.0031308 ) var_B = 1.055 * pow( var_B , ( 1 / 2.4 ) ) - 0.055;
else                     var_B = 12.92 * var_B;

R = var_R * 255.;
G = var_G * 255.;
B = var_B * 255.;

}

1 Like

hey again @FrankS ,

it seems indeed to have a input issue with the existing elements, as just xyz are from 0To100 or 0To1.

I was a bit bored and took the time to write a converter (two in fact) for the Cie D65 2° standard to sRGB, checked with online converters (@inno , thanks), whether my elements work correctly and they do, so here you go:

CieLab2sRGB.gh (7.4 KB)

hope that’s a good workaround for you

Ben

2 Likes

CieLab2sRGB_Illumination.gh (8.5 KB)

and here with the (not so funny typing part) illumination options.

Good night

1 Like