From db302377b9574f9fb7415d25df8eb4a18628f845 Mon Sep 17 00:00:00 2001 From: Jarl Holta Date: Thu, 9 Jan 2025 04:43:10 +0100 Subject: [PATCH] Colormath opt, and D65 normalization --- Source/simba.colormath_conversion.pas | 48 +++++++------ Source/simba.colormath_distance_unrolled.pas | 76 ++++++++++---------- 2 files changed, 68 insertions(+), 56 deletions(-) diff --git a/Source/simba.colormath_conversion.pas b/Source/simba.colormath_conversion.pas index 97bba8212..765afb0e7 100644 --- a/Source/simba.colormath_conversion.pas +++ b/Source/simba.colormath_conversion.pas @@ -20,8 +20,8 @@ interface simba.base, simba.math, simba.colormath; const - XYZ_POW_2_4: array[0..255] of Single = ( - 0.000834, 0.000984, 0.001148, 0.001328, 0.001523, 0.001733, 0.001960, 0.002203, 0.002463, 0.002740, 0.003035, 0.003347, 0.003677, 0.004025, 0.004391, 0.004777, 0.005182, 0.005605, 0.006049, 0.006512, 0.006995, 0.007499, 0.008023, 0.008568, 0.009134, 0.009721, 0.010330, 0.010960, 0.011612, 0.012286, 0.012983, 0.013702, 0.014444, 0.015209, 0.015996, 0.016807, 0.017642, 0.018500, 0.019382, 0.020289, 0.021219, 0.022174, 0.023153, 0.024158, 0.025187, 0.026241, 0.027321, 0.028426, 0.029557, 0.030713, 0.031896, 0.033105, + XYZ_GAMMA_LUT: array[0..255] of Single = ( + 0.000000, 0.000304, 0.000607, 0.000911, 0.001214, 0.001518, 0.001821, 0.002125, 0.002428, 0.002732, 0.003035, 0.003345, 0.003677, 0.004025, 0.004391, 0.004777, 0.005182, 0.005605, 0.006049, 0.006512, 0.006995, 0.007499, 0.008023, 0.008568, 0.009134, 0.009721, 0.010330, 0.010960, 0.011612, 0.012286, 0.012983, 0.013702, 0.014444, 0.015209, 0.015996, 0.016807, 0.017642, 0.018500, 0.019382, 0.020289, 0.021219, 0.022174, 0.023153, 0.024158, 0.025187, 0.026241, 0.027321, 0.028426, 0.029557, 0.030713, 0.031896, 0.033105, 0.034340, 0.035601, 0.036889, 0.038204, 0.039546, 0.040915, 0.042311, 0.043735, 0.045186, 0.046665, 0.048172, 0.049707, 0.051269, 0.052861, 0.054480, 0.056128, 0.057805, 0.059511, 0.061246, 0.063010, 0.064803, 0.066626, 0.068478, 0.070360, 0.072272, 0.074214, 0.076185, 0.078187, 0.080220, 0.082283, 0.084376, 0.086500, 0.088656, 0.090842, 0.093059, 0.095307, 0.097587, 0.099899, 0.102242, 0.104616, 0.107023, 0.109462, 0.111932, 0.114435, 0.116971, 0.119538, 0.122139, 0.124772, 0.127438, 0.130136, 0.132868, 0.135633, 0.138432, 0.141263, 0.144128, 0.147027, 0.149960, 0.152926, 0.155926, 0.158961, 0.162029, 0.165132, 0.168269, 0.171441, 0.174647, 0.177888, 0.181164, 0.184475, 0.187821, 0.191202, 0.194618, 0.198069, 0.201556, 0.205079, 0.208637, 0.212231, 0.215861, 0.219526, 0.223228, 0.226966, 0.230740, 0.234551, 0.238398, 0.242281, 0.246201, 0.250158, 0.254152, 0.258183, 0.262251, 0.266356, 0.270498, 0.274677, 0.278894, 0.283149, 0.287441, 0.291771, 0.296138, 0.300544, 0.304987, 0.309469, 0.313989, 0.318547, 0.323143, 0.327778, 0.332452, 0.337164, 0.341914, 0.346704, 0.351533, 0.356400, 0.361307, 0.366253, 0.371238, 0.376262, 0.381326, 0.386429, 0.391572, 0.396755, 0.401978, 0.407240, 0.412543, 0.417885, 0.423268, 0.428690, 0.434154, 0.439657, 0.445201, 0.450786, 0.456411, 0.462077, 0.467784, 0.473531, 0.479320, 0.485150, 0.491021, 0.496933, 0.502886, 0.508881, 0.514918, 0.520996, 0.527115, 0.533276, 0.539479, 0.545724, 0.552011, 0.558340, 0.564712, 0.571125, 0.577580, 0.584078, 0.590619, 0.597202, 0.603827, 0.610496, 0.617207, 0.623960, @@ -97,13 +97,15 @@ class function TSimbaColorConversion.BGRAToRGB(const RGB: TColorBGRA): TColorRGB class function TSimbaColorConversion.RGBToXYZ(const RGB: TColorRGB): TColorXYZ; var vR,vG,vB: Single; +const + // D65 White Point + D65_Xn: Single = 0.95047; + D65_Yn: Single = 1.00000; + D65_Zn: Single = 1.08883; begin - if RGB.R > 10 then vR := XYZ_POW_2_4[RGB.R] - else vR := (RGB.R / 255.0) / 12.92; - if RGB.G > 10 then vG := XYZ_POW_2_4[RGB.G] - else vG := (RGB.G / 255.0) / 12.92; - if RGB.B > 10 then vB := XYZ_POW_2_4[RGB.B] - else vB := (RGB.B / 255.0) / 12.92; + vR := XYZ_GAMMA_LUT[RGB.R]; + vG := XYZ_GAMMA_LUT[RGB.G]; + vB := XYZ_GAMMA_LUT[RGB.B]; vR := vR * 100; vG := vG * 100; @@ -113,23 +115,29 @@ class function TSimbaColorConversion.RGBToXYZ(const RGB: TColorRGB): TColorXYZ; Result.X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805); Result.Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722); Result.Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505); + + // Normalize XYZ by D65 white point + Result.X /= D65_Xn; + Result.Y /= D65_Yn; + Result.Z /= D65_Zn; end; class function TSimbaColorConversion.RGBToLAB(const RGB: TColorRGB): TColorLAB; var vR,vG,vB, X,Y,Z: Single; +const + D65_Xn_Inv: Single = 1.0 / 0.95047; + D65_Yn_Inv: Single = 1.0 / 1.00000; + D65_Zn_Inv: Single = 1.0 / 1.08883; begin - if RGB.R > 10 then vR := XYZ_POW_2_4[RGB.R] - else vR := (RGB.R / 255.0) / 12.92; - if RGB.G > 10 then vG := XYZ_POW_2_4[RGB.G] - else vG := (RGB.G / 255.0) / 12.92; - if RGB.B > 10 then vB := XYZ_POW_2_4[RGB.B] - else vB := (RGB.B / 255.0) / 12.92; + vR := XYZ_GAMMA_LUT[RGB.R]; + vG := XYZ_GAMMA_LUT[RGB.G]; + vB := XYZ_GAMMA_LUT[RGB.B]; - // Illuminant = D65 - X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805); - Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722); - Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505); + // Illuminant = D65 & Normalize D65 + X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805) * D65_Xn_Inv; + Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722) * D65_Yn_Inv; + Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505) * D65_Zn_Inv; // XYZ To LAB if X > 0.008856 then X := Power(X, ONE_DIV_THREE) @@ -389,9 +397,9 @@ class function TSimbaColorConversion.LABToXYZ(const LAB: TColorLAB): TColorXYZ; if (vZ3 > 0.008856) then vZ := vZ3 else vZ := (vZ - 16 / 116) / 7.787; - Result.X := vX * 100.0; + Result.X := vX * 95.047; Result.Y := vY * 100.0; - Result.Z := vZ * 100.0; + Result.Z := vZ * 108.883; end; class function TSimbaColorConversion.LABToRGB(const LAB: TColorLAB): TColorRGB; diff --git a/Source/simba.colormath_distance_unrolled.pas b/Source/simba.colormath_distance_unrolled.pas index 68fd28cc3..57826e212 100644 --- a/Source/simba.colormath_distance_unrolled.pas +++ b/Source/simba.colormath_distance_unrolled.pas @@ -135,27 +135,28 @@ function DistanceXYZ_UnRolled(const C1: PColorXYZ; const C2: TColorBGRA; const m var vR,vG,vB: Single; Color1, Color2: TColorXYZ; +const + D65_Xn_Inv: Single = 1.0 / 0.95047; + D65_Yn_Inv: Single = 1.0 / 1.00000; + D65_Zn_Inv: Single = 1.0 / 1.08883; begin Color1 := C1^; // function RGBToXYZ with C2 do begin - if R > 10 then vR := XYZ_POW_2_4[R] - else vR := (R / 255.0) / 12.92; - if G > 10 then vG := XYZ_POW_2_4[G] - else vG := (G / 255.0) / 12.92; - if B > 10 then vB := XYZ_POW_2_4[B] - else vB := (B / 255.0) / 12.92; + vR := XYZ_GAMMA_LUT[R]; + vG := XYZ_GAMMA_LUT[G]; + vB := XYZ_GAMMA_LUT[B]; end; vR := vR * 100; vG := vG * 100; vB := vB * 100; - Color2.X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805); - Color2.Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722); - Color2.Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505); + Color2.X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805) * D65_Xn_Inv; + Color2.Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722) * D65_Yn_Inv; + Color2.Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505) * D65_Zn_Inv; // function DistanceXYZ Result := Sqrt(Sqr((Color1.X - Color2.X) * mul[0]) + Sqr((Color1.Y - Color2.Y) * mul[1]) + Sqr((Color1.Z - Color2.Z) * mul[2])); @@ -165,23 +166,24 @@ function DistanceLAB_UnRolled(const C1: PColorLAB; const C2: TColorBGRA; const m var vR,vG,vB, X,Y,Z: Single; Color1, Color2: TColorLAB; +const + D65_Xn_Inv: Single = 1.0 / 0.95047; + D65_Yn_Inv: Single = 1.0 / 1.00000; + D65_Zn_Inv: Single = 1.0 / 1.08883; begin Color1 := C1^; // function RGBToLAB with C2 do begin - if R > 10 then vR := XYZ_POW_2_4[R] - else vR := (R / 255.0) / 12.92; - if G > 10 then vG := XYZ_POW_2_4[G] - else vG := (G / 255.0) / 12.92; - if B > 10 then vB := XYZ_POW_2_4[B] - else vB := (B / 255.0) / 12.92; + vR := XYZ_GAMMA_LUT[R]; + vG := XYZ_GAMMA_LUT[G]; + vB := XYZ_GAMMA_LUT[B]; end; - X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805); - Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722); - Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505); + X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805) * D65_Xn_Inv; + Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722) * D65_Yn_Inv; + Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505) * D65_Zn_Inv; if X > 0.008856 then X := Power(X, ONE_DIV_THREE) else X := (7.787 * X) + 0.137931; @@ -202,23 +204,24 @@ function DistanceLCH_UnRolled(const C1: PColorLCH; const C2: TColorBGRA; const m var vR,vG,vB, X,Y,Z, L,A,B, deltaH: Single; Color1, Color2: TColorLCH; +const + D65_Xn_Inv: Single = 1.0 / 0.95047; + D65_Yn_Inv: Single = 1.0 / 1.00000; + D65_Zn_Inv: Single = 1.0 / 1.08883; begin Color1 := C1^; // function RGBToLAB with C2 do begin - if R > 10 then vR := XYZ_POW_2_4[R] - else vR := (R / 255.0) / 12.92; - if G > 10 then vG := XYZ_POW_2_4[G] - else vG := (G / 255.0) / 12.92; - if B > 10 then vB := XYZ_POW_2_4[B] - else vB := (B / 255.0) / 12.92; + vR := XYZ_GAMMA_LUT[R]; + vG := XYZ_GAMMA_LUT[G]; + vB := XYZ_GAMMA_LUT[B]; end; - X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805); - Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722); - Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505); + X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805) * D65_Xn_Inv; + Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722) * D65_Yn_Inv; + Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505) * D65_Zn_Inv; if X > 0.008856 then X := Power(X, ONE_DIV_THREE) else X := (7.787 * X) + 0.137931; @@ -265,23 +268,24 @@ function DistanceDeltaE_UnRolled(const C1: PColorLAB; const C2: TColorBGRA; cons vR,vG,vB, X,Y,Z: Single; xC1,xC2,xDL,xDC,xDE,xDH,xSC,xSH: Single; Color1, Color2: TColorLAB; +const + D65_Xn_Inv: Single = 1.0 / 0.95047; + D65_Yn_Inv: Single = 1.0 / 1.00000; + D65_Zn_Inv: Single = 1.0 / 1.08883; begin Color1 := C1^; // function RGBToLAB with C2 do begin - if R > 10 then vR := XYZ_POW_2_4[R] - else vR := (R / 255.0) / 12.92; - if G > 10 then vG := XYZ_POW_2_4[G] - else vG := (G / 255.0) / 12.92; - if B > 10 then vB := XYZ_POW_2_4[B] - else vB := (B / 255.0) / 12.92; + vR := XYZ_GAMMA_LUT[R]; + vG := XYZ_GAMMA_LUT[G]; + vB := XYZ_GAMMA_LUT[B]; end; - X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805); - Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722); - Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505); + X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805) * D65_Xn_Inv; + Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722) * D65_Yn_Inv; + Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505) * D65_Zn_Inv; if X > 0.008856 then X := Power(X, ONE_DIV_THREE) else X := (7.787 * X) + 0.137931;