GithubHelp home page GithubHelp logo

Comments (13)

tabatkins avatar tabatkins commented on May 21, 2024

Ah I see, it skirts right next to the boundary for a long while before it finally touches. I agree, that doesn't match expectation; a brighter yellow (with slightly less red) is much closer to the author's intent.

Hmm, getting this right is a little tricky. Seems like the right approach might be to check, on each hop, if we're close to the gamut in absolute terms (that is, if a small channel clip would bring us in-gamut, with minimal color-warping), and if so, treat that as in-gamut for the purpose of the binary search.

That should find us a value with minimal-to-zero blue in this case, and only a tiny warp in hue.

I wonder if we want to be slightly more sophisticated than binary search, too - start the search with a linear spread of probes along the chrome-reduction path, then weight closeness-to-gamut against amount-of-chroma-reduction to find the interval to search in.

from color.js.

tabatkins avatar tabatkins commented on May 21, 2024

Hmmm, that final suggestion of mine might also help us deal with the "overhang" problem, where the varying-chroma line has multiple in-gamut and out-of-gamut sections. Binary search can skip over the overhang, even if it's close to the starting color, and force us to the much lower-chroma solution; and if the starting color is between the two in-gamut segments, looking only at decreased chroma values will never find the higher-chroma segment, even if it's just barely higher than the starting color!

So doing a quick probe of several locations, mostly below but some above, the starting color and checking if they're "close" to being in-gamut (that is, if channel-clipping would be only a tiny change), could really help.

from color.js.

svgeesus avatar svgeesus commented on May 21, 2024

Looking at the blue component, the first few Chroma reduction steps go:

  • -1.27 (original color)
  • -0.827
  • -0.307
  • 0.157

so after 3 iterations the blue component is well inside gamut. Smaller Chroma steps, or binary search that explores the interval between -0.307 and 0.157, would get us close to zero on blue.

Perhaps, to detect "close to boundary" compute ΔE2000 between the current color and a per-component clipped version of the current color?

from color.js.

tabatkins avatar tabatkins commented on May 21, 2024

I was thinking even simpler - just a quick "in the output space, is the distance between the current point and a channel-clipped version below ε?", but doing the distance computation in ΔE is probably smarter. ^_^

from color.js.

svgeesus avatar svgeesus commented on May 21, 2024

I did some calculations. deltaE2000 between P3 yellow and sRGB yellow is 5 (noticeable side by side, but fairly similar) while deltaE2000 between P3 yellow and our super-desaturated gamut mapped yellow is a whopping 22.4.

yellows

from color.js.

svgeesus avatar svgeesus commented on May 21, 2024

Ok even better, looking at the values Lea posted before and doing a clip when it is close, we get a deltaE2000 of 0.79 which is barely visible:

yellow2

from color.js.

tabatkins avatar tabatkins commented on May 21, 2024

First of all, nice.

Second, yeah, I've been thinking about this somewhat wrong. Our goal is to find the color as close to the original as possible which is in the output gamut. So we don't need to do any of that "balance out the chroma reduction vs the clipping distance", we just need to minimize the ΔE along the chroma-reduction line.

So yeah, sample a smattering of points in either direction (each 10 points of chroma?) from the starting point along the chroma increase/decrease line, channel-clipping each into the output gamut and measuring the ΔE from the starting color. Find the point with the smallest ΔE, and sub-sample on either side to find the minimum ΔE within the precision we want to care about.

I'm curious if there are any degenerate cases here we'd want to guard against, where the minimum ΔE would be for a channel-clipped color but still be fairly large. It's probably better to stay constant-hue-and-lightness in that case, right? So maybe check if the smallest ΔE from the initial sampling is above some threshold (5? 10?) and if so, just stick with the normal binary-search along the chroma-reduction line (aided by the fact that you already know approximately where it is, so you can start the search pretty accurately); this way you'll only shift the hue/lightness a tiny bit when it's warranted.

from color.js.

svgeesus avatar svgeesus commented on May 21, 2024

A recent analysis Colour gamut mapping between small and large colour gamuts: Part I. gamut compression

Note that most color gamut mapping research is concerned with natural, photographic images. Images containing vector-style graphics and type are rarely considered. Colors that form a palette of colors used in a Web page are pretty much never considered. However, the paper above examines several approaches including mapping towards the black point or white point rather than along lines of constant Lightness. In addition to CIE Lab, it also examines CAM02-UCS and Jzazbz for gamut mapping

from color.js.

svgeesus avatar svgeesus commented on May 21, 2024

This is very well illustrated in Kenichiro Masaoka, Yuichi Kusakabe, Takayuki Yamashita, Yukihiro Nishida, Tetsuomi Ikeda, and Masayuki Sugawara. Algorithm Design for Gamut Mapping From UHDTV to HDTV. Journal of Display Technology, vol. 12, No. 7, July 2016

Their GMA works in Lab and is hue preserving except for yellow and cyan highlights, where is is lightness preserving with a hue shift.

masaoka

from color.js.

svgeesus avatar svgeesus commented on May 21, 2024

Here is P3 yellow, with LCH Chroma reduced to the neutral axis. The RGB values are linear-light P3. The color wedge shows sRGB values, if in gamut; salmon, if outside sRGB and red if outside P3. Notice the red curve goes up (so, out of gamut) before finally dropping again.

https://drafts.csswg.org/css-color-4/images/lab-yellow-LCH-fade.svg

Here is the same thing but at each stage, I calculate the deltaE2000 between the current color and the color clipped to sRGB. If the deltaE is less than 2, the clipped color is displayed. Notice the red curve hugs the top edge now because clipping to sRGB also means it is inside P3 gamut. Notice how we get an in-gamut color much earlier. Starting Chroma for P3 yellow is 123.27 and we get an in-gamut color by Chroma 103. I did also try with deltaE76 but (in addition to it wildly over estimating the color difference for very saturated colors) it was a bit worse on gamut mapping, giving an in-gamut value at a Chroma of 95.

https://drafts.csswg.org/css-color-4/images/lab-yellow-LCH-clip-fade.svg

(Obligatory sigh that GitHub lamely does not allow SVG images, even though it displays them just fine if they are in a repo)

from color.js.

svgeesus avatar svgeesus commented on May 21, 2024

Improved

from color.js.

svgeesus avatar svgeesus commented on May 21, 2024

So it is better, but I can still get closer by manually tweaking LCH chroma until the deltaE is at minimum

image

image

from color.js.

svgeesus avatar svgeesus commented on May 21, 2024

Although the current algorithm doesn't find the optimal result, a deltaE2000 error of 0.3 is imperceptible. This issue can be closed.

from color.js.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.