-
-
Notifications
You must be signed in to change notification settings - Fork 83
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
Add CAM16 (JMh) #379
Add CAM16 (JMh) #379
Conversation
✅ Deploy Preview for colorjs ready!
To edit notification comments on pull requests, go to your Netlify site configuration. |
One thing to note, undefined values in CSS and this library are assumed to be zero when a real number is required. CAM16 has a non-linear achromatic response that often has achromatic values a non-zero chroma/colorfulness/saturation values. What this means is that chroma and hue both matter when converting achromatic values. Knowing what those values are allows for better round trip conversions. There currently isn't a mechanism in Color.js to handle such things. Ideally, in the future, two things should be considered:
I do not think these questions need to be resolved now to implement the color space, but it should be noted that when undefined values in CAM16 are used, and in the future HCT, that it may not yield the achromatic values that are desired. |
I will also note the "colorfulness" range is based on P3. This can be changed to whatever is desired. |
Adding a little more info on validation. A number of references used:
Results were compared against Colour Science and my implementation in ColorAide as well: https://github.com/colour-science/colour >>> import numpy as np
>>> import colour
>>> from coloraide.everything import ColorAll as Color
>>> xyz = np.array(Color('red').convert('xyz-d65').coords()) * 100
>>> colour.XYZ_to_CAM16(xyz, **colour.appearance.CAM_KWARGS_CIECAM02_sRGB)
CAM_Specification_CAM16(J=46.025701408152251, C=112.3966873794304, h=27.39325656758691, s=98.395239471843041, Q=83.926266178253229, M=81.254248158497788, H=9.2041940637581128, HC=None)
>>> Color('red').convert('cam16-jmh').coords()
[46.025701408152244, 81.25424815849782, 27.3932565675869] Color.js > const { default: Color } = require("colorjs.io");
undefined
> new Color('red').to('cam16-jmh').coords
[ 46.025701408152244, 81.25424815849786, 27.39325656758689 ] |
I have read the Nico Schlömer paper before, and it troubles me that the ISO document did not even consider things like division by zero when producing their specification. Effectively, this paper is the real specification. |
The full text of the Li et al paper originally defining CAM16 is available on ResearchGate, avoiding the Wiley paywall |
Oh, nice. I searched around for a non-paywall version for quite a bit. I can update the reference link. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall this looks great, thanks for doing it.
const adaptedCoefInv = 1 / adaptedCoef; | ||
const tau = 2 * Math.PI | ||
|
||
const cat16 = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A shame that Li et al only give M16 to 7 figures, but there we are
[ -0.002079, 0.048952, 0.953127 ] | ||
]; | ||
|
||
const cat16Inv = [ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree that using a full-precision inverse is better than the rounded, 9 figure inverse published in Appendix A
There should probably be some dim and dark tests, but that should not hold up merging this. |
Unpaywalled
Perhaps we can just say that hue is never powerless in CAM16-JMh and treat |
Feel free to ignore this is not relevant, just a drive-by comment. I know that CAM16 involves a bunch of variables about the viewing conditions, and presumably we had to make some assumptions here. Would it make sense to add a factory method that produces |
These kind of questions I'm not sure I can answer as it really depends on the direction that Color.js wishes to go in. From CAM16, we could create CAM16-UCS, CAM16-SCD, CAM16-LCD, create their distancing algorithms. We could create a dynamic way to create special instances of all these CAM16 related spaces with different viewing conditions. My main goal is to get HCT up and going, and that required getting CAM16 functional. JMh is provided as an easy way to make sure its all working. HCT will be built upon CAM16, but it has a very specific, defined set of viewing conditions. That will likely be my next PR. It will contain the HCT color space and a distancing algorithm. My last PR will provide an HCT gamut mapping algorithm which is the last piece in the puzzle to create the tonal palettes that that are comparable with Google's. It'll need to be tuned to give similar values. I imagine that will require me to leverage the existing algorithm. |
* main: Add CAM16 (JMh) (color-js#379) [spaces/prophoto] Use 64 bit-accurate conversion matrices formatting [spaces/hsl] Better handling of negative saturation on very oog colors Point to the actual, working tests not the old ones CSS4 toGamut fixes (color-js#352)
This is the first step in porting over support for the HCT color space. This adds the CAM16 model along with the output in JMh for verification.