What are the LCh and JCh values for the sRGB blue primary?

Hmm, hopefully I’m not speaking too imprecisely here. But usually when people talk about gamut mapping they usually mean somehow shrinking the source color gamut to fit into the destination color space. This requires a destination ICC profile with lookup tables that tell how to map from the destination profile’s source color gamut (which might be an ICC profile, or the color gamut of a specific image, or etc) to the destination color space profile’s actual color gamut. In other words, you really are dealing with several different color gamuts here:

  1. the color gamut of the original image encoded in whatever ICC profile color space.
  2. the color gamut used as the source color gamut of the destination LUT profile - this determines how much “squeezing” is done by the LUT tables.
  3. the color gamut of the destination “LUT” profile.

If the destination ICC profile is a matrix profile, then the “gamut mapping” is just clipping to the hull of the destination color space.

When using xicclu to convert from the ArgyllCMS sRGB.icm profile to XYZ and maybe then to LAB and to LCh, the entire sRGB color gamut fits inside the destination color space by definition. You can do the exact same calculations using a spreadsheet and get the same results. So unless the spreadsheet calculations are also “gamut mapping”, then there really isn’t any gamut mapping.

LCh, JCh deals with color as perceived by the standard observer, that mythical creature that is a stand-in for the rest of us :slight_smile: . So “light” in the sense that the light enters the eye, is processed by the optic nerve and the brain, and ultimately perceived as color.

Shouldn’t you get identical results between relative and absolute intents, if no gamut mapping was actually occurring?

When you make an ICC profile (V2 or V4, not the up and coming iccMAX) from an RGB matrix color space such as sRGB, the illuminant for the ICC profile is D50 regardless of the white point given in the original color space spec:

For the sRGB color space with its D65 white point, this means taking the sRGB color space red, green, and blue xy values as given in the sRGB colorspace specs, converting them to XYZ, and then doing a chromatic adaptation of the XYZ values from D65 to D50, resulting in a new set of XYZ values that define a new ICC profile color space with the D50 white point:

Once you’ve made the sRGB ICC profile from the sRGB color space specs, the original “D65” white point as given in the sRGB color space specs isn’t lost. It’s actually encoded in the ICC profile:

  • In V2 ICC profiles the original D65 sRGB color space white point is encoded in the “white point tag” which is not the same as the D50 illuminant tag.
  • In V4 ICC profiles, the original D65 sRGB color space white point is encoded in the “chad” (chromatic adaptation) tag. The “white point” tag is always the same “D50” XYZ values as are held in the “illuminant” tag.

Quoting from ICC Profile Conversion Intents (there are some issues in this article that need fixing, in case anyone actually looks at it):

When doing an ICC profile conversion between two ICC profiles:

  • “Relative colorimetric, with black point compensation” means align the white points and the black points so the gray axes line up; shorten or lengthen the distance from white to black so the white and black points match"; and clip any colors that fall outside the gamut of the destination color space.
  • “Relative colorimetric, without black point compensation” means the same as above, except don’t shorten or lengthen the distance from white to black.
  • “Absolute colorimetric” means don’t align anything and clip any colors that fall outside the destination color space.

If you are converting between two ICC RGB matrix profiles that have the same source white point, such as between sRGB and AdobeRGB, and also the same black point (which is X=Y=Z=0.0 for the sort of matrix ICC profiles we use as RGB working spaces, including of course sRGB and AdobeRGB), then relative colorimetric conversion with or without black point compensation, and also absolute colorimetric, all give exactly the same result.

In a V2 ICC profile workflow you could experiment with this “aligning/not aligning” of the white points by doing absolute colorimetric conversions between RGB matrix profiles with different source color space white points. Sample results are shown here:

mist-cp-assign-argyll-convert-relative-convert-absolute
In the images above, the actual color of the mist should be gray. I’ll let you consult the article to see why the left image looks yellow and the right image looks blue. The article also explains why you can’t do this sort of experiment using a V4 workflow such as is used by just about all of today’s free/libre image editing applications.

So circling back around to @briend’s actual question, if you use xicclu to convert from sRGB to XYZ, there won’t be any clipping because the XYZ color space is infinite. If you ask for relative colorimetric, you get results using the values that have been chromatically adapted from D65 to the D50 ICC profile illuminant. And if you ask for absolute colorimetric intent, you get results chromatically adapted back to the D65 white point. This is easy to see when converting sRGB “white” to XYZ:

relative:
$ xicclu -ir -px sRGB.icm
1 1 1
1.000000 1.000000 1.000000 [RGB] -> MatrixFwd -> 
0.964203 1.000000 0.824905 [XYZ]

absolute:
$ xicclu -ia -px sRGB.icm
1 1 1
1.000000 1.000000 1.000000 [RGB] -> MatrixFwd -> 
0.950455 1.000000 1.089050 [XYZ]

Changing topics slightly, this page has nice illustrations of the various conversion intents:

http://www.cambridgeincolour.com/tutorials/color-space-conversion.htm

But keep in mind the above page is talking about lookup table ICC profiles (for example printer profiles) which have perceptual intent tables. Matrix ICC profiles such as the sRGB ICC profile don’t have tables. Instead the conversion is done using the matrix made by the Red, Green, and Blue XYZ tags, which is why this sort of matrix-to-XYZ ICC profile conversion is easy to code in a spreadsheet.

Thank for the interesting article! Can all of these transforms that were lost in the old V2 workflow be done manually with libraries such as Colour?

Regarding the gamut mapping. . .I sort of assumed nudging or doing a chromatic adaptation of sRGB Blue might push it out of gamut. It would for illuminant C, for instance. However, I’m (slightly) sure doing the D50 adaptation on sRGB yellow and likely many other colors does in fact move it out of gamut and would require gamut mapping. Here’s the verbose command to adapt sRGB yellow to D50. Does this look correct?

xicclu -ir -px /usr/share/color/argyll/ref/sRGB.icm
1 1 0
1.000000 1.000000 0.000000 [RGB] → MatrixFwd → 0.821152 0.939392 0.110977 [XYZ]

colour.adaptation.chromatic_adaptation_VonKries(colour.sRGB_to_XYZ([1,1,0]),colour.xy_to_XYZ(colour.ILLUMINANTS[‘cie_2_1931’][‘D65’]),colour.xy_to_XYZ(colour.ILLUMINANTS[‘cie_2_1931’][‘D50’]), transform=“Bradford”)
array([ 0.82124442, 0.93937375, 0.11098565])

Good, I get about the same result as xicclu

colour.XYZ_to_sRGB(colour.adaptation.chromatic_adaptation_VonKries(colour.sRGB_to_XYZ([1,1,0]),colour.xy_to_XYZ(colour.ILLUMINANTS[‘cie_2_1931’][‘D65’]),colour.xy_to_XYZ(colour.ILLUMINANTS[‘cie_2_1931’][‘D50’]), transform=“Bradford”))
array([ 1.06810111, 0.9871334 , -0.36921608])

So this color would need to be gamut mapped? Or am I missing the idea that this color would be adapted back from D50 to D65 and thus shifted back to sRGB gamut?

I’m still foggy as to why you would want to adapt and desaturate sRGB Blue from 0,0,1 to [ 0.12575588, 0.05816817, 0.88102249]. This color definitely has a darker and more violet appearance to me. . I suppose it would look like sRGB Blue if my entire computer was using D50 instead of D65? I’m not sure if that’s true either. . . I should be able to check with CAM16?

Y_b = 20.0
L_A = 4.074366543152521
surround = colour.CAM16_VIEWING_CONDITIONS[‘Average’]

First I’ll try to adapt sRGB Blue to D50

adaptedBlue=colour.adaptation.chromatic_adaptation_VonKries(colour.sRGB_to_XYZ([0,0,1]),colour.xy_to_XYZ(colour.ILLUMINANTS[‘cie_2_1931’][‘D65’]),colour.xy_to_XYZ(colour.ILLUMINANTS[‘cie_2_1931’][‘D50’]), transform=“Bradford”)
adaptedBlue
array([ 0.14310034, 0.06062854, 0.71407512])

xicclu -ir /usr/share/color/argyll/ref/sRGB.icm
0 0 1
0.000000 0.000000 1.000000 [RGB] → MatrixFwd → 0.143051 0.060608 0.713928 [XYZ]

Then find a CAM16 spec for adapted blue w/ D50

XYZ_w = colour.xy_to_XYZ(colour.ILLUMINANTS[‘cie_2_1931’][‘D50’]) * 100
colour.XYZ_to_CAM16(adaptedBlue*100, XYZ_w, L_A, Y_b, surround)
CAM16_Specification(J=22.754809907494423, C=86.02568921553214, h=284.13308446701819, s=102.64787546106966, Q=59.022934123382356, M=62.190024123467886, H=326.1718245880528, HC=None)

normal sRGB blue w/ D65:

XYZ_w = colour.xy_to_XYZ(colour.ILLUMINANTS[‘cie_2_1931’][‘D65’]) * 100
colour.XYZ_to_CAM16(colour.sRGB_to_XYZ([0,0,1])*100, XYZ_w, L_A, Y_b, surround)
CAM16_Specification(J=25.068168770723343, C=86.373262825607966, h=282.76419345722189, s=100.40525547820542, Q=61.938259776454906, M=62.441293382597451, H=325.31203447272372, HC=None)

So, does this mean that D50 adapted sRGB Blue viewed in a D50 environment will appear about the same Chroma, but slightly dimmer and with a slight hue shift? Or is this a limitation of the math for the Bradford adaptation? And likewise, if you saw the non-adapted sRGB blue in a D50 environment, it would seem very, very blue:

XYZ_w = colour.xy_to_XYZ(colour.ILLUMINANTS[‘cie_2_1931’][‘D50’]) * 100 colour.XYZ_to_CAM16(colour.sRGB_to_XYZ([0,0,1]) * 100, XYZ_w, L_A, Y_b, surround)
CAM16_Specification(J=25.117896210374159, C=93.575173750949872, h=282.49231574642863, s=104.4452498954545, Q=62.012011664634123, M=67.647726696487283, H=325.14200310562353, HC=None)

Any tips/corrections appreciated.

Clipping the colours (and thus nudging outliers to the gamut boundary) is technically gamut mapping which you can do that with any min & max or median operators readily available in any spreadsheet application.

Yes, the above example images could be generated by just not doing Chromatic Adaptation while changing illuminant.

Made a quick Colab notebook to poke at Argyll a bit, got the same values on all the tests I did: Google Colab

Cheers,

Thomas

Before I read the rest of your post, I want to clarify some terminology:

Let’s say you chromatically adapt the sRGB color space with its D65 white point, to D50, to make a new color space which is the sRGB ICC profile. Now you have two different color spaces.

If you plot the XYZ values for the red, green, and blue primaries for each of these two color spaces on the xy chromaticity plane, you get two different triangeles, largely overlapping, but around the edges there are xy colors in each color space that aren’t in the other color space.

If you plot the volume for each color space in XYZ space, both have the same black point, X=Y=Z=0, but they have different gray axes and different white points. Again, there are colors in each color space that aren’t in the other color space.

Now please note these points because they are important:

  • Chromatic adaptation is not gamut mapping.

  • No colors get squished or clipped or gamut mapped when the sRGB color space is chromatically adapted from D65 to D50 to make the sRGB ICC profile color space.

  • When chromatically adapting all the colors in the sRGB color space with its D65 white point, from D65 to D50, no color is lost or squished or mushed or nudged or any such thing. Every single color in the original sRGB color space gets chromatically adapted to a new color. Except black of course.

You can call the process of chromatically adapting colors from D65 to D50 “mapping” if it makes you happy, because indeed it is a type of mathematical mapping. But it’s not “gamut mapping”. It’s chromatic adaptation.

Asking xicclu to give you the conversion from the sRGB.icm ICC profile color space to XYZ using absolute colorimetric intent is not gamut mapping. It’s chromatic adaptation. Nothing is clipped or nudged to make the resulting color fit inside the (infinitely large) XYZ color space. It’s not gamut mapping at all. It’s just chromatic adaptation.

In light of the above comments, this statement needs to be rewritten to avoid collapsing concepts that really do need to be kept separate:

It will only cause confusion to talk about “nudging” or “gamut mapping” when you are really talking about chromatic adaptation.

It’s not clear from the above quote whether “sRGB Blue” is the blue XYZ value for the original sRGB color space with its D65 white point, or the blue XYZ value that’s in the sRGB ICC profile, that’s been chromatically adapted from D65 to D50. Though given the person who’s making the statement, I’m guessing you mean "sRGB blue in the sRGB color space and not the sRGB ICC profile color space.

“push it out of gamut” requires specifying “which gamut is it pushed out of”. There is the infinite XYZ color gamut, the color gamut of the sRGB color space, and the color gamut of the sRGB ICC profile.

In a very real sense it doesn’t make any sense at all to talk about “pushed out of gamut” as a result of a chromatic adaptation of an entire set of colors from one white point to another white point, because you haven’t “lost” any colors doing the chromatic adaptation. You’ve chromatically adapted all of them.

It will take me some time to work through the rest of your post.

Yes, there are speadsheet functions for doing min, max, median, etc. But I wasn’t referring to doing min or max or median operators available in any spreadsheet application.

I used a spreadsheet to do a chromatic adapation from D65 to D50.

Min, max, median etc are not operations that are used when doing chromatic adaptations from one white point to another white point.

You can download my spreadsheet and check for yourself if you aren’t sure whether I might have somehow “nudged” something by using min, max, median etc in the process of doing the chromatic adaptation:

https://ninedegreesbelow.com/files/spreadsheets/sRGB_specifications_to_ICC_profile.ods

Gamut mapping is not chromatic adaptation, and trying to conflate the two terms into one will only lead to confusion. Yes, chromatic adaptation can also be done in the course of an ICC profile conversion from one color space to another (for example to a printer profile with LUTs) and that might result in additional colors being out of gamut and clipped. But it’s important to keep the “chromatic adaptation” part separate from the “gamut mapping” part when you talk about color space conversions:

“Gamut mapping” refers to how one deals with colors that are in gamut with respect to one color space and out of gamut with respect to another color space, when the goal is to convert the colors from the first space to the second space.

“Chromatic adaptation” refers to chromatically adapting colors from one white point to another white point.

These are two very different concepts accomplished in very different ways for very differnt purposes.

Yes, there are colors in the sRGB D65 color space that are out of gamut with respect to the sRGB ICC profile that’s made by chromatically adapting from D65 to D50 and vice versa. But no colors are clipped, minned, maxed, or medianed in the process of doing the chromatic adaptation. One might say they are “nudged” but that doesn’t say much about the type of nudging, in fact “nudged” totally buries the difference between gamut mapping and chromatic adaptation.

Thank you for the detailed explanations, they did help. I still don’t understand the possible benefit of adapting to D50 when talking about the appearance of colors on a computer. It wasn’t clear from the start that the LCh and JCh values you were using were D50 adapted. When discussing appearance, why would it be important to know the JCh values of a color after it has been adapted to D50 versus the native D65?

I think it is because ICC uses D50, so to get back to your screen, the adaptation must go in reverse. I supposed that might be too simplistic an explanation. I am not as deep into colour as you all are. :slight_smile:

Actually if you check you’ll see that I gave you both “adapted to D50” (relative, “-ir”) and “using D65” (absolute, “-ia”). I tried to indicate every step of the way which I was using, but I guess I didn’t try hard enough :slight_smile:

Hmm, see these two posts over from another thread:

Also see this article, in particular sections A3 and A4:
sRGB luminance: technology, standards, and color science which talks about “why D50”.

and this article, section D1:
Programmer's Guide to XYZ, RGB which has what I hope is an easy to understand “imagine this” that demonstrates what “adapting to the color of the light” actually means.

There is a common thread running through all of this, which is “What color of light are your eyes actually adapted to?”

In ICC profile color management, the assumption is not that your eyes are adapted to D50. The assumption is that your eyes are adapted to the color of white on your monitor in its current state of calibration.

ICC profile color management does indeed send “D50” values from the image to the monitor profile. The monitor profile in turn sends RGB values to the screen that are appropriate to your monitor’s actual state of calibration, if indeed you are using an appropriate monitor ICC profile that actually describes your monitor’s display characteristics in its current state of calibration.

@briend and @KelSolaar - Hopefully tomorrow I’ll have time to go through all of your calculations, which look really interesting. I’d very much like to add colour-science to my current list of “tools for exploring color spaces” and the provided examples are helping quite a lot.

I understand perfectly the difference and I’m not trying to conflate the two terms together.

I was merely referring to the fact that you can do gamut mapping in a spreadsheet, and might have to do if you are doing colourspace conversions.

Same than above, thanks!

I’m border going nuclear here, seriously :slight_smile:

Glad to see we are getting somewhere here!

I think you mis-quoted me out of context, if you re-read my sentence correctly the first word is Clipping, nothing more, nothing less.

Now to make things clear, the only thing I wanted to understand was what conversion path Argyll is taking under the Relative Colorimetric Intent, which I managed to find out as per my Colab Notebook.

Is there a reason for the obsession with ICC D50?

D50 is protocol driven in the ICC PCS system. Everyone understands that under the ICC system, some white point was chosen as the anchor reference. This doesn’t mean there is some magical element to D50. Most displays these days are pretty damn good at delivering proper D65 sRGB / REC.709 primaries and achromatic value.

So again, why the obsession with D50 other than the fact that some CMS system (ICC in this case) chose to rally around it as their reference space “glue” colour? The colours you would be staring at on a decent display in 2018 would be D65 under a V2 system.

It’s a protocol question under the hood. V4 notwithstanding with their awful decisions…

using the code that @KelSolaar posted, both of these (coincidentally) resolve sRGB blue to LCh hue 301:

LChab_D65 = Lab_to_LCHab(XYZ_to_Lab(XYZ_D65, D50))
LChab_D50 = Lab_to_LCHab(XYZ_to_Lab(XYZ_D50, D50))
print(LChab_D65)
[32.302587 148.413874 301.622547]
print(LChab_D50)
[28.459261 135.117122 301.838168]

So, does that mean that xicclu is in fact assuming my eyes are adapted to D50? Whereas with D65 the hue angle is ~306

Here’s an attempt to do reflectance recovery and mixing and compare to normal RGB mixing, so we might consider how blue and yellow might create green, which is the background topic of this entire thread :smiley:

https://gist.github.com/briend/194cd595201f581d6acb2e9280c70fe3

The four gradients are: spectral weighted geometric mean, spectral arithmetic mean, normal RGB weighted geometric mean, and normal RGB arithmetic mean.
Screenshot%20from%202018-08-31%2022-33-58

I think the top two bars looks so odd because the reflectances have many values > 1.0, and also probably because I’m not normalizing the illuminant properly. I would like to tweak the Meng recovery method to constrain to 1.0 as an option, and also allow illuminants besides E. I got a worse result if I adapted my target colors to E before generating the curves for some reason, so you can tell I can’t even reach my original target yellow and blue…

As an example, here’s the gradients I get using Scott Burns’ recovery method, which I much prefer even though @anon11264400 says it’s a horrible hack ;-). The first row is a weighted geometric mean, and the next two blend in increasing amounts of the results of a plain multiply operation. I don’t know if that’s coherent but I was trying to mimic a glazing or layering effect.

1 Like

I don’t understand why you “border going nuclear”. This is a discussion via a forum. I can’t see your face, I can’t stop you in mid sentence and ask you what you really mean. All I can do is try to interpret what you are saying and answer as best i can.

Please look at your post #23 above:

And then at your post #41 above

I’m not the one who brought the term “gamut mapping” into this conversation. I have only been talking about using xicclu to convert from the ArgyllCMS sRGB.icm ICC profile to XYZ. In this conversion there is no “gamut mapping” as is discussed in your provided link in your post #41. There is only a conversion from sRGB.icm to XYZ, either using relative colorimetric intent in which case you get XYZ values for sRGB adapted from D65 to D50, or else using absolute colorimetric intent, in which case you get the XYZ values that you’d get if there hadn’t been a chromatic adaptation from D65 to D50.

Then I referred to using a spreadsheet to do a chromatic adaptation (What are the LCh and JCh values for the sRGB blue primary? - #43 by Elle) and again you brouht up “gamut mapping”:

So my apologies for upsetting you, that wasn’t my intent. But when one person is talking about a chromatic adaptation and and another person repeatedly brings gamut mapping into the conversation, well, it seems like a good time to very carefully lay out the differences between gamut mapping and chromatic adaptation.

Of course you are absolutely correct to say that clipping when using a colorimetric intent to convert from one ICC profile to another, if the converted color falls outside the color gamut of the destination ICC profile, is indeed a form of gamut mapping. But that’s not what happens when using xicclu to convert from sRGB.icm to XYZ. I’m sure you understand all this, and I’m still very confused as to how gamut mapping got dragged into the discussion in the first place.

Unless maybe you were speculating that perhaps for some reason ArgyllCMS was doing some totally unnecessary rearrangement of the XYZ values? As per your following statement?

In which case my apologies for not figuring out why you were talking about gamut mapping. It would never in a million years cross my mind to wonder whether xicclu conversions were somehow tossing in totally pointless “gamut mappings” to distort results from plain and simple chromatic adaptation when asking for relative vs absolute colorimetric intent when doing a conversion from sRGB.icm to XYZ.

I think I stated clearly that I did not know what Argyll was doing under the hood and thus that gamut mapping could be a cause for the discrepancies between Argyll and Colour.

Why? Well…

You should not assume that everybody has the same knowledge about ICC than you. As an example, I did not assume you know about Python or Colour.

D50 is the graphics arts standard measurement conditions.

ICC adopted it for their PCS (Profile Connection Space) because the most common workflows assume complete observer adaption to white. i.e. Almost all the time people use Relative Colorimetric, Perceptual or Saturation intents. Absolute Colorimetric intent is typically only uses in special situations, such as side by side proofing, or soft proofing.

I fully get that. ICCs were largely designed around display referred print graphic work.

With that said, having D50 in the reference doesn’t imply that the input and output achromatic points are D50, hence my original comment; it is obessive to conflate the idea that the reference white being D50 means every single instance of white needs to be considered around D50. Doubly so when discussing modern perceptually uniform colour model implementations, many of which use D65.

Lab I believe was canonized around Illuminant C if I am not mistaken.

It just seems that too much of the discussion returns to D50.