Colour Calibration (channel mixer question)

Hello,
I read in the documentation on the colour calibration module that in bypass mode, the R,G and B tabs act like a channel mixer with a matrix multiplication.

┌ R_out ┐ ┌ Rr Rg Rb ┐ ┌ R_in ┐
│ G_out │ = │ Gr Gg Gb │ X │ G_in │
└ B_out ┘ └ Br Bg Bb ┘ └ B_in ┘

I wanted to experiment changing a purple into green . With 9 variables and 3 equations, there are many possible 3x3 matrices that will do the job. I wanted to change the colour (152,155,159) into (69,203,129) so I just took the matrix

┌ 69/152 0 0 ┐
│ 203/152 0 0 │
└ 129/152 0 0 ┘

I understand that I am using output values taken with the colour picker instead of the values from the working space but the behaviour of the module surprised me.

Then I just checked if by entering 0.33 in the columns of red and 0 everywhere else would turn my red patch into grey. Nope !

Am I getting my maths wrong, putting the coefficients in the wrong place or is this channel mixer not just a matrix multiplication ?

Thanks for any help,
Nicolas.

When the three sliders in any given channel do not equal 1, you create a cast. So in this instance, you have created a red cast because your red channel = 2.639!

Edit: Are you able to upload the image so we can play with it ourselves?

Yes, the original image is an .exr made in krita. (overkill I know)
https://drive.google.com/drive/folders/1ShSxx2MpaJxqI7Tvpa8GKJOcOEyQipZI?usp=sharing

If I put 1/3 in the first column (the sum is 1) and zero everywhere else, I don’t get the red patch turning to grey.

I’m wondering if the sum of each column must be 1, whether there is a solution to the original problem.

Thanks.

You could use a mask so the channel mixer effects only the purple patch (which by the way is 152,155,199 - not 159) and leaves the rest alone. That way you don’t need to worry about having sum = 1.

Thanks but the point is to understand the channel mixer and for the moment there is something that escapes me.
The grey problem is the first one I’d like to have an answer to now.
I tried entering
linsolve([152a11+155a12+199a13=69,152a21+155a22+199a23=203,152a31+155a32+199a33=129,a11+a21+a31=1,a12+a22+a32=1,a13+a23+a33=1],[a11,a12,a13,a21,a22,a23,a31,a32,a33])

in Xcas and got no solution.

Sorry I can’t help you with matrix math - not something I’ve done much of. Hopefully someone can chime in on that. For me, I can give example of a very close match to the target colour that also retains neutrals, but as you see, colour of the other circles shift - the only way I know to avoid that is to mask.


melangeur_canaux.exr.xmp (4.8 KB)

Load the xmp into darktable to see color calibration settings. This was achieved by the unscientific trial and error method, knowing reducing the B value (199<129) would mostly be achieved in the B tab, increasing G value (155>203) would mostly be achieved in G tab, and decreasing R value (152>69) would mostly be achieved in R tab. I hope you can get a more scientific answer, I too am interested.

Thanks, I’ll give it a look. I’m not bothered about what happens to the rest of the photo apart from observing the shift in the red, green and blue primaries underneath.

If you set them all to .3 you will just get a darker version of you image. You have not changed much just reduced the r g and b values of all colors to 1/3 of what they were so the ratio and hence the colors don’t really change you have just darkened your image…is that what you were asking??

You are just outputting to the red channel. Hence the red output.

No, if i multiply

┌ 1/3  0  0 ┐       ┌ 255┐
│ 1/3  0   0 │   X  │ 0  │
 └ 1/3 0  0┘        └ 0. ┘

The result is 

┌ 85┐    
│ 85│  
└ 85┘   

So the red turns to dark gray.

Just to check, which version of Darktable are you using? There was a bug in RGB channel mixing that was fixed in Darktable 3.4.1.

I’m using 3.4.1 on Mac

Had a closer look at your screenshots - you’re entering the coefficients in the wrong place. Think of it this way: in the R tab you see the coefficients which are multiplied by input red, green and blue to form the output red. In the case of your matrix, you would have to enter the nonzero coefficients in the first slider of the R, G and B tabs and zero out the others.

Edit: i.e. each R, G, B tab defines one row of the matrix even though the positioning of the sliders makes it look like a column.

and

However I have found this not to be true. For instance, with the above image provided by Nicolas, turn on color calibration, make sure gamut compression is 0, negative values are unticked and adaptation is none (bypass) in cat, then in R tab, reduce R slider from 1 > 0.5.

We see our purple patch has changed from 152,155,199 to 56,159,200. Sure, changes in G and B channels are minimal, but nonetheless, all three channels have changed. Now increase G slider in G tab to 1.5. Values become 8,199,197. In this case, we have not just a dramatic change in G channel as expected, but R channel also.

There are a couple of reasons you might observe this:

  • is the color picker working in the same RGB space as the pipeline? Normally it uses the histogram colourspace, which may be set to something different to the pipeline. Then, transforming to a different set of basis vectors will cause the values to shift
  • are there any modules active after color calibration, such as base curve or filmic? These modules again can cause values to shift as they do their job.

I have histogram profile set to export profile, in this case sRGB. If I change histogram profile to working profile, I still get a shift in both R and G channel when shifting G slider in G tab. If I change histogram profile and output profile and export profile all to working profile, in this case linear rec 2020, there are still shifts in both R and G channel, although much less pronounced.

There are no other modules between color calibration and output profile.

@nwinspeare: I’m not a darktable expert, but I think your matrix is transposed, as @flannelhead says. According to your screenshot, you have set the output red channel to various factors of the input channel. Assuming your other multipliers are zero, then you have set this matrix:

┌ 69/152 203/152 129/152 ┐
│   0       0       0    │
└   0       0       0    ┘

If you want a gray output, then the values your set in the “R” tab can be different to each other, but you should set identical channels in the “R”, “G” and “B” tabs.

Its a fair observation there is certainly cross talk so maybe this module doesn’t work like a classic display referred channel mixer. Also if you say drag the red channel in the red input or any other similar far enough down things go black even though in this case the image should still have blue and green so to me it doesn’t behave as a normal standard channel mixer…

Yes, I opened an issue in GitHub recently about color calibration returning black, which I guess is the same thing you’re seeing. (Edit: Link here: Color Calibration Channel Mixer produces black patch · Issue #9076 · darktable-org/darktable · GitHub) My understanding from that discussion is if you push normal channel mixers into negative xy values they’ll return a blob of saturated colour at the gamut border, whereas the colour calibration channel mixer clips to black. This is by design, so it is up to the user not to push things so far.

Edit: Although why in some instances turning down R slider in R channel leads to the whole image going black, instead of just the R channel, is beyond me. It’s also a weird phenomenon that turning down the channel slider (Eg. R in R, G in G) will see that channel approach 0 (RGB value), until you hit 0 slider value. Once you go negative slider value, that channel value starts increasing again, before the sudden black. This doesn’t happen with the old channel mixer. There, once you go into negative values on the slider, the RGB value just stays the same.

I wonder if it is something about the scene referred workflow. I’ve noticed also when blending in a single channel - for instance R - that if you take that individual channel down to 0, then the module has absolutely no effect, when you would expect it to still have an effect on both G and B channels. I don’t know if that is a related issue, or a different one.