Matrix multiplication

Perhaps the other reason, is that many people myself included probably expect a color managed file with the correct sRGB profile applied to look the same a plain file with assumed sRGB values to look identical?

Hi,

I haven’t checked the link, so I’m not exactly sure of what you are trying to
do, but here’s my understanding of your problem (if I got it wrong, sorry).

You have a column vector rgb (i.e. a “colour”) that you want to convert to another one RGB in a different space. You can do that by “applying” two matrices M1 and M2, and you would like to see whether you can do it by just using one matrix M. Did I get it right?

Then, you have this:

xyz = M1 . rgb

RGB = M2 . xyz

substituting for xyz in the 2nd equation:

RGB = M2 . (M1 . rgb)

Knowing that matrix multiplication is associative (forgetting about what @heckflosse wrote about floating-point operations, it is definitely true but I think it can be left out of the conversation here), you get:

RGB = (M2 . M1) . rgb

Therefore, M = M2 . M1, i.e. you would multiply “in reverse”. Does that make sense?

2 Likes

Could you give an explicit example of the problem you are talking about, perhaps with screenshots? You mentioned RawTherapee a couple of different times - is there something RawTherapee is doing with sRGB images with and without embedded sRGB profiles, that somehow seems unexpected?

Spot on!

Yes that is very helpful! and is exactly in agreement with several examples I have.

I am using the RT code as reference, for what I am trying to do. Ideally I would like to incorporate my work into at RT some point!

Specifically I am trying to create a matrix that will take color values that I have computed from density readings of a film scan, that should be in a particular colorspace. Lets call that colorspace RA4 space. (i.e. the colorspace that is created by using the CMY dyes in a RA4 processed color print)

I then want to transform that data to sRGB correctly. At least that is what I want to do initially…

That’s why I want understand how to do it properly! Once I have got the method correct I may do things slightly differently. But my goal initially is to do it correctly.

I can make up some examples using generated solid colors, and compare the results that I get from RT.

I’m totally confused as to how your inquiries regarding viewing conditions is related to "Perhaps the other reason . . . " as quoted above.

There are many web browsers that fail this test of “sRGB image looks the same with and without an embedded sRGB ICC profile” - are you talking about something you see in a web browser?

Perhaps a step back is order.

What I am trying to should be straight forward in that I want use the exact same methods that are used in digital photography and some extent even more so those used in RT. (which I hope are same etc…) The only difference is my values “camera” to XYZ are unique.

This involves a lot of trial and error, trying different things, and each time I try something I like to understand the process, the values used etc.

I understand this because the software simply ignores the values. But in the case of software that processes ICC profiles correctly what should happen?

Perhaps I can ask the question in different way. Let take two tiff files. File A has the correct sRGB value attached with D50. and File B which has the exact same data inside but no profile.

When the same file is displayed in RT should they appear the same or different? Or what color values does the internals or RT thinks it has?

Hmm, I thought I already answered this question above :slight_smile: . The files should look the same assuming the software assigns sRGB to images without embedded ICC profiles, which I’m sure RT does, leastways I can’t see any change in how a sample image looks before and after assigning an sRGB profile to an image with no embedded ICC profile. Do you see a visual difference?

I’m not sure what you mean by “ignores” but the problem is that those web browsers are flawed :slight_smile: . They should all by default assign sRGB to images without embedded ICC profiles, and then convert to the monitor profile.

No, hence my point that when no profile is applied RT assumes it sRGB at D50, and I assume so does many other applications. If it assumed the file without the profile was D65 it should apply an adjustment and the result should look different to the one with D50 profile?

Putting aside applications that don’t do things correctly I am looking to understand what the correct behaviour should be. Does that make my question clear?

If a V2 or V4 ICC profile color-managed editing application assumed an image without an embedded ICC profile was somehow “D65” and then tried to apply an adjustment to somehow compensate for the difference between D65 and D50, it would be a very confused ICC profile color-managed editing application.

If I were using software that behaved in this fashion, I’d file a bug report.

Very sorry @LaurenceLumi, the confusion was all mine. @agriggio explains it perfectly. Of course it’s not A * B * C because the input pixel is a vector, not a 3x3 matrix therefore needs to be on the rhs of each multiply! Incidentally, gmic has the mix_channels command for that. I think I’ll keep quiet now :slight_smile:

1 Like

I can’t help but think that I’m somehow missing the question that you are actually asking. An sRGB ICC profile already has the “D65” source white point incorporated into the profile by means of the chromatic adaptation that was used to make the sRGB ICC profile from the sRGB color space specs. It doesn’t have to be added again, in the context of using ICC profile color management.

I tried an experiment once, modifying LCMS to use D65 as the illuminant, instead of D50. I installed the modified LCMS in /usr (this is on Linux) so all ICC profile applications used this modified LCMS. And I made a set of ICC profiles that used D65 as the illuminant. With this modified LCMS, when making ICC profiles from color space specs, D65 color spaces didn’t need to be chromatically adapted to D50. But D50 color spaces such as ProPhotoRGB did need to be chromatically adapted to D65. And of course “E”, D60, and etc color spaces still needed to be chromatically adapted, but to D65 instead of D50.

When I tried editing using this modified LCMS and the modified profiles with my editing software such as GIMP, all the colors looked exactly the same. Exactly the same. The only way I could get “different colors” was to:

  • Use my “D50 illuminant” ICC profiles with my modified-to-use-D65 version of LCMS
  • Or else use my “D65” version of LCMS with my normal D50-adapted ICC profiles: Edit: What I meant to say, should have said, was “Use the D65-illuminant profiles with normal non-modified D50-illuminant LCMS”.

Sometimes you might run across an incorrectly-made sRGB ICC profile where the chromatic adaptation from D65 to D50 wasn’t done. Using such a profile makes images look blue, such as the image below on the right (the colors on the left are correct):

Back in the days of V2 workflows, you could “get different colors” - either blue or yellow or even other colors depending on your monitor’s actual white point, by using Absolute colorimetric rendering intent to the monitor.

You could also get different colors when converting from one ICC RGB working space to another ICC RGB working space with a different white point, but you had to specifically ask for Absolute colorimetric intent - all the editing software I’ve ever seen defaults to Perceptual or Relative, so nobody was likely to do this accidentally.

For example, you might convert from from sRGB to BetaRGB (which has a D50 white point) or vice versa, using Absolute colorimetric intent, resulting in images such as are shown below. Notice the image on the right is “too yellow” and the image on the left is “too blue”:

But the ICC decided this sort of color change when using Absolute colorimetric was confusing to users.

So for V4 workflows, when the source and destination color spaces are both “monitor class” profiles (all the standard RGB working spaces we use in the digital darkroom are “monitor class” profiles), when you ask for Absolute colorimetric rendering intent, what you get is Relative. Which makes it decidedly more difficult to write tutorials that encourage users to experiment and thus learn for themselves first-hand the difference between relative and absolute colorimetric intents :frowning:

The images above come from my article on “Will the real sRGB profile please stand up”, which was written when I actually had access to V2 editing software: https://ninedegreesbelow.com/photography/srgb-profile-comparison.html

1 Like

Specifically if I am creating data to store in a file that does not have ICC profile attached what parameters should I use?, and what parameters should I use if use a ICC profile with the correct primaries, and D50 white point etc ? Initially I though I should use the sRGB primaries and D65 for the former and D50 for the later.

But that does not seem to fit what the software I am using as example does. It seems rightly or wrongly that if you want the software to work as expected you need to create data in the former (the file without the ICC profile) with a D50 white point. As the software will NOT make any chromatic adaptation.

Hmm, well, the only answer anyone will ever be able to give you is that for V2 and V4 ICC profile applications, use the D50 adapted matrix for sRGB. Whether the profile is actually embedded in the image or not is irrelevant. I’ve tried to give reasons why several times in this thread, but as I said, I’m not hitting the area that answers your questions, and at this point I somewhat doubt my ability to do so :slight_smile: .

If you don’t want to use a D50-adapted matrix, wait until someone adds iccMAX support to an ICC profile color managed editing application, in which scenario I don’t have much of a clue what will happen or be possible. But don’t try to mix whatever you do using iccMAX applications with what you do using V2/V4 applications.

Or else don’t use ICC profile color management at all, and instead use OCIO color management, which requires using OCIO LUTS to get from whatever color space the image is in, to whatever color space you want the image to be in. But I’m not the person to advise you on the specifics of OCIO, if that’s the direction you want to go. If you do a search on the forum, there are already some threads on the topic.

Here is a thought: Go ahead and try whatever it is that you think should be done, as you generate the matrices for whatever application you have in mind. And if it works, great! Experimenting with doing whatever you think should work is a great way to learn what does work. In general trying stuff and seeing what happens, and then figuring out why really is a nice way to learn stuff.

Bear-of-little-brain here, methinks that 1) if you’re going to put primaries and whitepoint information in an image file, it should represent the color gamut to which the data was last converted, and 2) if you’re not going to put that information, you need to ensure the color gamut of the data can be used as-is by whatever media the data is intended for.

You can combine #1 and #2 for the largely unmanaged wild of the web by converting and storing sRGB/D50 (D50 mainly because the ICC tells people that’s their notion of reference whitepoint) and pray someone’s not going to regard your image on a cheap projector, ask me how I know…

I think the primary consideration is to ensure the metadata properly represents the image characteristics, and in its absence you need to have particular media in mind.

I think what you’re missing from Elle’s responses is that there are multiple ‘white points’ that are used in different ways, at different stages within the calculations used to generate the matrix used to convert between colorspaces. Specifically, the keyword you should look at more closely is ‘adapted’.

Disclaimer: I’m not an expert on the standards, I’ve just struggled with the math and figured this out after reading way too much documentation that was way too vague. I might still be misunderstanding a lot of this, so I would honestly like some feedback from experts like Elle.

So, consider for a moment that we consider ‘white’ to be [1, 1, 1] no matter what RGB colorspace we’re in. This doesn’t specify a whitepoint per se - no, we specify a white point in terms of the XYZ colorspace. For example, while sRGB’s white point has xy coordinates [0.3127, 0.3290], that still is just saying that the exact ‘color’ for [1, 1, 1] (or ‘white’) can be measured externally as having those xy coordinates.

ICC profiles use what’s called a ‘Profile Connection Space’ (PCS). What this is will vary, but most of the time it’s either XYZ or L*a*b* - and for ICC profiles (I guess versions 2 and 4), the white point that they use for the PCS isn’t E, but instead D50 - which is roughly equal to XYZ values [0.964, 1.000, 0.825]. This means that, to stay consistent, we have to transform whatever ‘white’ is to XYZ values such that ‘pure white’ is [0.964, 1.000, 0.825], rather than [1, 1, 1] (or, if we were using D65, roughly [0.950, 1.000, 1.089]).

However, because of how human eyes work, you can’t just rescale XYZ values directly to convert between white points. Instead, you have to convert XYZ values into LMS (native colorspace for the human eye), rescale those values, then convert back into XYZ.

There is some debate about what the best matrix to use is for converting between XYZ and LMS, and it often depends on your use case, needs, and specific setup. However, the most common when dealing with ICC profiles is the original ‘Bradford’ color transformation matrix. I specify ‘original’ because apparently there are two versions, and ICC profiles explicitly use the original one.

So, here’s an overview of how this looks:
Linear sRGB→XYZ→LMS→D50/D65→LMS→XYZ (PCS)

And going to another RGB space (for this example, to be displayed on a monitor with a D75 white point):
XYZ (PCS)→LMS→D75/D50→LMS→XYZ→RGB

It’s important to note that in both RGB colorspaces (both sRGB and the monitor’s colorspace), the RGB value for ‘white’ remains [1, 1, 1]. If the picture is a photo of a white piece of paper with a drawing on it, any part that shows the paper will have the same RGB value in both RGB colorspaces (assuming that it’s perfectly encoded as white and not slightly off-color, nor darkened to a light gray).

That’s why one of Elle’s comments carefully noted that the ICC specs assume that your eyes are 100% adapted to the white point of your display - because they’re designed to make sure that the display’s white point is always used for the actual value of white.

Now, for the math:

  1. orig = Original RGB value.
  2. final = Final resulting RGB value.
  3. toXyz = RGB to XYZ matrix for the initial (or ‘source’) RGB colorspace. Uses whatever that colorspace’s actual white point is, such as D65.
  4. toRgb = XYZ to RGB matrix for the final (or ‘destination’) RGB colorspace. Uses whatever that colorspace’s actual white point is, such as D75.
  5. whiteSource = Source RGB colorspace’s white point.
  6. whiteDest = Destination RGB colorspace’s white point.
  7. toLms = XYZ to LMS matrix, such as the Bradford or Hunt matrices.
  8. diag() = Function to turn a 3-element vector into a diagonal matrix.

final = toRgb * (toLms^-1) * diag((toLms*whiteDest)/(toLms*D50)) * toLms *
(toLms^-1) * diag((toLms*D50)/(toLms*whiteSource)) * toLms * toXyz * orig

I noticed that the built-in editor had decided to line-break right at the point where colors would be in the PCS (at the time I hadn’t put spaces around the asterisks), so I decided to put an actual line break in there. I put the spaces around most of the asterisks to help show where each colorspace conversion takes place. Decided not to with the ones inside ‘diag()’, to better group those together as a single ‘conversion’.

Hope this helps! While I did find this thread while googling for how to do matrix multiplication in gmic, I saw what looked like a very recent thread from someone going through some of the same issues I did.


Now, the reason I had gotten so confused while learning all this, was because I was wanting to figure this all out so that I could specifically use absolute colorimetric conversions between colorspaces; I didn’t want to use white point adaptation. Specifically, I wanted to make one image look identical on several different monitors, and make that look identical to the original object in real life. I had all displays in the same room as the object, too.

But I had in my head the idea that ‘white balance’ was meant to help adjust colors to be more or less white, going bluish or orangeish based on color temperature. So I kept trying to use white point adaptation to do the opposite of what it was intended to do, and since none of the documentation I could find was geared toward that, it was kinda frustrating!

Had to take a step back and figure out what it did first, in the context in which it was being used - and after I figured that out it was much easier to ‘undo’ the whitepoint adaptation.

Except then I learned that my phone’s camera was doing it all wrong and was assuming D50 was the actual white point for the display. Figuring out why certain shades of green lacked that slight tint of blue while everything else looked spot on was ‘fun’, alright.

… Actually it kinda was. And the whole project was just for fun anyway; can’t seem to get a job, so may as well mess around with colorspaces instead!

1 Like

Not really, if something is the same, then it is the same, if something is different then it is different!

This is not meant as criticism of Elle, who has been very helpful!

At the end of the day my question is very simple and can be summarised as: If I have some data that is in the sRGB colorspace what are the parameters used to describe that data? and in addition are those parameters any different from that I would find in sRGB ICC profile.

In seems at least as a defacto standard the answer to the later part of that question is that there is no difference. Now perhaps that was not intended, maybe its even a mistake… but otherwise users would likely complain if they attached an sRGB ICC profile to sRGB data and the result looked different!

Elle, I think you should have point me to this page… :slight_smile:

What I did not get before, is the values of the primaries in the an ICC profile have (or SHOULD have) been chromatically adapted from there absolute values. This was not intuitive but I get it now.

So in summary the sRGB data that uses the unadapted SRGB primaries plus the D65 white point should equal (or be close enough) to same data that is defined using correctly adapted primaries and the D50 white point?

1 Like

Hi @LaurenceLumi - hmm, well, I actually did mention that article, back in Comment 4 :slight_smile: , where I gave a link to an article that has a downloadable spreadsheet for calculating the sRGB ICC profile from the ICC specs and the sRGB color space specs. But I’m really glad you found that article helpful - it was a ton of work to write! - but I learned a lot while writing it.

@Tynach - I really like all the experimenting you’ve been doing with various displays. That sort of stuff is the 100% best way to actually learn how ICC profile color management really works. Otherwise the constant temptation is to make a lot of unconscious assumptions, that seem inevitably to end up being not correct just when you really want something to work “as expected”.

It always makes me a bit nervous when people refer to me as an expert :slight_smile: because everything I know about ICC profile color management was learned the hard way, one experiment at a time just like you are doing, followed by trying to figure out “why” results are as they are, whether by doing further testing or doing a lot of background reading or asking questions on forums and mailing lists, or whatever it takes. So whatever expertise I have is relative to the stuff I’ve tried to figure out. I don’t have any formal university degree in color management or anything like that.

Anyway, I do have some thoughts on your descriptions and comments for your wonderful monitor experiments, but I need to clear off some other “to dos” my list before sitting down to type something up.

1 Like

I should probably mention that this is all done with GLSL code, on Shadertoy and in the Android app ‘Shader Editor’. I’ve looked at ICC profiles and compared different ones to each other, but I’ve yet to write any code that actually uses any such profile.

It’s one of those things I feel I should do, but a large part of what I’m doing right now is on my phone in Shader Editor (where I have to ‘calibrate’ the display by having a massive array containing the equivalent to a VCGT tag, multiply all color values by 255, and use that as the array index for nabbing the final value for that channel).

Same, it’s happened a few times with me… And here I am unemployed because nobody wants to hire someone without actual job experience. Often I’ll post something that really makes sense to me and seems completely true, but I’ll still get the feeling that it might only seem true to me because I “don’t live in the real world.” And that’s often the sort of thing (though in more detail and with examples) told to me when I give opinions on topics like tab indentation, so I have a feeling they might be right.

What I more or less meant by ‘expert’ in my own post, however, was that you’re someone who has done that testing before - and thus you have built up a fairly decently sized repository of knowledge, at least when compared to others. I hesitate to say ‘professional’ because I honestly don’t know what your actual job consists of, but given the number of articles you’ve written (and both the depth and breadth of the topics in them), I think it’s safe to say you’re an expert - at least relatively.

I should have joined this community much sooner, but I didn’t really know about it. Besides that, it was only very recently that I broke down and finally just bought myself a colorimeter, as before that I was making a lot more assumptions about the quality of my own equipment (factory-calibrated monitors are, apparently, often very badly calibrated).

Mostly so far I’ve just been posting test code on Shadertoy, and occasionally asking for things like ‘where can I find copies of various official standards?’ on Reddit… Where I didn’t get any really useful leads; the subreddit I saw over there was I think /r/colorists, and 90% of the content is people saying things like, “In this program, always set these settings to those values when doing that.”

So Wikipedia has still been my number one source for things like what chromaticity coordinates belong to the primaries of which standards, and I’ve not really had anywhere to go for asking for feedback on the actual algorithms.

As for responding later, that’s no problem! I figure that’s what forum-like websites are for - group conversations that could take anywhere from minutes to weeks between responses. Wouldn’t want to rush you :smiling_face:

At any rate, uh… I sorta split up when I wrote this comment, part of it in the morning and part of it in the evening. I’m not really sure where I was going with some of it or if I intended to modify/add to/remove from earlier parts, so I’m sorry if it’s a little bit of a rambling mess. I’ll just post it as-is for now, as I’m not sure what else to do with it.