This code provides functions for color space conversions, including RGBtoXYZ
, XYZtoLab
, and rgb2lab
, which transform RGB values into Lab* color space according to CIE XYZ and Lab specifications. The code uses C programming language and assumes RGB values are in the range [0, 255] and XYZ values are in the range [0, 1].
npm run import -- "rgb 2 lab"
#include <math.h>
double F(double input) // function f(...), which is used for defining L, a and b changes within [4/29,1]
{
if (input > 0.008856)
return (pow(input, 0.333333333)); // maximum 1
else
return ((841/108)*input + 4/29); //841/108 = 29*29/36*16
}
void XYZtoLab(double X, double Y, double Z, double *L, double *a, double *b)
{
// TODO: make sure these are correct
const double Xo = 244.66128; // reference white
const double Yo = 255.0;
const double Zo = 277.63227;
*L = 116 * F(Y / Yo) - 16; // maximum L = 100
*a = 500 * (F(X / Xo) - F(Y / Yo)); // maximum
*b = 200 * (F(Y / Yo) - F(Z / Zo));
}
// source http://www.easyrgb.com/en/math.php
void RGBtoXYZ(double R, double G, double B, double *X, double *Y, double *Z) {
// Assume RGB has the type invariance satisfied, i.e., channels \in [0,255]
float var_R = R / 255.0;
float var_G = G / 255.0;
float var_B = B / 255.0;
var_R = (var_R > 0.04045) ? pow((var_R + 0.055) / 1.055, 2.4)
: var_R / 12.92;
var_G = (var_G > 0.04045) ? pow((var_G + 0.055) / 1.055, 2.4)
: var_G / 12.92;
var_B = (var_B > 0.04045) ? pow((var_B + 0.055) / 1.055, 2.4)
: var_B / 12.92;
var_R *= 100;
var_G *= 100;
var_B *= 100;
*X = var_R * 0.4124 + var_G * 0.3576 +
var_B * 0.1805;
*Y = var_R * 0.2126 + var_G * 0.7152 +
var_B * 0.0722;
*Z = var_R * 0.0193 + var_G * 0.1192 +
var_B * 0.9505;
}
double *rgb2lab(int R, int G, int B){
static double Lab[3] = {0, 0, 0};
double X, Y, Z;
RGBtoXYZ(R, G, B, &X, &Y, &Z);
XYZtoLab(X, Y, Z, &Lab[0], &Lab[1], &Lab[2]);
return Lab;
}
c
#include <math.h>
// Function to calculate F(x) according to the given formula
double F(double input) {
// Ensure input is in the valid range [4/29, 1]
if (input < 4 / 29.0) {
// If input is out of range, clamp it to the minimum value
input = 4 / 29.0;
} else if (input > 1) {
// If input is out of range, clamp it to the maximum value
input = 1;
}
if (input <= 0.008856) {
// For inputs less than or equal to 0.008856, use the linear formula
return (841.0 / 108.0) * input + 4 / 29.0;
} else {
// For inputs greater than 0.008856, use the cubic root formula
return pow(input, 1.0 / 3.0);
}
}
// Function to convert XYZ to Lab color space
void XYZtoLab(double X, double Y, double Z, double *L, double *a, double *b) {
const double Xo = 95.047; // Reference white in CIE XYZ
const double Yo = 100.0; // Reference white in CIE XYZ
const double Zo = 108.883; // Reference white in CIE XYZ
// Calculate L, a, and b values
*L = 116.0 * F(Y / Yo) - 16.0;
*a = 500.0 * (F(X / Xo) - F(Y / Yo));
*b = 200.0 * (F(Y / Yo) - F(Z / Zo));
}
// Function to convert RGB to XYZ color space
void RGBtoXYZ(double R, double G, double B) {
// Assume RGB values are in the range [0, 1]
double var_R = (R > 0.04045)? pow((R + 0.055) / 1.055, 2.4) : R / 12.92;
double var_G = (G > 0.04045)? pow((G + 0.055) / 1.055, 2.4) : G / 12.92;
double var_B = (B > 0.04045)? pow((B + 0.055) / 1.055, 2.4) : B / 12.92;
// Scale XYZ values
var_R *= 100.0;
var_G *= 100.0;
var_B *= 100.0;
// Return XYZ values
return var_R * 0.4124 + var_G * 0.3576 + var_B * 0.1805,
var_R * 0.2126 + var_G * 0.7152 + var_B * 0.0722,
var_R * 0.0193 + var_G * 0.1192 + var_B * 0.9505;
}
// Function to convert RGB to Lab color space
double *rgb2lab(int R, int G, int B) {
static double Lab[3] = {0, 0, 0};
double X, Y, Z;
double xyz_values[3];
xyz_values = RGBtoXYZ(R / 255.0, G / 255.0, B / 255.0);
XYZtoLab(xyz_values[0], xyz_values[1], xyz_values[2],
&Lab[0], &Lab[1], &Lab[2]);
return Lab;
}