Introducing a new color balance mode in darktable

Following up my previous post, where I introduced my new log profile correction, I present to you another mode for color-grading in darktable : the ASC CDL (

Triying to correct the picture showed in, I had a hard time with the current lift/gamma/gain module, which works in gamma-corrected sRGB mode and is difficult to work with, and shows over-saturation in shadows:


The new module follow the American Society of Cinematographers Color Decision List standard and works inlinear (= non gamma-corrected) ProPhoto RGB space:


In these 2 examples, I tried to match as closely as possible the two settings. However, you see the lift/gamma/gain mode oversaturates the dark greens and produces a loss of local contrast in highlights.

It was also easier to set-up the offset/power/slope version (less trials and errors). This can be a good way to adjust the contrast as well, after having recovered the dynamic range with the log profile (


NB : I was using the dehaze module as well, so the resaturation + additionnal contrast comes from there

The code :


LGG formulas can’t work with scene referred linear data.

Also note that the Sat formula uses REC.709 constants, and should instead be customizable, or auto-filled software depending. The clamp featured in the ASC is also a problem for some implementations, including ACES, which has it removed.

Fulcrum based Power is also easily achieved via a simple divide by fulcrum → Power → multiply by fulcrum chain.

Manipulations should all be applied on linear, ideally scene linear data, hence why most contemporary pipelines have an assumed fixed reference space with a scene referred linear model, and tack on the nonlinear camera rendering transforms as a non-destructive view. Calculations / manipulations are all done against the scene referred linear values, and transformed under the camera rendering transform, keeping the reference space always linearized.

1 Like

I welcome all your relevant remarks, but I always understand half of them.

What Sat formula ? I use RGBout = (RGBslope * RGBin + RGBoffset)^RGBpower

What ?

What the Hell is that ?

My background is in mechanical engineering, specifically : numerical simulation of thermal processes (mainly partial differential equations solving by finite elements analysis), metrology and high-level signal processing. So, everything I do in image processing, I understand it from a theoritical mathematical point of view. I’m new to C/low-level programming and not super sharp on color and image standards. Please, be gentle with me :no_mouth:

luma = 0.2126 * inR +
0.7152 * inG +
0.0722 * inB
outR = Clamp( luma + sat * (inR - luma) )
outG = Clamp( luma + sat * (inG - luma) )
outB = Clamp( luma + sat * (inB - luma) )
    S = in * slope
    O = S + offset
         = (in * slope) + offset
    out = Clamp(O) ^ power
 = Clamp((in * slope) + offset) ^ power

Contrast is a nonlinear stretching of values away from each other. A fulcrum is the pivot point value that you wish to move about, but remain unmoving itself. Power functions leave value 1.0 where they are, hence moving the fulcrum is a trivial adjustment. Imagine wanting to adjust contrast around a particular value, such as middle grey pegged at 0.18 scene referred. It is as simple as:

InRGB = InRGB / 0.18
OutRGB = Power(InRGB, PowerValue)
OutRGB = OutRGB * 0.18

The astute observer will recognize this as an exposure adjustment, the power contrast, then exposure adjustment back. After contrast adjustment, the middle grey value is unchanged.


Thanks !

is this luma the L channel from Lab ? I’m not using it so far, I only use separate RGB values. darktable works in Lab mode and with unclamped values until the output ICC color profile (before JPEG saving), so I convert the input to prophoto RGB, do the out = (in * slope + offset)^power for each RGB channel, and convert the output back to Lab. Is it still mandatory to clamp in this setup ?

ok, got it. But is that relevant for a color balance ?

You have the ASC-CDL specification, yes? That is the saturation component. If you are in ProPhoto, then you also would use the luminance coefficients for a D50 adapted set of primaries because ICCs are …

Lab is dumb as dirt, and will screw up a nearly unlimited number of manipulations. The clamp is in the official specification of the CDL.

You are talking about the CDL. Power is one of the functions. Fulcrums are relevant in most operations.

I don’t, I work from the Wikipedia page and Blender source code. Do you have a paper ?

I’m glad my photo ended up doing something useful for the community:)
Kudos for your work, hope to see your modules in DT soon.
I just wish I could understand better the technicalities :stuck_out_tongue:



@aurelienpierre according to that wikipedia page, you have to email them to find out how to get the information!

Here are a couple other links with info (apologies if you already saw them):

Overview of ASC CDL

Blender stack exchange (@anon11264400 seems to provide quite a lot of info there with additional links)


Ok so I get ASC CDL is not only a colorbalance thing. The saturation and especially the fulcrum contrast seem very useful, in order to recover a nice-looking image after the log profile.

In which order is it better to arrange the algorithms ?

In terms of implementation, the official order is as I provided above. Saturation exists separately.

Regarding linear versus nonlinear, the CDL meaning shifts when applied to the different transfer function encoded states.

For example, saturation averaged sums are only an approximation when applied on nonlinearly encoded material versus linearly encoded values.

If the CDL is applied on scene referred data, slope is exposure, and power is contrast. If done on properly encoded log material (with no hacky bits :wink: ), offset is exposure, and slope is the contrast control. Etc.

According to this website (posted 2013) saturation should be after “S.O.P.”
Familiar looking diagrams :thinking:

It also has some stuff about the xml implementation on other pages (if that was of interest).

Which is an odd choice given that the further away from linear ratios, the less accurate a desaturation becomes.


first results with all the ACD stack.

Edit : I don’t know what’s going on with the color here, what I see in dt and Gnome viewer is that :



Hi folks !

I have added color-pickers to neutralize casts. Basically, once you pick an area, it computes the average color and inverts its hue, so you can revert color casts more efficiently. It doesn’t always get the saturation right though.


1 Like

Hi again,

I have improved the accuracy of the color neutralization and added an optimizer. When you select 3 samples (black, grey, white), the optimizer tries to fit the CDL curves in order to neutralize the color of the sample patches.

Here is the result with no manual tuning (except for the sample patches selection) :


This feature has been merged today in darktable master branch and will be released (as far as I understand) in dt 2.6, next Christmas.


Hi Aurelien,
having tried your workflow exposure->unbreak input profile->color balance (as explained in your tutorial on I can say I’m very impressed by its performance and reliability.
Even if automatic mode fails sometimes, the manual mode does the job very well.

However I would like to integrate the camera calibration into that process.
I’ve created a camera profile following the method explained here.
It provides better results than the camera base curve.

But, with your process, adding the color look table preset tends to jeopardize the work already done…
What are your thoughts about this. Do you have any advice ?

Hi Philipp,

Thanks for your feedback ! Today, we have added generic presets to the unbreak profile to fallback when the auto mode fails. They are provided for 8, 10, 12, 14, 16 EV dynamic range cameras.

I have seen the same issue with color lookup. I don’t know yet if the inaccuracies of the LUT are just amplified (it’s really hard to get an evenly-lit chart), or if we need to do the LUT on a log encoded chart picture (which defeats the purpose of the color balance after, since the LUT will then linearize colors). For now, you could try another LUT based on a log image of your chart (tune the settings of the unbreak profile with the mid-grey, white and black patches).

Also, I have discovered just yet that, after log + colorbalance, the global tonemapping with draco method gives much better results, betten than shadows-highlights.

Anyway, still WIP.

One in English would be great or an update to the darktable manual :slight_smile:

1 Like