Matrix multiplication

Hopefully a simple question,

How can I take two matrices from Bruce Lindbloom site and combine them.

http://www.brucelindbloom.com/index.html?ColorCalculator.html

For example if I have a forward matrix from an image to XYZ of

0.7446,0.2074,0.0134
0.2772,0.9656,-0.2429
0.0269,-0.243,1.0402

and I have the matrix from XYZ to sRGB with an illuminant of:

3.1338561 -1.6168667 -0.4906146
-0.9787684 1.9161415 0.0334540
0.0719453 -0.2289914 1.4052427

so that I get a single matrix?

Are you asking how to multiply matrices, or about the whole operation of converting?

With G’MIC multiplying those two together because A * B * C = A * (B * C):

gmic run "(0.7446,0.2074,0.0134;0.2772,0.9656,-0.2429;0.0269,-0.243,1.0402) (3.1338561,-1.6168667,-0.4906146;-0.9787684,1.9161415,0.0334540;0.0719453,-0.2289914,1.4052427) mmul +invert"

Gives the following forward:

2.13144,-0.80958,-0.339543
-0.0938694,1.45765,-0.445029
0.396979,-0.747313,1.44041

And reverse:

0.444812,0.35742,0.215283
-0.0104358,0.806768,0.246799
-0.128005,0.320062,0.762961

The reverse is possible assuming those first two are invertible, due to (BC)⁻Âč = C⁻ÂčB⁻Âč

2 Likes

Thanks

I can can’t get that command to work with GMIC I have 1.7.9.

In any case I get very different results than I was expecting, should I not be multiple the second matrix against the first?

Regarding doing matrix multiplication, it’s associative so you can multiply (A* B) * C or A * (B * C) and the result is the same either way. But not any three random matrices can be multiplied. If you plan on doing much matrix math, it’s worth doing a bit of reading, maybe starting with Wikipedia, but there are wonderful websites that will walk you through all the basics, if you do a little searching on the internet.

https://en.wikipedia.org/wiki/Matrix_multiplication

I’ve never used g’mic for doing matrix math, but here are two other options iIf all you want to do is multiply a few matrices together and calculate a few inverses:

  1. I really like this website:

    http://www.bluebit.gr/matrix-calculator/

  2. Also you can do matrix math using openoffice or libreoffice. Neither is fun to use, setting up the specific matrix math is fiddly. This article has a downloadable spreadsheet that is set up to calculate the sRGB D50-adapted ICC profile from the sRGB color space specs, and so has examples of using a spreadsheet for matrix math, including doing Bradford chromatic adaptation:

    From sRGB color space to sRGB profile: how to calculate the ICC sRGB profile primaries from the sRGB color space specifications:
    https://ninedegreesbelow.com/photography/srgb-color-space-to-profile.html

Regarding Bruce Lindbloom’s equations, as far as I can tell they are first rate, never had any reason to doubt their accuracy.

Regarding Lindbloom’s pre-calculated adaptation matrices and his XYZ values for D50-adapted sRGB ICC profile and similar adapted profiles, he uses different D65 and D50 white point values than the sRGB color space specs D65 values and the ICC profile specification D50 values.

So of course Lindbloom’s calculated values aren’t the same as you’d expect if you used the values actually in the various relevant specifications. More information is here:

Survey of Free and Open Source ICC RGB Working Space Profiles:
https://ninedegreesbelow.com/photography/linux-icc-profiles.html#variants

Sadly some profile vendors seem to feel free to just make up whatever D65 and D50 values they want, leading to a plethora of profile variants for what are suppose to be “the same” profiles. If you really want the correct values “by the specs” values for RGB to XYZ for sRGB profiles, use the matrix that you can make from my sRGB profiles’ XYZ RGB channel values, or else look at ArgyllCMS sRGB.icm channel values.

But keep in mind the XYZ channel values for my profiles and for ArgyllCMS profiles have been modified to make well-behaved profiles - the difference between pure calculations and what’s needed to make a well-behaved ICC profile are small:

In Quest of Well Behaved Working Spaces:
https://ninedegreesbelow.com/photography/well-behaved-profiles-quest.html

1 Like

But its not communitcative if I am using the correct term.

ie. AB does not equal BA,

To get the correct result or at least the result I expect, you need to do B*A, or

XYZ → sRGB times Camera–> XYZ.

The result I was expecting was BTW:
1.872 -0.792 -0.076
-0.197 1.639 -0.444
0.028 -0.548 1.518

No, it’s not communicative.

I’m not an expert at doing matrix math, but it really helps if you work through some simple examples to get an idea of what’s going on, and check your results using the bluebit website.

I just wish I had some handy link to the tutorials I followed a long time ago, Anyone else have some good links to “get started” matrix math tutorials?

The downloadable spreadsheet I referred to has pretty good annotations. I’ve used it as a template for doing other sorts of matrix math related to color space calculations, using other color spaces, even as a basis for setting up RGB to XYZ to LAB and such. But honestly I have no interest at all in plugging in numbers for someone else or checking their math :slight_smile: . Even thinking about doing matrix math gives me a headache!

The matrix multiplication site you gave works perfectly I get the result that I was expecting.

Which is to multiple the last matrix by the first.

XYZ → sRGB times Camera–> XYZ.

The result I was expecting was BTW:
1.872 -0.792 -0.076
-0.197 1.639 -0.444
0.028 -0.548 1.518

I have a follow up question if my destination is sRGB, what should its white point be? I had expected it to be D65 but the Rawtherepee code has it is as D50 and also an example I am following is the same. i.e. what is the white point for the viewing environment?

Maybe commutative?

1 Like

Oh, blush! yes, that’s the right word. Not communicative like I wrote and not comminitcative as @LaurenceLumi wrote.

D50 for ICC profile calculations. For viewing environment, unclear what you mean - the lighting in the room? the color temperature of the monitor white point?

I usually struggle with concatenation. Even typing it now, I got it wrong. :slight_smile:

In a regular file without an ICC profile, say as example a jpg encoded as sRGB, what is the white point assumed to be? I had guessed D65, but looking at the RT code it suggests D50. The spec seems to suggest D50 as the viewing environment but I got confused


ICC generally uses D50 for various reasons (that some people might debate). As long as your app and / or OS has some colour management and can handle ICC profiles properly, it is not a concern.

As for the gmic command, perhaps you are using a version a little too antiquated. Update to a newer version and try again.

On the ICC web page for ICCMax, they cite the D50 illuminant as “fixed” for V4, “to ensure interoperability and prevent ambiguity in colour transforms”. Now, I have both D50 and D65 (owing mainly to dcraw conventions) ICC profiles in my profile “zoo”, and the LittleCMS library seems to handle the chromatic transition nominally.

1.7.9 is antique in gmic terms :slight_smile:. There have been lots of improvements since, the one you’re missing there is “run” which avoids many shell escaping headaches.

As stated already multiply the two in the same order you would use them individually (I had no idea you pasted in reverse of usage, sorry). In gmic you can reverse them with a simple “rv” at the right point - quicker than reorganising the numbers:

gmic run "(0.7446,0.2074,0.0134;0.2772,0.9656,-0.2429;0.0269,-0.243,1.0402) (3.1338561,-1.6168667,-0.4906146;-0.9787684,1.9161415,0.0334540;0.0719453,-0.2289914,1.4052427) rv mmul +invert"

then output is:

(1.87208,-0.792065,-0.0756067;-0.196737,1.6391,-0.443747;0.0278951,-0.547667,1.51832)

In floating point space a * (b * c) not necessarily gives the same result as (a * b) * c

Could you give an example of what you mean?

If you are talking about rounding errors from floating point math, that’s very important to keep in mind and can produce catastrophically different results given appropriately chosen input values. But I think issues with floating point calculations isn’t exactly germane to the current discussion - yes? no? I mean unless one were unfortunate enough to start with the wrong input values!

Simple example:

    float f1 = 1e38;
    float f2 = 10;
    float f3 = 0.1;
    
    std::cout << f1 << " * " << f2 << " * " << f3 << " results in  : " << (f1 * f2) * f3 << " or " << f1 * (f2 * f3) << std::endl;

(f1 * f2) * f3 = inf

f1 * (f2 * f3) = 1e+038

1 Like

Yes but what about a file that does not have a colour profile and is using the default sRGB values, what is the correct viewing environment expected to be D50 or D65?

For example when RT reads a plain TIff and assumes the values are sRGB what value for illuminant is assumed?

Is that the case?

The example I am working through which is here BTW http://www.strollswithmydog.com/determining-forward-color-matrix/

in order to get the correct result it has the last matrix that would be applied last as the first one in matrix multiplication, (if I am to get the same result as the example).

1 Like