v9.1.1
Menu

Reinhard Global Tone Mapping

mediumPROTone MappingHDRCV: Computational Photography

Implement Reinhard's global tone mapping operator to map High Dynamic Range (HDR) images to a displayable range while preserving local contrast. This technique is crucial in Computational Photography as it enables the display of HDR images on standard devices.

The concept of tone mapping is based on the idea of compressing the dynamic range of an image, which is the ratio of the brightest and darkest areas, to fit within the limited range of a display device. Tone mapping operators like Reinhard's apply a non-linear transformation to the image's luminance values, preventing saturation and preserving details. The transformation involves calculating the log-average luminance of the image, which represents the average brightness, and then scaling the luminance values based on a key value that controls the overall brightness.

To achieve this, the following steps are involved:

  1. Calculate the luminance of each pixel in the HDR image: L=0.299R+0.587G+0.114BL = 0.299R + 0.587G + 0.114B.
  2. Compute the log-average luminance of the image: Lˉ=exp⁡(1N∑x,yln⁡(L(x,y)+δ))\bar{L} = \exp\left(\frac{1}{N}\sum_{x,y} \ln(L(x,y) + \delta)\right) with a tiny δ\delta (e.g. 10−810^{-8}) so black pixels don't break the logarithm.
  3. Scale the luminance values based on the key value aa and log-average luminance: Ls=aLˉLL_s = \frac{a}{\bar{L}} L.
  4. Apply the Reinhard compression function to the scaled luminance values.
  5. Restore colour by multiplying each pixel's R, G and B by the same ratio Ld/LL_d / L, and clip the result to [0,1][0, 1].
Ld=Ls1+LsL_d = \frac{L_s}{1 + L_s}

Return an array of the same shape as the input, (H,W,3)(H, W, 3), with values in [0,1][0, 1].

This technique is widely used in image and video processing applications.

Example

Input
hdr = HDR image with values > 1.0
key = 0.18
Output
LDR image with values in [0, 1]
Reasoning
  • Take a 1×21 \times 2 image with two grey pixels: (4,4,4)(4, 4, 4) (a highlight) and (0.25,0.25,0.25)(0.25, 0.25, 0.25) (a shadow), with key a=0.18a = 0.18. Grey pixels have LL equal to their channel value, since the weights sum to 1: L=4L = 4 and 0.250.25.
  • Log-average luminance: Lˉ=e(ln⁡4+ln⁡0.25)/2=e0=1\bar{L} = e^{(\ln 4 + \ln 0.25)/2} = e^{0} = 1. As a geometric mean, it isn't dragged up by one huge highlight the way an arithmetic mean is.
  • Scale by a/Lˉ=0.18a / \bar{L} = 0.18: Ls=0.72L_s = 0.72 and 0.0450.045.
  • Compress: Ld=0.72/1.72≈0.4186L_d = 0.72 / 1.72 \approx 0.4186 and 0.045/1.045≈0.04310.045 / 1.045 \approx 0.0431.
  • Each pixel's channels are multiplied by Ld/LL_d / L, giving (0.4186,0.4186,0.4186)(0.4186, 0.4186, 0.4186) and (0.0431,0.0431,0.0431)(0.0431, 0.0431, 0.0431), shape (1,2,3)(1, 2, 3) as input.
  • Notice: the inputs differ by 16×16\times, the outputs by about 9.7×9.7\times, so highlights are squeezed hardest. LdL_d can never reach 1, so grey pixels stay below 1, but a strongly coloured pixel can push one channel past 1, which is what the final clip to [0,1][0, 1] handles.

Constraints

  • hdr: HDR image (H, W, 3)
  • key: Key value for exposure adjustment
  • Return: Tone-mapped LDR image

Learn this in

More from CV: Computational Photography

PRO

Editor locked

The code editor is locked for Pro problems. It is only available for free problems. Please upgrade to gain access to the code editor for all problems.

solution.py

Test results

Sign in to run your code against the test cases.