Skip to content

Commit a93401c

Browse files
committed
cbrt -> fcbrt & move to colormath_conversion
function is similar to fcbrt in colorlib, while not limited to x86 assembler, and rather than int magic we do sqrt and one more pass of newtons method.
1 parent fe10e4a commit a93401c

File tree

2 files changed

+29
-23
lines changed

2 files changed

+29
-23
lines changed

Source/simba.colormath_conversion.pas

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,25 @@ TSimbaColorConversion = class
6060
class function XYZToRGB(const XYZ: TColorXYZ): TColorRGB; static;
6161
end;
6262

63+
function fcbrt(x: Single): Single; inline;
64+
6365
implementation
6466

67+
(*
68+
* 2-4x speedup over Power(x, 1/3) in LAB colorspace finding
69+
* Not a generalizable solution, but good for small numbers
70+
* For number beyond this, consider the less accurate (for small numbers)
71+
* https://pastebin.com/uRAwkm7s - Sun Microsystems (C) 1993
72+
*)
73+
function fcbrt(x: Single): Single; inline;
74+
begin
75+
Result := Sqrt(x);
76+
Result := (2.0 * Result + x / Sqr(Result)) / 3.0;
77+
Result := (2.0 * Result + x / Sqr(Result)) / 3.0;
78+
Result := (2.0 * Result + x / Sqr(Result)) / 3.0;
79+
//Result := (2.0 * Result + x / Sqr(Result)) / 3.0; // Can't see that we need one more
80+
end;
81+
6582
class function TSimbaColorConversion.ColorToBGRA(const Color: TColor; const Alpha: Byte): TColorBGRA;
6683
begin
6784
Result.R := (Color and R_MASK) shr R_BIT;
@@ -140,11 +157,11 @@ class function TSimbaColorConversion.RGBToLAB(const RGB: TColorRGB): TColorLAB;
140157
Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505) * D65_Zn_Inv;
141158

142159
// XYZ To LAB
143-
if X > 0.008856 then X := Power(X, ONE_DIV_THREE)
160+
if X > 0.008856 then X := fcbrt(x)
144161
else X := (7.787 * X) + 0.137931;
145-
if Y > 0.008856 then Y := Power(Y, ONE_DIV_THREE)
162+
if Y > 0.008856 then Y := fcbrt(y)
146163
else Y := (7.787 * Y) + 0.137931;
147-
if Z > 0.008856 then Z := Power(Z, ONE_DIV_THREE)
164+
if Z > 0.008856 then Z := fcbrt(z)
148165
else Z := (7.787 * Z) + 0.137931;
149166

150167
Result.L := (116.0 * Y) - 16.0;

Source/simba.colormath_distance_unrolled.pas

Lines changed: 9 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,6 @@ function DistanceDeltaE_UnRolled(const C1: PColorLAB; const C2: TColorBGRA; cons
2929

3030
implementation
3131

32-
// 2-4x speedup over Power(x, 1/3) in LAB colorspace finding
33-
function Cbrt(x: Single): Single; inline;
34-
begin
35-
Result := Sqrt(x);
36-
Result := (2.0 * Result + x / Sqr(Result)) / 3.0;
37-
Result := (2.0 * Result + x / Sqr(Result)) / 3.0;
38-
Result := (2.0 * Result + x / Sqr(Result)) / 3.0;
39-
//Result := (2.0 * Result + x / Sqr(Result)) / 3.0; // Can't see that we need one more
40-
end;
41-
42-
4332
function DistanceRGB_UnRolled(const C1: PColorRGB; const C2: TColorBGRA; const mul: TChannelMultipliers): Single;
4433
begin
4534
Result := Sqrt(Sqr((C1^.R-C2.R) * mul[0]) + Sqr((C1^.G-C2.G) * mul[1]) + Sqr((C1^.B-C2.B) * mul[2]));
@@ -196,11 +185,11 @@ function DistanceLAB_UnRolled(const C1: PColorLAB; const C2: TColorBGRA; const m
196185
Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722) * D65_Yn_Inv;
197186
Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505) * D65_Zn_Inv;
198187

199-
if X > 0.008856 then X := Cbrt(X)
188+
if X > 0.008856 then X := fcbrt(X)
200189
else X := (7.787 * X) + 0.137931;
201-
if Y > 0.008856 then Y := Cbrt(Y)
190+
if Y > 0.008856 then Y := fcbrt(Y)
202191
else Y := (7.787 * Y) + 0.137931;
203-
if Z > 0.008856 then Z := Cbrt(Z)
192+
if Z > 0.008856 then Z := fcbrt(Z)
204193
else Z := (7.787 * Z) + 0.137931;
205194

206195
Color2.L := (116.0 * Y) - 16.0;
@@ -234,11 +223,11 @@ function DistanceLCH_UnRolled(const C1: PColorLCH; const C2: TColorBGRA; const m
234223
Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722) * D65_Yn_Inv;
235224
Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505) * D65_Zn_Inv;
236225

237-
if X > 0.008856 then X := Cbrt(X)
226+
if X > 0.008856 then X := fcbrt(X)
238227
else X := (7.787 * X) + 0.137931;
239-
if Y > 0.008856 then Y := Cbrt(Y)
228+
if Y > 0.008856 then Y := fcbrt(Y)
240229
else Y := (7.787 * Y) + 0.137931;
241-
if Z > 0.008856 then Z := Cbrt(Z)
230+
if Z > 0.008856 then Z := fcbrt(Z)
242231
else Z := (7.787 * Z) + 0.137931;
243232

244233
L := (116.0 * Y) - 16.0;
@@ -298,11 +287,11 @@ function DistanceDeltaE_UnRolled(const C1: PColorLAB; const C2: TColorBGRA; cons
298287
Y := (vR * 0.2126 + vG * 0.7152 + vB * 0.0722) * D65_Yn_Inv;
299288
Z := (vR * 0.0193 + vG * 0.1192 + vB * 0.9505) * D65_Zn_Inv;
300289

301-
if X > 0.008856 then X := Cbrt(X)
290+
if X > 0.008856 then X := fcbrt(X)
302291
else X := (7.787 * X) + 0.137931;
303-
if Y > 0.008856 then Y := Cbrt(Y)
292+
if Y > 0.008856 then Y := fcbrt(Y)
304293
else Y := (7.787 * Y) + 0.137931;
305-
if Z > 0.008856 then Z := Cbrt(Z)
294+
if Z > 0.008856 then Z := fcbrt(Z)
306295
else Z := (7.787 * Z) + 0.137931;
307296

308297
Color2.L := (116.0 * Y) - 16.0;

0 commit comments

Comments
 (0)