Skip to content

Commit db30237

Browse files
committed
Colormath opt, and D65 normalization
1 parent d619b1c commit db30237

File tree

2 files changed

+68
-56
lines changed

2 files changed

+68
-56
lines changed

Source/simba.colormath_conversion.pas

Lines changed: 28 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ interface
2020
simba.base, simba.math, simba.colormath;
2121

2222
const
23-
XYZ_POW_2_4: array[0..255] of Single = (
24-
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,
23+
XYZ_GAMMA_LUT: array[0..255] of Single = (
24+
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,
2525
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,
2626
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,
2727
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
9797
class function TSimbaColorConversion.RGBToXYZ(const RGB: TColorRGB): TColorXYZ;
9898
var
9999
vR,vG,vB: Single;
100+
const
101+
// D65 White Point
102+
D65_Xn: Single = 0.95047;
103+
D65_Yn: Single = 1.00000;
104+
D65_Zn: Single = 1.08883;
100105
begin
101-
if RGB.R > 10 then vR := XYZ_POW_2_4[RGB.R]
102-
else vR := (RGB.R / 255.0) / 12.92;
103-
if RGB.G > 10 then vG := XYZ_POW_2_4[RGB.G]
104-
else vG := (RGB.G / 255.0) / 12.92;
105-
if RGB.B > 10 then vB := XYZ_POW_2_4[RGB.B]
106-
else vB := (RGB.B / 255.0) / 12.92;
106+
vR := XYZ_GAMMA_LUT[RGB.R];
107+
vG := XYZ_GAMMA_LUT[RGB.G];
108+
vB := XYZ_GAMMA_LUT[RGB.B];
107109

108110
vR := vR * 100;
109111
vG := vG * 100;
@@ -113,23 +115,29 @@ class function TSimbaColorConversion.RGBToXYZ(const RGB: TColorRGB): TColorXYZ;
113115
Result.X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805);
114116
Result.Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722);
115117
Result.Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505);
118+
119+
// Normalize XYZ by D65 white point
120+
Result.X /= D65_Xn;
121+
Result.Y /= D65_Yn;
122+
Result.Z /= D65_Zn;
116123
end;
117124

118125
class function TSimbaColorConversion.RGBToLAB(const RGB: TColorRGB): TColorLAB;
119126
var
120127
vR,vG,vB, X,Y,Z: Single;
128+
const
129+
D65_Xn_Inv: Single = 1.0 / 0.95047;
130+
D65_Yn_Inv: Single = 1.0 / 1.00000;
131+
D65_Zn_Inv: Single = 1.0 / 1.08883;
121132
begin
122-
if RGB.R > 10 then vR := XYZ_POW_2_4[RGB.R]
123-
else vR := (RGB.R / 255.0) / 12.92;
124-
if RGB.G > 10 then vG := XYZ_POW_2_4[RGB.G]
125-
else vG := (RGB.G / 255.0) / 12.92;
126-
if RGB.B > 10 then vB := XYZ_POW_2_4[RGB.B]
127-
else vB := (RGB.B / 255.0) / 12.92;
133+
vR := XYZ_GAMMA_LUT[RGB.R];
134+
vG := XYZ_GAMMA_LUT[RGB.G];
135+
vB := XYZ_GAMMA_LUT[RGB.B];
128136

129-
// Illuminant = D65
130-
X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805);
131-
Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722);
132-
Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505);
137+
// Illuminant = D65 & Normalize D65
138+
X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805) * D65_Xn_Inv;
139+
Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722) * D65_Yn_Inv;
140+
Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505) * D65_Zn_Inv;
133141

134142
// XYZ To LAB
135143
if X > 0.008856 then X := Power(X, ONE_DIV_THREE)
@@ -389,9 +397,9 @@ class function TSimbaColorConversion.LABToXYZ(const LAB: TColorLAB): TColorXYZ;
389397
if (vZ3 > 0.008856) then vZ := vZ3
390398
else vZ := (vZ - 16 / 116) / 7.787;
391399

392-
Result.X := vX * 100.0;
400+
Result.X := vX * 95.047;
393401
Result.Y := vY * 100.0;
394-
Result.Z := vZ * 100.0;
402+
Result.Z := vZ * 108.883;
395403
end;
396404

397405
class function TSimbaColorConversion.LABToRGB(const LAB: TColorLAB): TColorRGB;

Source/simba.colormath_distance_unrolled.pas

Lines changed: 40 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -135,27 +135,28 @@ function DistanceXYZ_UnRolled(const C1: PColorXYZ; const C2: TColorBGRA; const m
135135
var
136136
vR,vG,vB: Single;
137137
Color1, Color2: TColorXYZ;
138+
const
139+
D65_Xn_Inv: Single = 1.0 / 0.95047;
140+
D65_Yn_Inv: Single = 1.0 / 1.00000;
141+
D65_Zn_Inv: Single = 1.0 / 1.08883;
138142
begin
139143
Color1 := C1^;
140144

141145
// function RGBToXYZ
142146
with C2 do
143147
begin
144-
if R > 10 then vR := XYZ_POW_2_4[R]
145-
else vR := (R / 255.0) / 12.92;
146-
if G > 10 then vG := XYZ_POW_2_4[G]
147-
else vG := (G / 255.0) / 12.92;
148-
if B > 10 then vB := XYZ_POW_2_4[B]
149-
else vB := (B / 255.0) / 12.92;
148+
vR := XYZ_GAMMA_LUT[R];
149+
vG := XYZ_GAMMA_LUT[G];
150+
vB := XYZ_GAMMA_LUT[B];
150151
end;
151152

152153
vR := vR * 100;
153154
vG := vG * 100;
154155
vB := vB * 100;
155156

156-
Color2.X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805);
157-
Color2.Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722);
158-
Color2.Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505);
157+
Color2.X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805) * D65_Xn_Inv;
158+
Color2.Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722) * D65_Yn_Inv;
159+
Color2.Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505) * D65_Zn_Inv;
159160

160161
// function DistanceXYZ
161162
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
165166
var
166167
vR,vG,vB, X,Y,Z: Single;
167168
Color1, Color2: TColorLAB;
169+
const
170+
D65_Xn_Inv: Single = 1.0 / 0.95047;
171+
D65_Yn_Inv: Single = 1.0 / 1.00000;
172+
D65_Zn_Inv: Single = 1.0 / 1.08883;
168173
begin
169174
Color1 := C1^;
170175

171176
// function RGBToLAB
172177
with C2 do
173178
begin
174-
if R > 10 then vR := XYZ_POW_2_4[R]
175-
else vR := (R / 255.0) / 12.92;
176-
if G > 10 then vG := XYZ_POW_2_4[G]
177-
else vG := (G / 255.0) / 12.92;
178-
if B > 10 then vB := XYZ_POW_2_4[B]
179-
else vB := (B / 255.0) / 12.92;
179+
vR := XYZ_GAMMA_LUT[R];
180+
vG := XYZ_GAMMA_LUT[G];
181+
vB := XYZ_GAMMA_LUT[B];
180182
end;
181183

182-
X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805);
183-
Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722);
184-
Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505);
184+
X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805) * D65_Xn_Inv;
185+
Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722) * D65_Yn_Inv;
186+
Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505) * D65_Zn_Inv;
185187

186188
if X > 0.008856 then X := Power(X, ONE_DIV_THREE)
187189
else X := (7.787 * X) + 0.137931;
@@ -202,23 +204,24 @@ function DistanceLCH_UnRolled(const C1: PColorLCH; const C2: TColorBGRA; const m
202204
var
203205
vR,vG,vB, X,Y,Z, L,A,B, deltaH: Single;
204206
Color1, Color2: TColorLCH;
207+
const
208+
D65_Xn_Inv: Single = 1.0 / 0.95047;
209+
D65_Yn_Inv: Single = 1.0 / 1.00000;
210+
D65_Zn_Inv: Single = 1.0 / 1.08883;
205211
begin
206212
Color1 := C1^;
207213

208214
// function RGBToLAB
209215
with C2 do
210216
begin
211-
if R > 10 then vR := XYZ_POW_2_4[R]
212-
else vR := (R / 255.0) / 12.92;
213-
if G > 10 then vG := XYZ_POW_2_4[G]
214-
else vG := (G / 255.0) / 12.92;
215-
if B > 10 then vB := XYZ_POW_2_4[B]
216-
else vB := (B / 255.0) / 12.92;
217+
vR := XYZ_GAMMA_LUT[R];
218+
vG := XYZ_GAMMA_LUT[G];
219+
vB := XYZ_GAMMA_LUT[B];
217220
end;
218221

219-
X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805);
220-
Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722);
221-
Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505);
222+
X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805) * D65_Xn_Inv;
223+
Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722) * D65_Yn_Inv;
224+
Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505) * D65_Zn_Inv;
222225

223226
if X > 0.008856 then X := Power(X, ONE_DIV_THREE)
224227
else X := (7.787 * X) + 0.137931;
@@ -265,23 +268,24 @@ function DistanceDeltaE_UnRolled(const C1: PColorLAB; const C2: TColorBGRA; cons
265268
vR,vG,vB, X,Y,Z: Single;
266269
xC1,xC2,xDL,xDC,xDE,xDH,xSC,xSH: Single;
267270
Color1, Color2: TColorLAB;
271+
const
272+
D65_Xn_Inv: Single = 1.0 / 0.95047;
273+
D65_Yn_Inv: Single = 1.0 / 1.00000;
274+
D65_Zn_Inv: Single = 1.0 / 1.08883;
268275
begin
269276
Color1 := C1^;
270277

271278
// function RGBToLAB
272279
with C2 do
273280
begin
274-
if R > 10 then vR := XYZ_POW_2_4[R]
275-
else vR := (R / 255.0) / 12.92;
276-
if G > 10 then vG := XYZ_POW_2_4[G]
277-
else vG := (G / 255.0) / 12.92;
278-
if B > 10 then vB := XYZ_POW_2_4[B]
279-
else vB := (B / 255.0) / 12.92;
281+
vR := XYZ_GAMMA_LUT[R];
282+
vG := XYZ_GAMMA_LUT[G];
283+
vB := XYZ_GAMMA_LUT[B];
280284
end;
281285

282-
X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805);
283-
Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722);
284-
Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505);
286+
X := (vR * 0.4124 + vG * 0.3576 + vB * 0.1805) * D65_Xn_Inv;
287+
Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722) * D65_Yn_Inv;
288+
Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505) * D65_Zn_Inv;
285289

286290
if X > 0.008856 then X := Power(X, ONE_DIV_THREE)
287291
else X := (7.787 * X) + 0.137931;

0 commit comments

Comments
 (0)