Search code examples
iosimage-processinggpuimage

How to reproduce Highlights and Shadow effects from Adobe Lightroom in iOS app


I'm trying to reproduce Adobe Lightroom effect in my iOS application. Currently I'm using GPUImage for all effects, but found difficult to reproduce Highlights and Shadow effects. Also I already tried to use CIHighlightShadowAdjust from CIFilter but it gives me wrong result.

So I'm looking for at least algorithm which is used by Lightroom for this effects. They both are very similar to Brightness change, but seems like they are used to change only light/dark parts of picture, in depends if Highlights or Shadows was used.

Can anyone point in a right direction what I need to look to make same effects? How it is possible to change brightness only for dark/light part of picture?

Here is examples 1. Left is original image and right is an image with +100 highlights adjustment(possible range -100;100 with 0 as default).

Highlights +100

You can see that sky(lighter part of image) has different brightness, but statue is almost has not changed.

  1. Left is original image and right is an image with +100 shadows adjustment(possible range -100;100 with 0 as default).

Shadows + 100

Here you can see that statue(darker part of picture) has big changes in brightness, but sky remain almost without changes.


Solution

  • It looks like a nonlinear brightness transform has been applied. For example, the highlighting effect could mean that only the brighter parts of the image have even more increased brightness and the shadow adjustment could mean that the darker parts of the image have increased brightness.

    The general approach would be

    • Transform RGB image data into a color space with the brightness as separate dimension, for example HSL or CIELAB.
    • Transform the brightness/lightness/luminance pixel-wise with a single transformation function that is continuous and monotonically increasing but bounded to the range of allowed values. This is akin to non-linearly stretching or compressing the brightness histogram.
    • Replace the original brightness with the transformed one.
    • Transform back into RGB color space.

    A characteristic of the brightness transformation function is that it typically only stretches or compresses a certain brightness range (you show that nicely in the example images). This requires typically more than only a single parameter (you would need to define the range of the histogram that is affected as well as the strength). It looks like Adobe has some heuristics what it regards as shadows and what it regards as highlights (maybe the mean of the brightness histogram) as cut-off and only offers the strength as parameter.

    The exact shape of the transformation is also up to your own taste. I played around a bit

    Highlighting that looks similar to your hightlighting I can get with (transformed to CIELAB and Ligthness L goes from 0-100) a piecewise-linear function:

    a = 1.5
    b = 50
    L(L>b)=a*L(L>b)-(a-1)*b
    

    enter image description here

    Shadow enhancement that looks similar to your shadow enhancement I can get with an exponentially decaying enhancement.

    a = 4;
    b = 20;
    L = ((a-1)*exp(-L/b)+1) * L;
    

    enter image description here

    You see that I need always at least two parameters and I'm convinced that one could find better transformation functions, but the results strongly suggest that in essence it's nothing more than just a brightness transformation, which can be reproduced in an iOS app. Playing around with different transformation functions might give a better feeling of what is good and what is not.