From a93401cdb53d350e87f12ceb3b18cef4232c61af Mon Sep 17 00:00:00 2001 From: Jarl Holta Date: Thu, 9 Jan 2025 22:29:23 +0100 Subject: [PATCH] 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. --- Source/simba.colormath_conversion.pas | 23 ++++++++++++++-- Source/simba.colormath_distance_unrolled.pas | 29 ++++++-------------- 2 files changed, 29 insertions(+), 23 deletions(-) diff --git a/Source/simba.colormath_conversion.pas b/Source/simba.colormath_conversion.pas index 765afb0e7..854ddbba9 100644 --- a/Source/simba.colormath_conversion.pas +++ b/Source/simba.colormath_conversion.pas @@ -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; @@ -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; diff --git a/Source/simba.colormath_distance_unrolled.pas b/Source/simba.colormath_distance_unrolled.pas index 74b13d66c..af82b3d2e 100644 --- a/Source/simba.colormath_distance_unrolled.pas +++ b/Source/simba.colormath_distance_unrolled.pas @@ -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])); @@ -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; @@ -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; @@ -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;