Fred's ImageMagick Scripts



    Licensing:

    Copyright © Fred Weinhaus

    My scripts are available free of charge for non-commercial (non-profit) use, ONLY.

    For use of my scripts in commercial (for-profit) environments or non-free applications, please contact me (Fred Weinhaus) for licensing arrangements. My email address is fmw at alink dot net.

    If you: 1) redistribute, 2) incorporate any of these scripts into other free applications or 3) reprogram them in another scripting language, then you must contact me for permission, especially if the result might be used in a commercial or for-profit environment.

    Usage, whether stated or not in the script, is restricted to the above licensing arrangements. It is also subject, in a subordinate manner, to the ImageMagick license, which can be found at: http://www.imagemagick.org/script/license.php

    Please read the Pointers For Use on my home page to properly install and customize my scripts.

TONEMAP3


Enhances the shadows and/or highlight regions in an image using a non-linear log or gamma function plus an extra processing function.

Download Script

last modified: December 16, 2018



USAGE: tonemap3 [-k kind] [-a amount] [-t type] [-c colormode] [-s shadows] [-h highlights] [-e edge] [-w window] [-S saturation] [-C colorspace] [-A] infile outfile
USAGE: tonemap3 [-help]

-k ... kind ......... apply non-linear enhancement; log or gamma; default=log
-a ... amount ....... amount of non-linear enhancement; float>0; default=4
-t ... type ......... type of extra processing; none (n), retinex (r),
..................... or space (s); default=retinex
-c ... colormode .... colormode; OHTA, YUV, YIQ, YCbCr, Rec709YCbCr;
..................... default=OHTA
-s ... shadows ...... increase/decrease percent brightness in shadows;
..................... positive or negative integer; default=0
-h ... highlights ... increase/decrease percent brightness in highlights;
..................... positive or negative integer; default=0
-e ... edge ......... edge sharpening amount; float>=0; nominally 0 to 2;
..................... default=1
-w ... window ....... window parameter for type=space; float>0; default=12.5
-S ... saturation ... saturation percent change; positive or negative integer;
..................... default=50
-C ... colorproc .... preprocessing to change colorspace to: RGB, sRGB;
..................... default is no change
-A .................. preprocessing to apply autolevel stretch; default is
..................... not to apply autolevel stretch

PURPOSE: Enhances the shadows and/or highlight regions in an image using a non-linear log or gamma function plus an extra processing function.

DESCRIPTION: TONEMAP3 enhances the shadows and/or highlight regions in an image using a non-linear log or gamma function plus an extra processing function, which can be either: a multiresolution retinex or space (spatially adaptive contrast enhancement). The a copy of the image is first processed by the non-linear function. Then it is converted to the desired colorspace and the channels separate. Then the channels are processed to enhance the saturation. Next a copy of the input image is converted to the same colorspace and the intensity (luminance) image is separate. The non-linear function is applied to it followed by the extra processing function and by the shadow/highlight enhancement and . edge sharpening. This last image is used to replace the intensity channel from the first processing of original image. Finally the 3 channels are recombined and converted back to RGB.

ARGUMENTS:

-k kind ... KIND of non-linear enhancement. Choices are log (l) or gamma (g). The log function is a scaled log whose scaling function is 10^amount. The gamma function is a power law whose exponent is the amount. The default=log

-a amount ... AMOUNT of non-linear enhancement. Values are float>0. Note that kind=gamma can process dark image with amounts greater than 1 or bright images with amounts less than 1. Whereas kind=log can only process dark images. The log amounts are exponents for a power of 10. For example a log amount of 3 is equivalent to 1000. Nominal amounts for the log are about 3 to 4. Nominal equivalent amounts for gamma are about twice those for the log, i.e. 6 to 8. The default=4

-t type ... TYPE of extra processing. The choices are: none (n), retinex (r) or space (s). Space is a spatially adaptive contrast enhancement and retinex is multiscale enhancement. Note that equalize was tested, but did not work well. Generally retinex works well with fewer artifacts. Space can work better for some images, but has more potential for ringing artifacts near high contrast edges. The default=retinex.

-c colormode ... COLORMODE is the colorspace in which processing is done. Values are OHTA, YUV, YIQ, YCbCr or Rec709YCbCr. There is some small difference between OHTA and the others, but very little if any between those others. OHTA is an approximation for a principle components analysis (PCA) also known as Karhunen Loeve transformation (KLT). The default=OHTA

-s shadows ... SHADOWS is the increase/decrease percent brightness in the shadows. Values are in range -100<=integer<=100. The default=0

-h highlights ... HIGHLIGHTS is the increase/decrease percent brightness in the highlights. Values are in range -100<=integer<=100. The default=0

-e edge ... EDGE is the edge sharpening amount. Values are floats>=0. Nominal values are between 0 and 2. The default=1

-w window ... WINDOW is the moving window percentage of image size for type=space. Values are floats>0 and are nominally between 5 and 20. Larger or smaller values can mitigate the ringing. Larger values narrow the ringing and smaller values broaden or diffues the ringing. The default=12.5

-S saturation ... SATURATION is the saturation percentage increase/decrease. Values are positive or negatative integers. The default=50

-C colorproc ... COLORPROC is an optional preprocessing step to convert the input image from some other colorspace to either RGB or sRGB. This seems to be needed for HDR Radiance images in XYZ colorspace (.hdr suffix) prior to a bug fix in .hdr images in IM 6.7.2.0. The choices are: RGB and sRGB. The default is no change. Note that somewhere between IM 6.7.5.5 and IM 6.7.6.7, colorspace RGB and sRGB were swapped to correct their meaning.

-A ... Optional AUTOLEVEL preprocessing step. Generally this will not be needed, especially for HDR image with very high dynamic range that require processing in IM HDRI mode. Using it on such images generally cause changes in color or causes the images to become dark.

REQUIREMENTS: space and retinex scripts. Also IM 6.5.9-0 to support the -brightness-contrast function.

NOTE: type=retinex will be slow due to the use of -fx for IM less than 6.4.2-1. type=space will be slow due to the use of -fx when not in HDRI mode.

Note: For IM 6.7.5.5 or higher, in order to reproduce some of the examples below, one may have to add, remove or change -C arguments, due to the swap of the meaning of -colorspace RGB and -colorspace sRGB. Also if -c is not none for .hdr images, then some parameter changes may be needed. For more details, see http://www.fmwconcepts.com/imagemagick/tonemap3/tonemap_tests.txt

References:
http://biblion.epfl.ch/EPFL/theses/2006/3588/EPFL_TH3588.pdf (see page 33)
http://en.wikipedia.org/wiki/Principal_component_analysis
http://www.sciencedirect.com/science/article/pii/0146664X80900477

CAVEAT: No guarantee that this script will work on all platforms, nor that trapping of inconsistent parameters is complete and foolproof. Use At Your Own Risk.


EXAMPLES

(Processed With Q16 HDRI IM Compile)

Note: Over time there have been changes to IM. Therefore, some examples now are better and some worse. So some arguments may need changing, but may not fix all the examples. Also -C sRGB or RGB will need swapping on current versions of IM.


Example 1 -- variation in type -- OHTA vs YUV

Original Displayed As JPEG
(Actual EXR Image Used)
(source image web site)

Arguments:
-t none -s -15 -h -10 -e 2 -S 0.5 -c OHTA

Arguments:
-t none -s -10 -h -10 -e 2 -S 0.5 -c YUV

Arguments:
-t retinex -s 0 -h -10 -e 1 -S 0.5 -c OHTA

Arguments:
-t retinex -s 0 -h -10 -e 1 -S 0.5 -c YUV

Arguments:
-t space -s -10 -h -10 -e 1 -S 0.5 -c OHTA

Arguments:
-t space -s -10 -h -10 -e 1 -S 0.5 -c YUV



Example 2 -- variation in type -- OHTA vs YUV

Original Displayed As JPEG
(Actual EXR Image Used)
(source image web site)

Arguments:
-t none -s 30 -h -10 -e 2 -S 50 -c OHTA

Arguments:
-t none -s 30 -h -10 -e 2 -S 50 -c YUV

Arguments:
-t retinex -s 10 -h -10 -e 1 -S 50 -c OHTA

Arguments:
-t retinex -s 10 -h -10 -e 1 -S 50 -c YUV

Arguments:
-t space -s 30 -h -20 -e 2 -S 50 -w 5 -c OHTA

Arguments:
-t space -s 30 -h -20 -e 2 -S 50 -w 5 -c YUV



Example 3 -- variation in type -- OHTA vs YUV

Original Displayed As JPEG
(Actual EXR Image Used)
(source image web site)

Arguments:
-t none -s 30 -h -10 -e 2 -S 50 -c OHTA

Arguments:
-t none -s 30 -h -10 -e 2 -S 50 -c YUV

Arguments:
-t retinex -s 10 -h 0 -e 1 -S 50 -c OHTA

Arguments:
-t retinex -s 10 -h 0 -e 1 -S 50 -c YUV

Arguments:
-t space -s 30 -h -10 -e 1 -S 50 -w 40 -c OHTA

Arguments:
-t space -s 30 -h -10 -e 1 -S 50 -w 40 -c YUV



Example 4 -- variation in type -- OHTA vs YUV

Original Displayed As JPEG
(Actual EXR Image Used)
(source image web site)

Arguments:
-t none -s 10 -h -10 -e 2 -S 50 -c OHTA

Arguments:
-t none -s 10 -h -10 -e 2 -S 50 -c YUV

Arguments:
-t retinex -s -10 -h -10 -e 1 -S 50 -c OHTA

Arguments:
-t retinex -s -10 -h -10 -e 1 -S 50 -c YUV

Arguments:
-t space -s 10 -h 0 -e 1 -S 50 -w 20 -c OHTA

Arguments:
-t space -s 10 -h 0 -e 1 -S 50 -w 20 -c YUV



Example 4 -- variation in type -- OHTA vs YUV -- sRGB

Original Displayed As JPEG
(Actual HDR Image Used)
(source image web site)

Arguments:
-t none -s -30 -h -15 -e 2 -S 50 -c OHTA -C sRGB

Arguments:
-t none -s -30 -h -15 -e 2 -S 50 -c YUV -C sRGB

Arguments:
-t retinex -s 20 -h 0 -e 1 -S 50 -c OHTA -C sRGB

Arguments:
-t retinex -s 20 -h 0 -e 1 -S 50 -c YUV -C sRGB

Arguments:
-t space -s -30 -h -20 -e 1 -S 50 -c OHTA -C sRGB

Arguments:
-t space -s -30 -h -20 -e 1 -S 50 -c YUV -C sRGB



Example 5 -- variation in type -- OHTA vs YUV -- RGB

Original Displayed As JPEG
(Actual HDR Image Used)
(source image web site)

Arguments:
-t none -s 5 -h -10 -e 2 -S 50 -c OHTA -C RGB

Arguments:
-t none -s 5 -h -10 -e 2 -S 50 -c YUV -C RGB

Arguments:
-t retinex -s 20 -h 0 -e 1 -S 50 -c OHTA -C RGB

Arguments:
-t retinex -s 20 -h 0 -e 1 -S 50 -c YUV -C RGB

Arguments:
-t space -s 20 -h -10 -e 1 -S 50 -c OHTA -C RGB

Arguments:
-t space -s 20 -h -10 -e 1 -S 50 -c YUV -C RGB



Example 5 -- OHTA w/ RGB prior to IM 6.7.2.0 vs OHTA w/o RGB IM 6.7.2.0

Original Displayed As JPEG
(Actual HDR Image Used)
(source image web site)

Arguments:
(before IM 6.7.2.0)
-t retinex -s 20 -h 0 -e 1 -S 50 -c OHTA -C RGB

Arguments:
(at or after IM 6.7.2.0)
-t retinex -s 20 -h 0 -e 1 -S 50 -c OHTA



Example 6 -- OHTA -- Retinex vs Space -- Post .hdri bug fix IM 6.7.2.0

Original Displayed As JPEG
(Actual HDR Image Used)
(source image web site)
(NOTE: Processed after .hdr bug fix at IM 6.7.2.0)

Arguments:
-t retinex -s -30 -h 10 -e 2 -S 50 -c OHTA -C sRGB -A

Arguments:
-t space -s 30 -h 20 -e 2 -S 50 -c OHTA -C sRGB -A



What the script does is as follows for kind=retinex:

  • Processes the image with the non-linear enhancement,
    converts to the desired colorspace and separates channels
  • Takes the original image and converts to the desired
    colorspace and separates out the intensity-like channel
  • Applies the non-linear enhancement to the intensity-like
    channel, followed by the extra processing step, followed
    by shadow/highlight enhancement, followed by edge sharpening
  • Combines this modified intensity-like channel with the processed
    other two channels from the first step, then converts to RGB

This is equivalent to the following IM commands for kind=retinex:

  • if [ "$cspace" = "none" ]; then
    cproc=""
    else
    cproc="-set colorspace $cspace"
    fi
  • if [ "$alevel" = "yes" ]; then
    aproc="-auto-level"
    else
    aproc=""
    fi
  • convert -quiet -regard-warnings "$infile" -alpha off $cproc $aproc +repage "$tmpA1"
  • if [ "$kind" = "log" ]; then
    amount=`convert xc: -precision 8 -format "%[fx:10^$amount]" info:`
    proc0="-evaluate log $amount"
    elif [ "$kind" = "gamma" ]; then
    proc0="-gamma $amount"
    fi
  • ssign=`convert xc: -format "%[fx:sign($shadows)==-1?1:0]" info:`
  • hsign=`convert xc: -format "%[fx:sign($highlights)==-1?1:0]" info:`
  • mlo=0
  • mhi=100
  • plo=0
  • phi=100
  • if [ "$shadows" != "0" -a $ssign -eq 1 ]; then
    mlo=$((-shadows))
    elif [ "$shadows" != "0" -a $ssign -eq 0 ]; then
    plo=$shadows
    fi
  • if [ "$highlights" != "0" -a $hsign -eq 1 ]; then
    phi=$((100+highlights))
    elif [ "$highlights" != "0" -a $hsign -eq 0 ]; then
    mhi=$((100-highlights))
    fi
  • if [ $mlo -eq 0 -a $mhi -eq 100 ]; then
    proc1=""
    else
    proc1="-level $mlo,$mhi%"
    fi
  • if [ $plo -eq 0 -a $phi -eq 100 ]; then
    proc2=""
    else
    proc2="+level $plo,$phi%"
    fi
  • if [ "$sat" = "0" ]; then
    saturation=""
    else
    saturation="-brightness-contrast 0,$sat"
    fi
  • if [ "$edge" = "0" ]; then
    eproc=""
    else
    eproc="-sharpen 0x$edge"
    fi
  • if [ "$type" = "none" ]; then
    tproc=""
    elif [ "$type" = "space" ]; then
    tproc="space -m 0 -w $window -g 5"
    elif [ "$type" = "retinex" ]; then
    tproc="retinex"
    fi
  • convert $tmpA1 $proc0 -colorspace $colormode -separate +channel $saturation $tmpS1
  • convert $tmpA1 -colorspace $colormode -channel R -separate +channel $proc0 $tmpI1
  • $tproc $tmpI1 $tmpI1
  • convert \( $tmpI1 $proc1 $proc2 $eproc \) $tmpS1[1] $tmpS1[2] \
    -set colorspace $colormode -combine -colorspace RGB \
    $outfile