# Re: [csswg-drafts] [css-color-4] Conversion precision for hue in LCH model creates false results (#5309)

From: Chris Lilley via GitHub <sysbot+gh@w3.org>
Date: Fri, 27 Nov 2020 16:40:45 +0000

Message-ID: <issue_comment.created-734915273-1606495243-sysbot+gh@w3.org>
```[Here](https://github.com/LeaVerou/color.js/blob/c78e6657600f092126eed865ab03fcb51355c075/src/spaces/lch.js#L15-L34) is the solution we are using in [color.js](https://colorjs.io/):

```js
from: {
lab (Lab) {
// Convert to polar form
let [L, a, b] = Lab;
let hue;
const ε = 0.0005;

if (Math.abs(a) < ε && Math.abs(b) < ε) {
hue = NaN;
}
else {
hue = Math.atan2(b, a) * 180 / Math.PI;
}

return [
L, // L is still L
Math.sqrt(a ** 2 + b ** 2), // Chroma
angles.constrain(hue) // Hue, in degrees [0 to 360)
];
}
```

> I'm using the Chroma value to determine if the hue should be clamped. And C < 0.01 is well below the 8bit quantize level.

Hmm, we are doing an epsilon on a and b which gives a square area on the neutral axis. Using chroma gives a circular area and would be better. We return `NaN` for the hue angle of these indeterminate-hue colors. Our epsilon is smaller than yours, ideally we want it below the 12bit level in Rec BT.2020 colorspace and I should probably verify that it is.

> ALSO: I stay in D65 because I am not doing anything related to print, CMYK, ProPhoto, or comparing to D50, et

Okay, but that means the Lab value you calculate and published Lab measurements, or the Lab result returned from a commercial spectroradiometer will be different. I wasn't sure about this either, but some expert guidance plus a desire to be compatible with ICC workflows plus my own experimenting on round-trip error produced by Bradford CAT between D65 to D50 to D65 again, convinced me this was not a significant source of error.

> In addition I've pre-calculated all the constants and rounded to 20 places which had a great effect on reducing the noise for grey sRGB colors, and the pre-calcs improve performance too.

Yes, early rounding has often been a source of trouble. That is why the sRGB specification changed the transfer function during standardization, because the early testing was done at high precision while the published proposal was rounded  to insufficient number of significant digits and the linear and curved portions of the transfer function didn't actually meet! (Not that this had any visible effect below 10 bits per component).

Likewise the CIE publication 15 was revised to give the constants as rational numbers rather than a rounded-off floating point value. Color.js [also uses those](https://github.com/LeaVerou/color.js/blob/c78e6657600f092126eed865ab03fcb51355c075/src/spaces/lab.js#L15-L16):

```js
ε: 216/24389,  // 6^3/29^3
κ: 24389/27,   // 29^3/3^3
```

and [again for Jzazbz](https://github.com/LeaVerou/color.js/blob/c78e6657600f092126eed865ab03fcb51355c075/src/spaces/jzazbz.js#L15-L23):

```js
b: 1.15,
g: 0.66,
n:2610 / (2 ** 14),
ninv: (2 ** 14) / 2610,
c1: 3424 / (2 ** 12),
c2: 2413 / (2 ** 7),
c3: 2392 / (2 ** 7),
p: 1.7 * 2523 / (2 ** 5),
pinv: (2 ** 5) / (1.7 * 2523),
```

> I think I could get even lower noise in C if I recalc the sRGB -> XYZ matrix to a higher precision too.

Perhaps, although the precision limit is that the defining chromaticities for most colorspaces are only given to 2 or 3 significant figures.

It isn't really noise (in the sense of measurement noise, although that can certainly be a factor especially for spectroradiometric measurements of dark colors unless care is taken to specify a longer integration time) but simply numerical instability as _a_ and _b_ tend to zero.

Returning `NaN` in such cases allows handling to be deferred to later processing. Sometimes it is appropriate to treat it as zero, in other cases (such as perceptually uniform interpolation on LCH) it is better to substitute the hue angle of the other color being interpolated.

--
GitHub Notification of comment by svgeesus
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/5309#issuecomment-734915273 using your GitHub account

--
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
```
Received on Friday, 27 November 2020 16:40:47 UTC

This archive was generated by hypermail 2.4.0 : Tuesday, 5 July 2022 06:42:22 UTC