[Suggestion] Simplify Tone Equalizer

No, I haven’t had the chance! What has changed?

The release notes say: * The automatic mask tuning has been improved in the tone equalizer module

1 Like

The main changes are discussed here, although the final implemention was delivered in a different PR:

1 Like

Two things that I would like to clarify to better use the Tone Eq would be one, the norm used. I have no idea other than cycling through them why I would use one over the other as a basis for constructing a mask…the current manual only offers this…

luminance estimator

Choose the method by which the luminance of a pixel will be estimated when mapping it to a mask intensity value (default RGB euclidean norm).

It might be nice to have just a few comments of what the overall impact of choosing one over the other might be as they produce widely different masks when you switch between them. If we have 5 or6 options we should be able to provide a concrete example or use case of why it exists and why you might think to use this over another…

Also, I think for a long time that while I understood that the mask histogram was not the same as the image histogram (early on I think many people equated the two) at the same time I was trying to get my mask spread across the full range as if it was and trying to adjust it to get some contrast in the mask that matched the brightness zones of the image so I could adjust these…but after revisiting the documentation it seems that this was not really a good mask. For example in an image where the foreground was dark and the sky was lighter if I wanted to simply lighten all of the foreground by the same amount and darken the sky a bit again I only need a mask that might actually look more like a gradient mask so that most of the dark pixels get the same adjustment ie are lightened the same and that the reverse is true for the sky and then it blends smoothly…in the past I would tweak the mask settings so that is almost looked like a monochrome version of the image thinking this was better for tonal adjustments but actually this is the thing the tone equalizer is trying to avoid… Perhaps I still don’t have it right but that is how I understand the documentation. I think the tone eq is amazing but I still think the mask is not well understood or controlled by many users… Any comments, corrections or explanations around this post are welcome for sure. I would love to use the Tone eq even better than I do now and I am sure many of you do. For context these comments are based on interpreting this section of the manual below…

It is important that the mask separates the image into regions of similar brightness, and that a suitable amount of blur is applied within those regions. This means that all of the pixels in each region will have their exposure adjusted similarly, without adversely affecting local contrast. Examine your image beforehand to identify which regions you wish to dodge and burn, and use the controls on the masking tab to ensure that those areas are reasonably separated in tone within the final mask. This will allow those regions to be adjusted independently.

2 Likes

Thank you. Looking forward to trying it out in the next release.

Reading through related issues on github, I found this one:

There @anon41087856 says the following:

[…] the contrast correction is meant to make the mask more manageable. So the contrast has to be set such that the filter behaves, it’s not for the filter to accommodate insane contrast settings. It’s a purely technical control that is only meant to push the filters in their sweet spot. If instead it makes them fail, then it’s ill-set. It’s not artistic, anyway it has no direct aesthetical effect on the picture at the end.

So from that I understand that

-The mask contrast is not artistic and has no effect on the final picture.
-It’s there to be able to make the mask more manageable.
-Push it too hard, and it will break the mask.

@anon41087856, what do you think? Does my idea from a few posts back make any sense?

There is no white and there is no black in a scene-referred pipeline. That kind of thinking applies only to a printing medium. In the pipeline, you have a range of light energies and no prior information on them, except how they look once they get projected onto your screen, which is unknown from the pixel algorithm. All we can do is to apply a gain (exposure compensation) and a fulcrumed gain (contrast compensation).

You got the sum-up right, but I don’t know what ideas you are referring to.

No. The radial-basis interpolation has 8 hard-set values for performance. Then, if we do that, copy-pasting presets becomes impossible. Finally, that requires running several pipelines computations (one for detection, one for actual processing), which is not allowed by the current pipeline design. That’s why any detection thing (spot WB, vertical/horizontal lines, etc.) needs a push on a button.


In any case, as a principle, I disregard anything that begins with “simplify”. What we are doing is not simple, the GUI should acknowledge that. Also, if it was simple, it would have been done already. I’m not known to be lazy and to pass on good opportunities to make things faster and easier, but sometimes you hit a good old technical wall that has no solution on paper. Like, in this case, predict how much contrast will be lost by applying a variance-thresholded edge-avoiding blur.

2 Likes

There is no white and there is no black in a scene-referred pipeline. That kind of thinking applies only to a printing medium. In the pipeline, you have a range of light energies and no prior information on them, except how they look once they get projected onto your screen, which is unknown from the pixel algorithm. All we can do is to apply a gain (exposure compensation) and a fulcrumed gain (contrast compensation).

Right, my bad. The names were poorly chosen, since we are in scene referred. I meant “white” as in the brightest value in the mask, and “black” as the lowest value in the mask. Since the guided filter reduces contrast, they are both probably going to be shown as shades of grey (unless the exposure is way out of what my screen can show and filmic is not activated, right?)

The question is: can we divide those 2.5EV equally into 9 nodes and have the module work properly?

No. The radial-basis interpolation has 8 hard-set values for performance. Then, if we do that, copy-pasting presets becomes impossible.

Bummer…If each of those hard-set nodes need to be 1EV apart instead of say 0.1EV or whatever the case may require, then my suggestion wouldn’t work.

What I don’t understand is why this would break copy-pasting presets. Leaving the hard set values aside for a moment, if you have 9 nodes spread out evenly throughout a histogram, as long as the brightest node matches the brightest level in the histogram, and the darkest node, the darkest, wouldn’t the effect translate perfectly between images? For example: if I increase the exposure of the third brightest node by 0.5EV, wouldn’t the effect be the same on the final image regardless of the dynamic range of the generated mask, assuming luminance estimator, preserve details, filter diffusion, smoothing diameter and edges refinement/feathering remain constant? What would change the final result would be if you alter any of those last five parameters, right?

Finally, that requires running several pipelines computations (one for detection, one for actual processing), which is not allowed by the current pipeline design. That’s why any detection thing (spot WB, vertical/horizontal lines, etc.) needs a push on a button.

I don’t mind pushing a button or moving a slider, or a couple of sliders. My issue with the exposure/contrast compensation, is that it is a bit of a guessing game. You press the button, and each time the result changes slightly, often not spreading your histogram very well across the nodes, so you have to go back and forth between tabs.

If exposure/contrast compensation are a bit fiddly to use, have the potential to screw up the guided filter at high values, and their goal is to spread the mask across the 9 nodes, wouldn’t it be easier (in an ideal scenario) to tell the module: these are the settings for the guided filter mask, dynamic range will be reduced accordingly, but this are the brightest and darkest levels in the mask, so please divide it evenly into 9 nodes.

In any case, as a principle, I disregard anything that begins with “simplify”. What we are doing is not simple, the GUI should acknowledge that. Also, if it was simple, it would have been done already. I’m not known to be lazy and to pass on good opportunities to make things faster and easier, but sometimes you hit a good old technical wall that has no solution on paper. Like, in this case, predict how much contrast will be lost by applying a variance-thresholded edge-avoiding blur.

I am sorry if I gave you the wrong impression. It’s hard to communicate the right tone through writing and english is not my first language. I chose this thread, since it had semi recent activity, and a lot of comments, but I didn’t pick the title. I know you are not doing simple stuff by any means, are lazy or don’t want to improve the tools you cleverly designed. My comments, opinions and mockups come from a place of admiration and respect for your work on darktable in the hopes that they might help any of you improve the tools we have. If this particular case can’t really be improved, I will still use the module. It’s not the end of the world, and what it allows us to do makes up for going back and forth between tabs and sliders.

Cheers!

Just my 2 cents since I also need to switch between the advanced and masking tab quite often with some pictures until the result is as I just need it.
What may help me in this situation would be some kind of direct interaction in the advanced view. I thought about the possibility to use the scroll-wheel plus accelerator here, like we have it in the mask definitions. e.g. scroll-wheel plus [shift] to shift the spectra left-right and scroll-wheel plus [ctrl] to stretch-compress the spectra. What do you think about this?

You can do that, at least with master (soon-to-be 3.8):

3 Likes

This is actually great! I didn’t realise you could map those sliders to shortcuts and use them from another tab. I set mine to:

Ctrl+Left = decrease exposure
Ctrl+Right = increase exposure
Ctrl+Up = increase contrast
Ctrl+Down = decrease contrast

So much easier to tweak the mask once you are able to look at its histogram!

I actually can’t believe how well this works once I got it set up this way. Looking at the histogram is key when adjusting the mask’s exposure and contrast. Would it then be crazy to have a true histogram in the masking tab (however short vertically) instead of a gray bar under the “mask post processing” label that displays a representation of the middle 80% of the histogram?

On another note, I don’t know if this has been changed in 3.8, but In 3.6 the sliders for the mask exposure/contrast compensation go from -4 to +4EV. It seems a little extreme for contrast, since after a few tests I haven’t needed to push it above .4EV. Perhaps to be safe in case someone wants to work only on a certain part of the image (highlights, midtones, shadows) it can have 1-2EV of room, but isn’t 4EV in either direction too much? Also, since contrast compensation is only used in the case of a guided filter, and the sliders always decrease the mask’s contrast, is there a need to let the contrast compensation slider go into negative values?

You can actually see it in the mask it just takes getting used to…if its black its off the left edge, if its extreme white its off the right edge and all tones in the region get the same ev adjustment…so if the areas you want to impact are shades of grey you are good…then its just how you blur, contrast, refine the edges of those grey regions…in that way the mask actually give you more information than the histogram as you don’t know where the bright and darker parts of the masking are from looking at the histogram…I guess you can match them up with the cursor indicator but the mask is better for an overall impression…

You are right, of course. A histogram is just a tool to help us make decisions, and if we want to target a specific area of the image, it won’t help us, since it won’t tell us if the blur is affecting the areas we need it to affect. However look at the following two screenshots with same settings of the same picture:

Screenshot_20211201_084308

Screenshot_20211201_084340

If you look at the grey bar in the masking tab, I’d think the histogram range is very narrow, and only spans three nodes at the most, as well as being all the way to the right side. In reality, the histogram is quite centered, and I’m able to affect the mask with at least 6 nodes before even touching the exposure/contrast compensation sliders. That’s what I’m talking about. Besides having the blur where and how we need it in the mask, I find it important to know how many nodes it spans, and the current grey bar doesn’t seem to be a very reliable tool, but perhaps I’m missing something.

Two things about the bar and histogram display.

The gray bar spans 80% of the histogram “surface”. Your example has a fairly long “tail” towards the shadows, and a larg peak in the light areas. So the gray bar will cover most of the light areas, but “ignore” the shadow part.

Now, exactly how much of the histogram the bar should cover can be discussed, but 100% coverage doesn’t work in practice.

E.g. xtreme highlighs, like lamps, would throw off the bar in an impossible way: “tone equalizer” comes before filmic in the execution pipeline, so channel values are not restricted to the interval 0…1 yet. That means extreme highlights could end up at values of 3, 4, … with the rest of your image nicely in the 0-1 range.

Noise is also a problem: in the shadows, small intensity variations can give large variations in EV. And noise is just that, small intensity variations. So you could end up with very low EV values (far outside the useful range of your image).

In addition, the lightness scale in the tone equalizer is linear in EV, that means exponential in lightness (each EV doubles the physical lightness). This ‘favours’ the shadows, and more or less mirrors human perception. The image histogram at the top of the right sidebar is linear in lightness, which favours the hightlights and corresponds to the actual light energy.

So forcing the mask or an indicator to cover 100% of your image at this point in the pipeline is just plain bad.

Since you can see the mask overlayed on your image (“display exposure mask” at the bottom of the tab), you should still have a good idea how the mask coverage is, and how well suited to your purpose. The mask is a tool here, not the final result.

And how often do you really target the whole tonal range with the tone equalizer? There are simpler tools to adjust global contrast…

2 Likes

Yes, that is clear

I don’t quite agree, but see below.

That is also clear

That is clear as well.

That is also understood

Hence why I proposed a zoomable interface for the advanced tab, so that we are not stuck with nodes that are 1EV apart. That way you could disregard those “long tails”. Contrast compensation is there for that reason, but if used agressively, will create artifacts and mess up with the guided filter. What @kofa suggested is so far the best solution for me, although it’s not perfect, since you can only use the module that way via shortcuts and not through the GUI.

Agreed

Very often. I try to use the module based on what @anon41087856 shows here, and he uses the module on the whole image:

Module usage could be summed up in the following 3 usecases:

  • For increasing contrast, as long as you don’t care about also increasing local contrast use no filter.
  • For increasing contrast while preserving local contrast, use guided filters (I won’t go into the differences here).
  • For compressing dynamic range while preserving local contrast (which I believe is one of the most important usecases, and most of what @anon41087856 demonstrates in the video) use guided filters.

The part of the image where you do any of the 3 is up to you. The problem is that, say you want to focus on a very specific region, like the shadows of the image (leaving noise aside, I mean the actual darker parts of the image that you want to affect). To expand the histogram and have more nodes to control them you need to increase mask contrast and adjust mask exposure accordingly. The problem with that, is that the mask will start to fall apart quickly, creating artifacts. But if you don’t increase contrast you don’t have enough nodes.

Now, let’s look at what happens in each of the three usecases, when boosting the contrast enough to focus on only the shadows, for example:

  • Increase global and local contrast, no GF: there is no contrast compensation, so no problem.
  • Increase contrast and preserve local contrast, GF: Possible artifacts.
  • Compress dynamic range and preserve local contrast, GF: Possible artifacts, and if you compress DR in areas with too similar lightness value, the GF can only do so much, local contrast will decrease (although probably not as much as with no GF).

That’s why, despite what @kofa just showed us, I believe that, and if the technical difficulties are indeed solvable (proportionally scalable nodes), having a zoomable interface in the advanced tab instead of fixed nodes as well as a real histogram in the masking tab could be a good solution. If there is no contrast compensation, in theory, contrast wouldn’t mess with the guided filter, hopefully minimizing/avoiding the artifacts.

If not, the shortcuts he showed us, already make the module much easier to use for me.

Cheers!

Not breaking it down in to use cases I think in the end its to allow it to be fast enough to not kill the pipeline…the pipeline is triggered so often that a really slow module would impact performance. So if you are stuck with 8 or 9 points and you go to 0.1 ev nodes then you have a range span of 1EV …would that be useful?? I’m just asking not trying to be difficult…

Obviously, if my suggestion is possible, but brings darktable to its knees, that is not a viable solution.

0.1EV, 0.3EV, 0.8EV… Whatever you might need. That’s what I mean with a zoomable interface. The EV values change, but the nodes are proportionally at the same distance from each other, instead of fixed at 1EV separation.

Remember we are talking about the mask, and the mask only. If after tweaking the mask’s settings, the mask’s contrast decreases, and the mask’s dynamic range spans let’s say 2EV in total, then 9 nodes at 0.1EV distance would control 1EV of the mask, which in turn would control half of the final image, giving you all the nodes to tweak that half, and you wouldn’t need exposure or contrast compensation, hopefully then mitigating or avoiding artifacts resulting from the latter.

All this assuming my idea is possible.

But the mask’s range is fixed at 8EV (9 nodes for 8 intervals). So your nodes are always 1EV apart relative to the mask
What you change with the sliders is which part of the image histogram is covered. And the display of the mask will be affected by the filmic module later in the pipeline

I’m not sure I understand what you mean. EVs are EVs, they are not relative to the mask. The working range of the module is fixed at 8EV with 9 nodes at 1EV distance.

What we change with the top sliders in the masking tab is the kind of mask we are creating, which in turn reduce the mask’s contrast, so its dynamic range.

What we change with exposure/contrast compensation is the position (exposure) and spread (contrast) of the mask, so we can use more nodes to control the final image. If those values are pushed too hard, artifacts are introduced.

What I’m advocating for is that the tone EQ is not fixed at 8EV, so we can work with a lower contrast mask, and still have 9 nodes to control the final result, hopefully mitigating/avoiding artifacts.

If I understand correctly, you’d like to stretch and offset the scale of the X-axis to fit the histogram.
Again, if I understand correctly, the exposure and contrast adjustment scale the data to fit the pre-defined section of the X-axis, between -8EV and 0 EV.

What is the difference between your method (positioning and scaling the X-axis to fit the (to-be-manipulated part of the) histogram), and the other (positioning / scaling the histogram (exposure and contrast, respectively) so (the to-be-manipulated part of) it fills the X-axis (between -8 EV and 0 EV))?

One (your way) appears to say:
‘The object I want to manipulate is too small, only 8 mm; one edge is at 3.5 cm, the other at 4.3 cm. Let’s get another ruler that has a millimetre scale, and slide it so that the object gets between the 0 mm and 8 mm marks. I’ll read off data using my new ruler using the mm scale and enter the numbers in my calculations.’ The left edge will read 0 (mm), the right edge 8 (mm), the other points distributed between them.

The other:
‘Let’s make a 10x enlarged copy of the object, so it is 8 cm long; now let’s slide it to the left so that it fits between the 0 cm and 8 cm marks on my ruler. I’ll read off my data using my original ruler, using the cm scale, and enter the numbers in my calculations.’ The left edge will read 0 (cm), the right 8 (cm), the rest nicely distributed between those.

Yes to both.

That’s right, you got what I meant. The disadvantage of the second method (making an enlarged copy of the object, AKA mask contrast compensation) is that if the values are pushed too much, the mask and the guided filter will start to break and create artifacts. Going along with your metaphor, it’s the same as when you enlarge a photo beyond its resolution. The image will start to fall apart.

My method (getting a smaller ruler), assuming it is technically possible, would hopefully avoid those artifacts, since after the mask is created it is not altered by additional post-processing (exposure and contrast).