Tone Equalizer proposal

I have been looking at the tone equalizer for a while now and I finally have something that may be good enough to show it publicly.

Disclaimer: This is my first time working on a module and the learning curve is steep. This preliminary version has known problems (it may produce deviating results on export and crashes when you make the graph too small).

This is a summary/explanation of what I have changed and why I have changed it.

3rd party example images

Forest scene by @Mattes, Sunbeam highlights a detail in the forest

High contrast garden by @Popanz, High contrasts in a man made wilderness

Basics of the Tone Equalizer

Why is it difficult to raise shadows / lower highlights? If we simply make dark pixels brighter and bright pixels darker, we will loose contrast - especially local contrast and the image will look dull and HDR-ish.

(In all of the example images I went pretty extreme with “wrong” settings to show the effects.)

To prevent this, we want to treat pixels that are close to each other nearly the same. This leads to the introduction of a mask:

  1. We convert the image to black and white.
  2. We blur it.
  3. We decide based on this mask, how much each image pixel will be brightened or darkened.

This strategy is suitable for preserving small details (local contrast), but it breaks when the differences are too large. In this case we get bright or dark borders around the edges of objects.

This is why the tone equalizer uses a guided filter. This filter will blur uniform areas of the image, but preserve contrasty edges. The “Edges refinement/feathering” slider will tell the guided filter, what an edge is. Very low values will completely blur the image while high values will detect everything as an edge and blur nothing at all.

It is worth playing with the mask when tone equalizer results don’t look good. If the image looks to HDR-ish, the mask may not be blurry enough. If there are artifacts around objects, edge detection is too low.

In the final step, we use a curve, the sliders or the mousewheel to set how much brightness correction should be applied, each brightness level of the mask gets an associated correction.

Note that the “EV” values that are shown on the histogram and sliders are “mask EVs” and only very loosely related to the dynamic range of the image. Even without extra “compensation” applied, the dynamic range of the mask can easily be half of that of the image, so the shown EV values can be misleading.

The problems with exposure/contrast compensation

The sliders for mask exposure compensation and mask contrast compensation - together with their respective “magic wands” - are notorious for their unpredictable behavior. When they are changed, the mask histogram usually moves roughly in the right direction, but also often jumps around. These sliders change exposure and linear contrast BEFORE applying the guided filter.

Blurring an image reduces its dynamic range and contrast. This is easy to see, the brightest pixel gets averaged with nearby pixels, making it less bright, and similarly the darkest pixel becomes less dark. As a result, the difference between the brightest and darkest pixels (the dynamic range) decreases. However, the extent of this reduction depends on the brightness of the surrounding pixels, which makes the behavior unpredictable.

The main change in this experimental version is swapping the order of the steps:

This way the mask can be modified deterministically.

Side note: In current Darktable the lower section of the masking tab is incorrectly labelled “mask post-processing” while it actually pre-processes the mask before the guided filter calculation.

Which order is better?

The result when swapping the order of operations is not the same as before. This is why I implemented new (additional) Exposure/Contrast sliders and the old ones are still in the module for backwards compatibility.

If the result is different, which order is better? I would argue that changing mask exposure after the filter is better for this reason:

The original uncompensated contrast of the mask is directly derived from the image. Therefore it provides a somewhat deterministic baseline for setting “Edges refinement/feathering”, especially when defining settings that should be valid for multiple images (module defaults, presets).

Using contrast compensation artificially “disconnects” the mask’s properties from the image:

This is an extreme example, as this image has a low dynamic range and does not need the tone equalizer. However, before clicking “auto adjust”, the mask is reasonably blurry - which is what you would want. Clicking the magic wand not only increases the mask contrast (the original intention) but also removes the blurriness completely.

People use the mask contrast compensation to “spread the histogram”, so they can use all 9 sliders for precise control. I don’t think that users are aware of the effects this has on edge detection. Some users even want to work only on shadows or only on highlights and spread the graph even more for this reason. Such adjustments surely require an adjustment to “Edges refinement/feathering”.

The proposed reversed order does not have these problems. Users can move the histogram around to their heart’s content without effects on edge detection.

Taking things too far

Very strong corrections with the tone equalizer tend to look bad.

Ignoring the “mask EV vs. image EV” difference, we can make the following observation: It’s actually the downward slopes of the curve that lead to a loss of contrast. Worse, a downward slope of more than 1 EV per EV in the curve will reverse brightnesses in the image (i.e. area A was darker than B and now B is darker than A).

Curves that spread the downward slope linearly over a long distance, making it less steep, gave nicer results in my (few) tests.

Therefore I think that the sine-like curves from the “compress shadows/highlights” presets are not optimal for compressing the dynamic range. Those curves are the steepest in the midtones, the brightness range that we care about the most.

When there is no desire to keep the blacks/whites unchanged, an alternative would be the straight downwards line that I have seen @s7habo use on Youtube.

Experimental warnings

After noticing the significance of the slope, I added another very experimental feature: coloring the curve to warn the user, if they are doing something that will probably look bad.

Currently implemented “rules”:

  • A downward slope of more than 0.5 EV/EV is orange, a downward slope of more than 1 EV/EV is red. For this I compare the 5th and 95th percentile of image and mask to get a very rough estimate of how much the mask dynamic range differs compared to the image.

  • Raising the shadows and lowering the highlights with the guided filter turned off will cause orange warnings.

  • Lowering the shadows and raising the highlights with the guided filter turned on will cause orange warnings. The user probably expects to be able to improve the image contrast here, but the guided filter will work against this.

Note that when users spread out the histogram (i.e. to work only on shadows), the curve is actually much steeper than it looks. Users who use this type of precision editing have to be very gentle to not introduce artifacts.

The updated UI

Auto align is another new functionality that was not yet mentioned. It should automatically align the mask, which is especially useful for presets. Using this option, the mask will also re-align itself, when an upstream module in the pipeline changes the image exposure.

Possible values are:

  • Custom - Set mask contrast and brightness manually (current default).

  • Fully fit - Fit the mask, so the darkest 5% of values are below the -7 marker, 90% are between -7 and -1 and 5% are above -1 (the same target values that the old magic wands used). Mask contrast and brightness sliders are not available in this mode.

  • Align at shadows - Fit the mask, so the darkest 5% of values are below the -7 marker and 95% above. The contrast slider is available in this mode, so the mask histogram can be scaled around the -7EV point. Set it to approximately 1 to work only on shadows.

  • Align at midtones - Fit the mask, so some middle brightness value is locked at -4 EV. The contrast slider is available in this mode, so the mask histogram can be scaled around the -4EV point.

  • Align at highlights - Fit the mask, so the brightest 5% of values are above the -1 marker and 95% below. The contrast slider is available in this mode, so the mask histogram can be scaled around the -1EV point. Set it to approximately 1 to work only on highlights.

Note that all brightnesses below -8EV are treated the same as -8EV and all brightnesses above 0EV are treated as 0EV. I noticed in tutorials that people like to make the histogram smaller, so it is fully contained in the 8EV range. I don’t think that this is necessary.

Setting the new controls to auto-align: custom, scale: 0, shift: 0 will make the module behave the same as the previous tone equalizer.

Next steps

I hope this is useful.

Over on the AgX thread I learned that some users of this forum build preview versions of darktable with experimental features. Maybe this could be included there (just copy my toneequal.c). However note that I added new parameters - going back to an old version from this one would be problematic, so don’t try this on your production database.

29 Likes

I personally against combining the two tabs. I never use the sliders and I don’t want to see them. I also don’t like making the module take up more vertical space; vertical space is premium real estate.

I use this module on just about every edit, so I wince a bit at the thought of changing it; the guided filter works really well in my opinion.

2 Likes

The sliders are in a collapsible section, which uses very little space when it is closed. They can also be used to more precisely edit the curve points (i.e. by typing values), I found it valuable to have them there during testing.

2 Likes

Well yes, but still take up more space than the current module, and there’s really no good reason to ever have both displayed at the same time IMO

Maybe try it before making a decision. For example when I created the custom curve above, I did this by right-clicking the sliders and entering values and it was nice to see the effect immediately.

2 Likes

Thanks for sharing your investigation and suggested improvements… I will try to find some time to play with it…at the very least some of your observations about the math and or the process might at the very least be evaluated and prove to be worthwhile improvements so it wouldn’t also have to be a wholesale change of the module perhaps but some integrated enhancement…in any case maybe a few more corner cases shown here where you can demonstate the merits of your approach vs the existing one might help others with interest to test and evaluate it…

Here is a dirty (lazy) build by just copying your module into a test build I had for AGX…it doesn’t have the last change made by kofa… so this build is only for exploring or testing your module and it does have AGX but not the last update as noted…

I found one small bug…if you cycle through the presets they work unless you select the last one for the full scale and then the other stop working…

https://www.dropbox.com/scl/fi/icmmuohip5bli6bz580b9/darktable-5.1.0-610-g0fd2580dff-dirty-win64.exe?rlkey=7j9pivp7hi1cdwcjot9mohmgs&st=e5m2hew4&dl=0

2 Likes

I think you should provide some compelling use cases.

I also don’t need to try the UI change. I use the sliders 1 in 100 used of this module, I don’t want to see them all the time.

First of all: thank you @JovianSettler for taking the initiative to work on improving the tone equalizer, there has been a lot of talk, but nobody willing to put in the elbow grease.
Regarding the slider discussion: I also don’t understand why the sliders are moved into the same tab as the curve, as slider movements do not affect the histogram. In terms of the extra consumed vertical space I would find it acceptable if there is a real workflow use-case which benefits from having it there.

However the masking parameters in the “masking” tab affect the histogram, that’s why I would rather like to have a way to show the histogram while moving those sliders. IMHO the tone distribution boxplot visualization in the “mask pre-processing” collapsible section does not accurately reflect the real tone distribution for some of my workflows (neither clipping shadows nor highlights), then I find myself switching back and forth between the “curve” and “masking” tabs frequently. I see two ways how this could be achieved:

  1. moving the masking parameters into a collapsible section within the “curve” tab, which probably will not be popular with people who are sensitive to vertical space usage.
  2. have the histogram in a collapsible section within the “masking” section and remove the tone distribution boxplot.
2 Likes

Hello.

This is just an idea, the tone equalizer module, can use the same method to show and hide the sliders as the color equalizer did and thus achieve a simpler and more compact interface that can show the advanced controls at the time the user wants to be precise or be simple if the user wishes, where you can control the tones from the same curve. It would also maintain consistency with the color equalizer module. That would make the program modules use the same methodology of operation.

4 Likes

If there was an update to the module and the decision to use the sliders holds I think keeping conventions as you suggest would be good but personally I could do without them and I am sure that @hannoschwalm in one of the previous discussions said the math was the same…in any case I could live without them…

I also never change the curve smoothing and I am not saying remove it but it doesn’t need to be prominent does it …

In my quick play the tools here labelled contrast and brightness worked well as did the presets except for the little bug I noted so for me.

So in the layout above I would move the masking items below this where the sliders are shown into a masking section…some could even be above ie the commonly used ones say the estimator and the preserve details selection and then the 4 mask controls could be in a collapsable section ie smoothing feathering diffusion and quantification or really they could just be separated by a header and you would have all the controls there with no tab switching…the bar is not needed if the manipulation can be seen on the graph as the controls would be in that unified panel. Maybe I am just projecting how I use the module and what features but anything that removed that tab switching…I guess short cuts can always be brought into play as well…but anyway I would be fine with a unified panel design for the module

Let’s first try this, the collapsible section seems ok to me.

3 Likes

I agree with Mica. The strength of this module is both the curve and being able to use the scroll wheel in the parts of the image(zone) you want to target. This is a very unique workflow that you don’t see elsewhere and should be the primary way to use the module imo. The users who need the sliders don’t really need the curve at all imo…

1 Like

Having it collapsed doesn’t really change anything for the better, its still a click to get to the sliders and you’ve used up more vertical space because the tabs are still there.

3 Likes

Wow thanks for diving in tone equalizer module :star_struck:
I’ll have a try this week!

I agree that the behavior of the “post-processing” sliders always have puzzled me, I was expecting these to effectively change mask contrast and exposure, but as you noted it is not the case. And the fact that they change the blurriness is a common cause of either halos or loss of local contrast.

I use this module a lot, and it requires a lot of back and forth between the tabs, at least in my experience/usage. I don’t use the sliders from the “simple” tab at all because I can’t see the real time effect on the curve, which can display odd “oscillations” very quickly. But I’d love to have the both the curve and sliders from the masking tab on the same panel. Also, vertical space is not a problem in my opinion because:

  1. Many module use such vertical space (some way to much, like blurs)
  2. It would be legitimate in this module which requires a lot of tuning
  3. Some sections can be collapsible
3 Likes

I think I follow what you mean by “sliders” but we should be clear when discussing if we are talking about sliders what we mean and what is going where ie if we mean some of the ones from the masking tab vs the individual zone sliders for the curve. A couple of times I wasn’t 100% sure which ones you were referring to.

In this proposed mock-up the mask histogram is very responsive and so if the mask controls were moved underneath the graph we could remove the step of going back and forth between the tabs to adjust it and we would see the impact in real time. There are quick options to skew the mask left or right or center it and finally custom to taste. We would no longer need the mask position bar graph as we wouldn’t be in a different tab from the graph… There must be some overhead for this as often if I click too fast i will see wait for the previous action to complete or something like that and also it jumps around. So it would be one less thing to update and in limited testing I didn’t see that in the mock-up (proposed version/update)

For me if the individual EV sliders are collapsed, hidden or remain as a tab it wouldn’t matter for me as I honestly never take a look at them… I also feel like the more important discussion is this an opportunity to merge the curve and mask tabs and what might that look like… again just my opinion…

1 Like

Thanks for the helpful comments.

Since I was asked to summarize the benefits of these changes again, they are mostly on the usability side:

  • With automatic alignment as default (which it is not right now) increase the chance that the user does not need to touch the mask at all - like in any other raw development software.

  • Presets with automatic alignment have a higher chance of working without changes to the mask.

  • With automatic alignment, the module automatically adjusts to upstream image changes. For example the user can change the exposure (earlier in the pipeline) and the tone equalizer will still affect the same areas of the image.

  • If the user decides to change the mask exposure/contrast manually, the histogram moves much more responsively and predictably.

  • Also seeing the histogram while moving it is a benefit in itself. This was discussed here fore example: Some thoughts on improving the Tone Equalizer UI ¡ Issue #17287 ¡ darktable-org/darktable ¡ GitHub

Regarding the slider discussion:

  • I did not realize that the sliders were that universally hated, given that they are the default interface of the module. :slight_smile:

  • On their own page, they are not very useful, because the user has too little context regarding what they do. In my opinion their usefulness increases when seeing the graph/histogram at the same time.

  • Regarding what they do / “the math”: The sliders simply move the 9 dots on the graph. However there is one major difference: The sliders can be moved individually. User input in the graph always affects multiple dots (this also bothered the OP on the github discussion linked above).

  • During a past discussion about removing the sliders, somebody mentioned that they are needed to be assigned to MIDI controls.

Since this discussion is mostly about vertical space, I will make things more compact in the next version.

Bugs:

  • Over on github it was mentioned that I did not increment the module version number correctly and therefore edits and presets were not correctly converted to the new version (which can cause all sorts of issues, because C and memory…). I was not able to reproduce the bug that @priort saw, but it sounds to me like this might be the cause.

I will provide an updated version in a few days.

9 Likes

First thing I would do is to swap the tab labels ‘simple’ and ‘advanced!’

Apart from that, let me cast a vote in favour of…

  1. Those ‘simple’ sliders. I do use them, and regularly. sometimes for a steep fall off of highlights, sometimes for a tweak to the peak point.

  2. I Also use the curve-smoothing slider.

A question about “automatic alignment.” When one cuts and pastes from another images, it is usually necessary to adjust the mask in the new image: how would that be with auto alignment?

The ability to control via MIDI is a great feature. But IMO the risk of using only one slider is to introduce artifacts very easily. See for example if I use the default preset and increase the -4EV slider, it gives this wavy curve:

So I’m wondering if, even for beginners, it is a good idea to keep the label “simple” over this tab (also, the “advanced” tab is much easier to use I think).

2 Likes

Just because the curve looks strange that doesn’t necessarily introduce artifacts

I don’t use the sliders very often, but they are handy on occasions, especially for making repeatable presets. For me, they mostly serve as a place where I can manually enter values.

What irks me most is that the graph and the graph exposure/contrast adjustments are on different tabs. I put the together in the quick access panel, which has mostly alleviated this issue. But the new UI is even better. I like it!

7 Likes