Skip to content

Commit

Permalink
cbrt -> fcbrt & move to colormath_conversion
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
slackydev committed Jan 9, 2025
1 parent fe10e4a commit a93401c
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 23 deletions.
23 changes: 20 additions & 3 deletions Source/simba.colormath_conversion.pas
Original file line number Diff line number Diff line change
Expand Up @@ -60,8 +60,25 @@ TSimbaColorConversion = class
class function XYZToRGB(const XYZ: TColorXYZ): TColorRGB; static;
end;

function fcbrt(x: Single): Single; inline;

implementation

(*
* 2-4x speedup over Power(x, 1/3) in LAB colorspace finding
* Not a generalizable solution, but good for small numbers
* For number beyond this, consider the less accurate (for small numbers)
* https://pastebin.com/uRAwkm7s - Sun Microsystems (C) 1993
*)
function fcbrt(x: Single): Single; inline;
begin
Result := Sqrt(x);
Result := (2.0 * Result + x / Sqr(Result)) / 3.0;
Result := (2.0 * Result + x / Sqr(Result)) / 3.0;
Result := (2.0 * Result + x / Sqr(Result)) / 3.0;
//Result := (2.0 * Result + x / Sqr(Result)) / 3.0; // Can't see that we need one more
end;

class function TSimbaColorConversion.ColorToBGRA(const Color: TColor; const Alpha: Byte): TColorBGRA;
begin
Result.R := (Color and R_MASK) shr R_BIT;
Expand Down Expand Up @@ -140,11 +157,11 @@ class function TSimbaColorConversion.RGBToLAB(const RGB: TColorRGB): TColorLAB;
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)
if X > 0.008856 then X := fcbrt(x)
else X := (7.787 * X) + 0.137931;
if Y > 0.008856 then Y := Power(Y, ONE_DIV_THREE)
if Y > 0.008856 then Y := fcbrt(y)
else Y := (7.787 * Y) + 0.137931;
if Z > 0.008856 then Z := Power(Z, ONE_DIV_THREE)
if Z > 0.008856 then Z := fcbrt(z)
else Z := (7.787 * Z) + 0.137931;

Result.L := (116.0 * Y) - 16.0;
Expand Down
29 changes: 9 additions & 20 deletions Source/simba.colormath_distance_unrolled.pas
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,6 @@ function DistanceDeltaE_UnRolled(const C1: PColorLAB; const C2: TColorBGRA; cons

implementation

// 2-4x speedup over Power(x, 1/3) in LAB colorspace finding
function Cbrt(x: Single): Single; inline;
begin
Result := Sqrt(x);
Result := (2.0 * Result + x / Sqr(Result)) / 3.0;
Result := (2.0 * Result + x / Sqr(Result)) / 3.0;
Result := (2.0 * Result + x / Sqr(Result)) / 3.0;
//Result := (2.0 * Result + x / Sqr(Result)) / 3.0; // Can't see that we need one more
end;


function DistanceRGB_UnRolled(const C1: PColorRGB; const C2: TColorBGRA; const mul: TChannelMultipliers): Single;
begin
Result := Sqrt(Sqr((C1^.R-C2.R) * mul[0]) + Sqr((C1^.G-C2.G) * mul[1]) + Sqr((C1^.B-C2.B) * mul[2]));
Expand Down Expand Up @@ -196,11 +185,11 @@ function DistanceLAB_UnRolled(const C1: PColorLAB; const C2: TColorBGRA; const m
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 := Cbrt(X)
if X > 0.008856 then X := fcbrt(X)
else X := (7.787 * X) + 0.137931;
if Y > 0.008856 then Y := Cbrt(Y)
if Y > 0.008856 then Y := fcbrt(Y)
else Y := (7.787 * Y) + 0.137931;
if Z > 0.008856 then Z := Cbrt(Z)
if Z > 0.008856 then Z := fcbrt(Z)
else Z := (7.787 * Z) + 0.137931;

Color2.L := (116.0 * Y) - 16.0;
Expand Down Expand Up @@ -234,11 +223,11 @@ function DistanceLCH_UnRolled(const C1: PColorLCH; const C2: TColorBGRA; const m
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 := Cbrt(X)
if X > 0.008856 then X := fcbrt(X)
else X := (7.787 * X) + 0.137931;
if Y > 0.008856 then Y := Cbrt(Y)
if Y > 0.008856 then Y := fcbrt(Y)
else Y := (7.787 * Y) + 0.137931;
if Z > 0.008856 then Z := Cbrt(Z)
if Z > 0.008856 then Z := fcbrt(Z)
else Z := (7.787 * Z) + 0.137931;

L := (116.0 * Y) - 16.0;
Expand Down Expand Up @@ -298,11 +287,11 @@ function DistanceDeltaE_UnRolled(const C1: PColorLAB; const C2: TColorBGRA; cons
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 := Cbrt(X)
if X > 0.008856 then X := fcbrt(X)
else X := (7.787 * X) + 0.137931;
if Y > 0.008856 then Y := Cbrt(Y)
if Y > 0.008856 then Y := fcbrt(Y)
else Y := (7.787 * Y) + 0.137931;
if Z > 0.008856 then Z := Cbrt(Z)
if Z > 0.008856 then Z := fcbrt(Z)
else Z := (7.787 * Z) + 0.137931;

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

0 comments on commit a93401c

Please sign in to comment.