I am currently using C# to compute the range of various color spaces. One such, CIE Lab*, is giving me a headache.
To compute the range, I enumerate each possible RGB color, convert it, and store the minimum and maximum value of each component in the new color space. Ultimately, 16,777,216 colors are enumerated. This gives a valid range for HSB, HSL, RGB, RYB, XYZ, and YUV.
When I compute the range of XYZ-derived color spaces (namely, CIE Lab*), I get unexpected results. Most resources on the web suggests CIE Lab* has a range of
L = [0, 100], A = [-127, 128], B = [-127, 128]
The result of my computation, however, varies based on the illuminant used to convert to XYZ and differs significantly from what the web suggests it should be. This would normally be expected of XYZ as illuminants determine the white point (or the maximum value of each component).
The actual range produced from my computation is,
L = [0, 100], a = [-79.2872809298957, 93.5500249398082], and B = [-112.02942991288, 93.3884778832379]
The following demonstrates how I compute the range:
//The maximum value of the first component
var amax = double.MinValue;
//The maximum value of the second component
var bmax = double.MinValue;
//The maximum value of the third component
var cmax = double.MinValue;
//The minimum value of the first component
var amin = double.MaxValue;
//The minimum value of the second component
var bmin = double.MaxValue;
//The minimum value of the third component
var cmin = double.MaxValue;
for (var r = 0; r < 256; r++)
{
for (var g = 0; g < 256; g++)
{
for (var b = 0; b < 256; b++)
{
//This just gets a structure with three _double_ values, which correspond to the values of each component
var result = ...
if (result.A > amax)
amax = result.A;
if (result.B > bmax)
bmax = result.B;
if (result.C > cmax)
cmax = result.C;
if (result.A < amin)
amin = result.A;
if (result.B < bmin)
bmin = result.B;
if (result.C < cmin)
cmin = result.C;
}
}
}
This led me to believe my conversion algorithm is invalid. I then computed the accuracy of the conversion algorithm by comparing an input RGB color with the RGB color produced after converting to the given color space and back. The accuracy was perfect meaning the RGB color that was converted to CIE Lab* was the same RGB color after converting back.
Still uncertain with my calculations, I installed Colourful and performed the enumeration again. Now, I get a slightly different range of,
L = [0, 100], a = [-69.4486345075232, 108.405957448357], and B = [-202.351230669589, 58.2087459930753]
In all cases, the illuminant D65 was used. At this point, it is clear neither conversion algorithm is necessarily incorrect. So where does the range,
L = [0, 100], A = [-127, 128], B = [-127, 128]
come from?
Theory 1
It is a conceptual range (which I'll refer to as moving forward) that must be converted from and to accordingly. One way to achieve this would be to get the absolute range of the a and b components respective to the conceptual range and my own computational range (which I'll refer to as, also).
Thus, given the computational value y in the zero-based ranges, [0, 172.8373058697039], [0, 205.4179077961179], we want to find the conceptual value x in the range [0, 255].
a,
x / 255 = y / 172.8373058697039
x = (y / 172.8373058697039) * 255
b,
x / 255 = y / 205.4179077961179
x = (y / 205.4179077961179) * 255
You would then subtract by the absolute minimum value of a and b in the conceptual range (127). This gives a valid value in the conceptual range.
Theory 2
The conversion algorithm should be producing a value in the conceptual range and so is thus invalid. This doesn't seem to be the case, though, as my algorithm is based on the ones published here and I tested an additional third party library.
Theory 3
The conceptual range corresponds to the average range of all illuminants.
Theory 4
The conceptual range corresponds to an arbitrary range that falls within the gamut of the color space.
Theory 5
The algorithm used to compute the range does not work equally for all color spaces.