@@ -31,9 +31,9 @@ impl ToLAB for RGBLU {
3131
3232 let epsilon: f32 = 216. / 24389. ;
3333 let k = 24389. / ( 27. * 116. ) ; // http://www.brucelindbloom.com/LContinuity.html
34- let X = if fx > epsilon { fx . cbrt ( ) - 16. / 116. } else { k * fx } ;
35- let Y = if fy > epsilon { fy . cbrt ( ) - 16. / 116. } else { k * fy } ;
36- let Z = if fz > epsilon { fz . cbrt ( ) - 16. / 116. } else { k * fz } ;
34+ let X = if fx > epsilon { cbrt_poly ( fx ) - 16. / 116. } else { k * fx } ;
35+ let Y = if fy > epsilon { cbrt_poly ( fy ) - 16. / 116. } else { k * fy } ;
36+ let Z = if fz > epsilon { cbrt_poly ( fz ) - 16. / 116. } else { k * fz } ;
3737
3838 let lab = (
3939 ( Y * 1.05f32 ) , // 1.05 instead of 1.16 to boost color importance without pushing colors outside of 1.0 range
@@ -45,6 +45,21 @@ impl ToLAB for RGBLU {
4545 }
4646}
4747
48+ fn cbrt_poly ( x : f32 ) -> f32 {
49+ // Polynomial approximation
50+ let poly = [ 0.2 , 1.51 , -0.5 ] ;
51+ let y = ( poly[ 2 ] * x + poly[ 1 ] ) * x + poly[ 0 ] ;
52+
53+ // 2x Halley's Method
54+ let y3 = y* y* y;
55+ let y = y * ( y3 + 2. * x) / ( 2. * y3 + x) ;
56+ let y3 = y* y* y;
57+ let y = y * ( y3 + 2. * x) / ( 2. * y3 + x) ;
58+ debug_assert ! ( y < 1.001 ) ;
59+ debug_assert ! ( x < 216. / 24389. || y >= 16. / 116. ) ;
60+ y
61+ }
62+
4863/// Convert image to L\*a\*b\* planar
4964///
5065/// It should return 1 (gray) or 3 (color) planes.
@@ -153,3 +168,41 @@ impl ToLABBitmap for ImgRef<'_, RGBLU> {
153168 } )
154169 }
155170}
171+
172+ #[ test]
173+ fn cbrts1 ( ) {
174+ let mut totaldiff = 0. ;
175+ let mut maxdiff: f64 = 0. ;
176+ for i in ( 0 ..=10001 ) . rev ( ) {
177+ let x = ( i as f64 / 10001. ) as f32 ;
178+ let a = cbrt_poly ( x) ;
179+ let actual = a * a * a;
180+ let expected = x;
181+ let absdiff = ( expected as f64 - actual as f64 ) . abs ( ) ;
182+ assert ! ( absdiff < 0.0002 , "{expected} - {actual} = {} @ {x}" , expected - actual) ;
183+ if i % 400 == 0 {
184+ println ! ( "{:+0.3}" , ( expected - actual) * 255. ) ;
185+ }
186+ totaldiff += absdiff;
187+ maxdiff = maxdiff. max ( absdiff) ;
188+ }
189+ println ! ( "1={totaldiff:0.6}; {maxdiff:0.8}" ) ;
190+ assert ! ( totaldiff < 0.0025 , "{totaldiff}" ) ;
191+ }
192+
193+ #[ test]
194+ fn cbrts2 ( ) {
195+ let mut totaldiff = 0. ;
196+ let mut maxdiff: f64 = 0. ;
197+ for i in ( 2000 ..=10001 ) . rev ( ) {
198+ let x = i as f64 / 10001. ;
199+ let actual = cbrt_poly ( x as f32 ) as f64 ;
200+ let expected = x. cbrt ( ) ;
201+ let absdiff = ( expected - actual) . abs ( ) ;
202+ totaldiff += absdiff;
203+ maxdiff = maxdiff. max ( absdiff) ;
204+ assert ! ( absdiff < 0.0000005 , "{expected} - {actual} = {} @ {x}" , expected - actual) ;
205+ }
206+ println ! ( "2={totaldiff:0.6}; {maxdiff:0.8}" ) ;
207+ assert ! ( totaldiff < 0.0025 , "{totaldiff}" ) ;
208+ }
0 commit comments