-
-
Notifications
You must be signed in to change notification settings - Fork 85
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
How do I properly map CAM16 and HCT to srgb/p3 gamut? #579
Comments
So, let me start off by saying that CAM16 is designed specifically for colors within the visible spectrum, as are most color spaces. Some color spaces convert better outside of that range due to the simplicity and specifics of their conversion algorithms, but not all color spaces perform well outside of that range. CAM16 (and HCT which is derived from CAM16 and Lab) is designed to be perceptually uniform. To do this, a complex algorithm is used to bend the colors through the color space to be perceptually uniform. The algorithms are optimized to do this well within the visible color spectrum, but with many of these perceptual algorithms, all bets are off once the colors are outside the visible spectrum. Some perceptual color spaces may perform outside these ranges better than others, and some perceptual spaces may convert better outside these ranges with specific hue ranges than other hue ranges. To illustrate this problem, you can see the conversation on Oklab's limitations here. This has an image that beautifully illustrates what I'm talking about. Certain regions past the visible spectrum, most notably blue, have their hue lines fall apart and collapse. It is no different with spaces like HCT and CAM16. We can also see this in CAM16 when we try and plot the color space in the ProPhoto gamut which has a blue region that extends outside the visible spectrum. Notice that the blue portion starts to wrap back into itself. So, how can you work better with these colors? If we want to minimize HCT and CAM16 color issues during gamut mapping, then we want to gamut map within HCT or CAM16, not OkLCh which will cause us to convert to another color space introducing this issue. Essentially, we want to correct the high chroma before we convert out of the color space. Color.js has its playground broken in their docs, so I am going to use a different app just to visualize what I'm talking about and then I will demonstrate how to do what I'm suggesting in Color.js. Notice below that when we gamut map HCT colors in HCT (not OkLCh) that the results are better! ![]() So, in Color.js, this means doing something like this. Notice the second one gives us a more expected value. > new Color('hct', [193, 100, 30]).toGamut({'space': 'p3'}).coords
[ 184.23341509813838, 29.79869340206087, 18.572330969327616 ]
> new Color('hct', [193, 100, 30]).toGamut({'space': 'p3', 'method': 'hct'}).coords
[ 192.92010189388748, 37.11907910096848, 30.506469338229138 ] Now for CAM16, we do not currently implement a ∆E method in CAM16 required for gamut mapping directly in CAM16 (at least based on the current gamut mapping approach employed). We also do not currently implement an approach that gamut maps without requiring such a ∆E method. So for CAM16 we don't have a good way currently to do the same. CAM16 was mainly added as a requirement to expose HCT as that is a popular color space that users were requesting. |
I just included the method key and it works like a charm producing the desired results. Thank you very much. |
In both CAM16 and HCT I noticed that produced ranges can include odd colors for range slider gradients.
For CAM16 this happens on
Hue ranges between 227-264 where
Colorfullness range >= 104
Odd J color values observed < 25
I assume HCT shows simular problems because it uses CAM16 as a base.
For HCT this becomes visible on the Tone range when
Colorfulness > 90
Hue range between 193 - 324
Odd Tones observed < 33
This can be tested and reproduced on your own colorpicker demo. I am not familiar with the math related to this, but I would prefer the produced ranges to match visual expectations rather than to reflect math results. toGamut({space: 'srgb/p3'}) both produce visually identical results.
I have no clue why this happens really. is there any toGamut setting i can use to prevent this behavior?
The text was updated successfully, but these errors were encountered: