Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-color] D50 mismatch in Lab ↔ sRGB algorithms #2492

Closed
danburzo opened this issue Apr 2, 2018 · 11 comments
Closed

[css-color] D50 mismatch in Lab ↔ sRGB algorithms #2492

danburzo opened this issue Apr 2, 2018 · 11 comments

Comments

@danburzo
Copy link

danburzo commented Apr 2, 2018

In Section 17. Sample code for color conversions of the CSS Color Module Level 4 spec, there's a discrepancy with the D50 white point values.

In the XYZ ↔ Lab conversion code, it's assumed to be [0.9642, 1.0000, 0.8249] (as specified by the ICC spec).

However, the D50 ↔ D65 chromatic adaptation uses Bradford matrices from this page, which have been computed for D50 being [0.96422, 1.00000, 0.82521].

I think the correct approach is to use the ICC-defined D50 throughout, no?

(Also, I'm not clear on why the ICC value for the D50 white point differs from the generally accepted one. e.g. Matlab).

@danburzo
Copy link
Author

danburzo commented Apr 2, 2018

It may be useful to specify in the section about lab() and lch() colors the specific values for the D50 white point as defined in the Profile Connection Space: [0.9642, 1.0000, 0.8249].

This document contains some matrices that may be useful.

@svgeesus
Copy link
Contributor

svgeesus commented Apr 2, 2018

Thanks for reporting the discrepancy!

neither ICC nor Lindbloom are authoritative for D50, which is defined by the CIE. I will check up and update the spec (and sample code) with the correct value.

I will also check in Wyszecki & Stiles when I get home.

@svgeesus svgeesus self-assigned this Apr 2, 2018
@svgeesus svgeesus added the css-color-4 Current Work label Apr 2, 2018
@danburzo
Copy link
Author

danburzo commented Apr 2, 2018

Thanks!

So if I understand correctly, the intent of the spec is to:

  1. assume CIELAB is relative to D50 (as defined by CIE, not ICC); and furthermore,
  2. the method of computing sRGB ↔️ CIELAB (in particular, the choice of matrices) is non-normative.

In regards to 1, this sentence:

D50 is also the whitepoint used for the profile connection space in ICC color interconversion,

I think may benefit from clarifying the distinction between the ICC definition of D50 and the CIE definition of D50.

In regards to 2, I'm a bit concerned that I've seen many variations on the matrices used to get sRGB ↔️
XYZD65 ↔️ XYZD50, or direct sRGB ↔️ XYZD50 pairs, and I wonder whether some well-defined matrices in the spec won't lead to more consistent implementations, since the approximations and the floating-point errors have a compounding effect on the result.

P.S. This page another set of matrices, and this sentence which further confuses things:

and the values of D65 and D50 from CIE 15.2 (and the ICC specification for D50)
D65 = [95.04; 100; 108.89];
D50 = [96.42; 100; 82.49];

Not having access to CIE 15.2, I'm having a hard time piecing things together...

@svgeesus
Copy link
Contributor

svgeesus commented Apr 3, 2018

I've seen many variations on the matrices used to get sRGB ↔️
XYZD65 ↔️ XYZD50, or direct sRGB ↔️ XYZD50 pairs

Firstly, you can't do any of those with just a matrix; the sRGB needs to be linearized first. But having done that step, the operations for lin_sRGB to XYZ_D65, and XYZ_D65 to LMS, and white adjustment, and LMS to XYZ_D50 are all 3x3 matrices so the overall matrix is obtained by matrix multiplication.

The slightly different value for the Z component of D50 in ICC is a mistake, not an intentional change, but one they are now unable to correct without requiring all deployed CMS to be updated.

I feel that it would be better to express the correct values in the spec, with enough significant digits to avoid roundoff error.

@danburzo
Copy link
Author

danburzo commented Apr 3, 2018

Also, in the Lab to LCH code, I think Math.atan2() should be normalized to the interval [0, 360).

@svgeesus
Copy link
Contributor

svgeesus commented Apr 3, 2018

Yes, indeed it should. Good catch. Although H is also defined to wrap, if someone enters a hue outside that range.

@danburzo
Copy link
Author

danburzo commented Apr 3, 2018

Ah yes, I had somehow misread that H is <number> not <hue>. Too much time in front of the screen :)

@danburzo
Copy link
Author

danburzo commented Apr 4, 2018

Some updates from my D50 saga: As I wrote in this thread, I was not able to find appropriate matrices for the conversion between sRGB and CIELab that did not introduce non-negligible errors. One particular doozy is that grayscale RGB colors will produce a Chroma of up to 0.0035 in the LCH equivalent.

@danburzo
Copy link
Author

danburzo commented Apr 6, 2018

One last thing is nagging me: is there a benefit to keeping the CIELab values relative to D50 rather than sRGB's D65? Since the standard D50 does not match the values from ICC / Profile Connection Space... Defining lab() as relative to D65 would make computations simpler.

@svgeesus
Copy link
Contributor

svgeesus commented Apr 6, 2018

Yes, the value is that everyone else uses D50. If you use a spectrometer to measure color it will give you a readout in Lab with a D50 whitepoint.

@danburzo
Copy link
Author

danburzo commented Apr 6, 2018

Thank you for the clarification!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants