Search code examples
imageimage-processinggraphicsbrightnesscontrast

Changing non-commutative image properties(like brightness and contrast) using sliders, adobe lightroom way


I am working on an app where i want to change several properties of an image like brightness, contrast, saturation, hue etc using sliders (the use case is similar to the lightroom workflow where user can change these properties just by moving sliders).

enter image description here

Problem:

My problem is, these properties are not commutative.

Example

  1. I change brightness by value +30 on image I i.e. B(I), then contrast on the resulting image by -60 i.e. C(B(I)), the result is not same as B(C(I)).
  2. After above operation C(B(I)), if i try to revert the brightness by -30 to negate the brightness effect, i.e. B(C(B(I))), the result is not same as C(I).

Approaches i have tried:

I have tried two different approaches but both of them have failed.

  1. Keep on applying the results on the latest image i.e. if i want to change the brightness again i apply it on the result of C(B(I)). This obviously give wrong results and don't negate the effect of earlier application of brightness.
  2. Whenever a effect is reapplied, remove the first one. Example: If i have applied C(B(I)), and again want to change brightness, i would remove the first brightness effect and hence would have C(I) and then will apply the result on this new result. So new effect would look like B(C(I)). The problem with this approach is, its slow as the effects need to be reapplied as soon as you change the slider(because of the removal of pervious effect). And it also result in sudden change in image(very visual) if i change the slider back to brightness(because not the result is changed from C(B(I)) to B(C(I))).

Lightroom and many other image processing softwares achieve this but i don't know how, they perfectly negate the changes as user move the slider irrespective of the order in which properties are applied. I don't know how they do it and hence need help.

Note: Lately i was wondering if this can be achieved by blending(don't know which type of blend) the result of each effect applied on original image, rather than applying them on the results of previous one.


Solution

  • The way this works is to create a graph of the operations you want to perform on the image and re-execute the entire graph whenever any parameter changes. So if you want Brightness followed by Contrast, you'd create a Brightness node and a Contrast node, then hook them together like this:

    Image -> Brightness -> Contrast -> Output Image

    When the user changes either the brightness or contrast slider, you execute the entire graph with the new parameters. If you've written your image processing nodes sensibly, then this shouldn't be too slow for something like just a brightness and contrast adjustment.

    If your graph is very large and complicated, it may make sense to cache some of the intermediate images and only recalculate the parts after the intermediate. But honestly, for the type of stuff shown in your picture, that shouldn't be necessary.