snibgo's ImageMagick pages

[Adaptive] Contrast-limited equalisation

Equalising an image is often useful, but can uglify photographs. When the contrast introduced by equalisation is limited, results are more pleasing. The process can be adapted across the image.

This page builds on concepts developed in Blending tiles and Adaptive auto level and gamma

Scripts on this page assume that the version of ImageMagick in %IM7DEV% has been built with various process modules. See Process modules.

This page also experiments with a technique that makes an image's histogram Gaussian, ie bell-shaped.

An ImageMagick bug in version 6.9.1-6 causes "histogram:" images to be of MIFF format, even though they are named ".PNG". See bug report Histogram images. So I use an older version of IM for that task:

set IMH=%IMG691%

See:

  • Adaptive Histogram Equalization and Its Variations, Pizer et al, 1986.
  • Sample input files

    This page uses two sample input files. They were both created by dcraw from 14-bit NEF files from a Nikon D800 camera, with gammas that maximised the standard deviation.

    All operations are performed on the full-size images, but smaller versions are made for the web.

    set IMH=%IM%
    set WEB_SIZE=-resize 600x600 -quality 40
    
    set SRC1=eql_src1.tiff
    
    if not exist %SRC1% %IMG7%magick ^
      %PICTLIB%20130713\AGA_1372_sRGB.tiff ^
      -crop 5120x4840+0+0 +repage ^
      %SRC1%
    
    %IMG7%magick ^
      %SRC1% ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src1_hist.png ^
      %WEB_SIZE% ^
      eql_src1_sm.jpg
    eql_src1_sm.jpg eql_src1_hist.png
    set SRC2=eql_src2.tiff
    
    if not exist %SRC2% %IMG7%magick ^
      %PICTLIB%20141203\AGA_2159_gms.tiff ^
      -crop 5684x4864+1100+60 +repage ^
      %SRC2%
    
    %IMG7%magick ^
      %SRC2% ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src2_hist.png ^
      %WEB_SIZE% ^
      eql_src2_sm.jpg

    This very high contrast scene has clipped,
    before we do any processing.

    eql_src2_sm.jpg eql_src2_hist.png

    Simple equalisation

    IM's "-equalization" is a useful first-pass tool for seeing what an image contains. It spreads the values equally so the same number of pixels are around 1% as around 50%. As photographs tend to have bell-shaped histograms, this increases the contrast in the centre, and decreases contrast in both shadows and highlights.

    %IMG7%magick ^
      %SRC1% ^
      -equalize ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src1_eq_hist.png ^
      %WEB_SIZE% ^
      eql_src1_eq_sm.jpg

    Looks horrible. Shadows have clipped.

    eql_src1_eq_sm.jpg eql_src1_eq_hist.png
    %IMG7%magick ^
      %SRC2% ^
      -equalize ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src2_eq_hist.png ^
      %WEB_SIZE% ^
      eql_src2_eq_sm.jpg

    Looks okay. Highlights are clipped.

    eql_src2_eq_sm.jpg eql_src2_eq_hist.png

    Aesthetically, I like the result from the second image but not the first.

    The difficulty with the first image is the narrow peak, with few pixels in the shadows or hightlights. This results in many pixels being pushed into the shadows and highlights.

    Equalising tones

    We can equalise just the Lightness channel of the image in Lab colour space.

    %IMG7%magick ^
      %SRC1% ^
      -colorspace Lab -channel R ^
      -equalize ^
      +channel -colorspace sRGB ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src1_eqt_hist.png ^
      %WEB_SIZE% ^
      eql_src1_eqt_sm.jpg
    eql_src1_eqt_sm.jpg eql_src1_eqt_hist.png
    %IMG7%magick ^
      %SRC2% ^
      -colorspace Lab -channel R ^
      -equalize ^
      +channel -colorspace sRGB ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src2_eqt_hist.png ^
      %WEB_SIZE% ^
      eql_src2_eqt_sm.jpg
    eql_src2_eqt_sm.jpg eql_src2_eqt_hist.png

    The results look somewhat artificial, with a good spread of tones but not of colours. The first image looks like a black and white photograph that has been coloured by hand.

    Equalisation without clipping

    We can fairly easily prevent clipping.

    The script equSlope.bat takes an image, makes a histogram, calls equSlopeH.bat to process it, and applies the returned cumulative histogram as a clut to the image.

    The script equSlopeH.bat takes a histogram and makes a cumulative histogram with specified toe and highlight slopes.

    Sensible values for the four numeric parameters come from an examination of the histograms. FUTURE: I may write something to automate this. (A de-clipping script would also be useful.)

    This doesn't remove clipping that has already occurred. It merely reduces or eliminates clipping caused by equalisation.

    set eqshDEBUG=1
    call %PICTBAT%equSlope %SRC1% 10 50 20 95
    
    %IMG7%magick ^
      %eqsOUTFILE% ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src1_eqs_hist.png ^
      %WEB_SIZE% ^
      eql_src1_eqs_sm.jpg

    There is no clipping.

    eql_src1_eqs_sm.jpg eql_src1_eqs_hist.png
    call %PICTBAT%equSlope %SRC2% 2 98
    set eqshDEBUG=
    
    %IMG7%magick ^
      %eqsOUTFILE% ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src2_eqs_hist.png ^
      %WEB_SIZE% ^
      eql_src2_eqs_sm.jpg

    Looks okay. It doesn't remove clipping that is already present.

    eql_src2_eqs_sm.jpg eql_src2_eqs_hist.png

    Contrast-limited equalisation

    The script eqLimit.bat applies an equalisation to an image. It works by creating the histogram of the image, cumulating the histogram, and using this as a clut on the image. It usually limits the increase in contrast by capping the height of the histogram, and redistributing those counts between all the buckets, and repeating until the amount redistributed is less than or equal to 1%. (This threshold is modifiable: eqlDIFF_LIMIT.)

    The parameter %2 is a standard deviation factor, sd_fact. It caps the height of the histogram to (mean + sd_fact * standard-deviation), and hence limits the slope of the clut, which in turn limits the increase in contrast.

    This is the "contrast-limited" part of the process. It doesn't reduce or limit the contrast of the image. Rather, it limits the increase of contrast caused by equalisation.

    The default value for %2 is 1.0, which seems good for most photographs, including those with a small mean. Setting it to 0.0 would limit the histogram to its mean, resulting in a small shift in contrast, so there is almost no equalisation. Setting it to a high value such as 9999 will mean (for ordinary photographs) there is no contrast limit, and the result is a conventional equalisation. I find that values between 0.0 and 3.0 are useful.

    For example:

    A tight limit, 0.5.

    call %PICTBAT%eqLimit %SRC1% 0.5 . . eql_src1_0_5.tiff
    
    %IMG7%magick ^
      eql_src1_0_5.tiff ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src1_0_5_hist.png ^
      %WEB_SIZE% ^
      eql_src1_0_5_sm.jpg
    eql_src1_0_5_sm.jpg eql_src1_0_5_hist.png

    A looser limit, 2.0, gives a greater increase in contrast.

    call %PICTBAT%eqLimit %SRC1% 2.0 . . eql_src1_2_0.tiff
    
    %IMG7%magick ^
      eql_src1_2_0.tiff ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src1_2_0_hist.png ^
      %WEB_SIZE% ^
      eql_src1_2_0_sm.jpg

    The greater contrast has increased the saturation.

    eql_src1_2_0_sm.jpg eql_src1_2_0_hist.png

    Both images, with default parameters to the script:

    set eqlDEBUG=1
    
    call %PICTBAT%eqLimit %SRC1% . . . eql_src1_cle.tiff
    
    %IMG7%magick ^
      eql_src1_cle.tiff ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src1_cle_hist.png ^
      %WEB_SIZE% ^
      eql_src1_cle_sm.jpg
    eql_src1_cle_sm.jpg eql_src1_cle_hist.png
    call %PICTBAT%eqLimit %SRC2% . . . eql_src2_cle.tiff
    
    %IMG7%magick ^
      eql_src2_cle.tiff ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src2_cle_hist.png ^
      %WEB_SIZE% ^
      eql_src2_cle_sm.jpg
    
    set eqlDEBUG=
    eql_src2_cle_sm.jpg eql_src2_cle_hist.png

    Aesthetically, I like both results. The skin tones and colours look natural.

    For the first image, the capped and normalised histogram from the input is:

    eql_src1_cle_eql_gch.png

    This histogram is the same as the first histogram shown at the top of this page, but with all three channels shown together, and capped.

    This histogram is cumulated, and this is used as a clut:

    eql_src1_cle_eql_gchc_clhe_red.png

    The bottom-left of this clut is nearly flat, so it will darken shadows.

    Tweaking shadows and highlights

    Two parameters to the eqLimit.bat script allow us to increase the contrast in the shadows or highlights.

    %3 is LIFT_SHADOW_PC, the percentage to raise the shadow area of the input histogram, before cumulating it.

    set eqlDEBUG=1
    
    call %PICTBAT%eqLimit %SRC1% . 75 . eql_src1_cles.tiff
    
    %IMG7%magick ^
      eql_src1_cles.tiff ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src1_cles_hist.png ^
      %WEB_SIZE% ^
      eql_src1_cles_sm.jpg
    eql_src1_cles_sm.jpg eql_src1_cles_hist.png

    The "75" parameter creates a shoulder at the shadow end of the input histogram curve, at 75% of the height, so the histogram becomes:

    eql_src1_cles_eql_gch.png

    This shoulder steepens the start of the cumulated slope, which increases shadow contrast by lightening dark pixels without significantly changing the brightness of the rest of the image:

    eql_src1_cles_eql_gchc_clhe_red.png

    ASIDE: the script eqLimit.bat finds the first histogram entry that is above 75%. But this histogram is "combed", eg it has entries that alternate between 0 and 100% when these really represent 50%. The script "decombs" the histogram, rather crudely, by blurring.

    Similarly, we can increase the contrast in the highlights, or "drop the highlights", by raising the right-side of the histogram by 5% with a "drop-highlight" parameter:

    set eqlDEBUG=1
    
    call %PICTBAT%eqLimit %SRC1% . 75 5 eql_src1_clesh.tiff
    
    %IMG7%magick ^
      eql_src1_clesh.tiff ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src1_clesh_hist.png ^
      %WEB_SIZE% ^
      eql_src1_clesh_sm.jpg
    eql_src1_clesh_sm.jpg eql_src1_clesh_hist.png

    So the histogram is:

    eql_src1_clesh_eql_gch.png

    And the cumulated slope is:

    eql_src1_clesh_eql_gchc_clhe_red.png

    Some points about the "lift-shadow" and "drop-highlight" parameters:

    1. In our example, 5% at the highlights has a similar effect to 75% at the shadows. This is because the input image is dark; its histogram is skewed to the left.
    2. While the contrast-limit aspect generally reduces the maximum contrast, the two parameters increase the contrast in their areas, though never to more than the limit.
    3. As the two parameters raise the contrast in those areas, they reduce the contrast in the mid-tones.
    4. If the lift-shadow is given and input doesn't stretch down to black, neither will the output.
    5. If the drop-highlight is given and input doesn't stretch up to white, neither will the output.
    6. If either parameter is greater than 100, all buckets of the histogram are set to 100%, the cumulation becomes a linear no-op, and the image will not be transformed.

    FUTURE: It may be more natural to specify shadow and highlight modification more directly as a tweak to the clut, eg "add a 1 in 2 gradient to the shadow portion until this intersects the existing curve."

    Contrast-limited adaptive equalisation

    This is also called "contrast-limited adaptive histogram equalisation", CLAHE.

    As with Adaptive auto level and gamma, we can blend either in 2x2 tiles with blending across the entire image (script eqlQtr.bat), or any number of tiles with blending between centres (script eqlTile.bat).

    eqlQtr.bat takes the same parameters as eqLimit.bat above:

    Adaptive equalisation takes the data from a smaller area so gives greater local contrast than non-adaptive. For the first image, this darkens the shadows by too much, so I use %3=80.

    The adaptive scripts work by dividing the image into tiles, calling eqLimit.bat for each tile to calculate the clut, then applying each clut to a copy of the full image, and finally blending the versions together.

    The blending for eqlQtr.bat is simple, so is done within a magick command. For eqlTile.bat, the blending is more complex so is done by calling the script blendTile.bat.

    call %PICTBAT%eqlQtr %SRC1% . 80 . eql_src1_eqlq.tiff
    
    %IMG7%magick ^
      %eqlqOUTFILE% ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src1_eqlq_hist.png ^
      %WEB_SIZE% ^
      eql_src1_eqlq_sm.jpg

    This is good. The figures pop out, even with no added saturation or sharpening.

    eql_src1_eqlq_sm.jpg eql_src1_eqlq_hist.png
    call %PICTBAT%eqlQtr %SRC2% . . . eql_src2_eqlq.tiff
    
    %IMG7%magick ^
      %eqlqOUTFILE% ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src2_eqlq_hist.png ^
      %WEB_SIZE% ^
      eql_src2_eqlq_sm.jpg

    This is also good.

    eql_src2_eqlq_sm.jpg eql_src2_eqlq_hist.png

    eqlTile.bat takes two more parameters: the number of tiles horizontally and vertically.

    call %PICTBAT%eqlTile %SRC1% 1.0 99 2 . . eql_src1_eqlt.tiff
    
    %IMG7%magick ^
      %eqltOUTFILE% ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src1_eqlt_hist.png ^
      %WEB_SIZE% ^
      eql_src1_eqlt_sm.jpg

    Good, though the face on the left is in darker shadow than the previous version.

    eql_src1_eqlt_sm.jpg eql_src1_eqlt_hist.png
    call %PICTBAT%eqlTile %SRC2% 0.8 . . . . eql_src2_eqlt.tiff
    
    %IMG7%magick ^
      %eqltOUTFILE% ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_src2_eqlt_hist.png ^
      %WEB_SIZE% ^
      eql_src2_eqlt_sm.jpg

    Good.
    Compared to the previous version,
    contrast has increased within the tree and within the pavement.
    Perhaps this is too distracting, for this image.

    eql_src2_eqlt_sm.jpg eql_src2_eqlt_hist.png

    My conclusion is that adaptive equalisation with eqlQtr.bat and eqlTile.bat gives great results, but needs care to prevent local contrast from becoming too strong.

    For fully automated processing, eqLimit.bat is a good choice.

    Make histogram Gaussian

    For comparison with equalisation techniques, we can change the histogram to be a Gaussian curve.

    To show this working, we make an image with Gaussian-distributed noise, then equalise the source's histogram to this using the matchHisto.bat script.

    %IMG7%magick ^
      -size 500x400 ^
      xc:gray50 ^
      -attenuate 2.0 ^
      +noise Gaussian ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_noise_hist.png ^
      eql_noise.png

    The histogram shows the inevitable clipping at both ends.

    eql_noise.pngjpg eql_noise_hist.png
    call %PICTBAT%matchHisto ^
      %SRC1% eql_noise.png eql_match_noise.tiff
    
    %IMG7%magick ^
      eql_match_noise.tiff ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_match_noise_hist.png ^
      %WEB_SIZE% ^
      eql_match_noise_sm.jpg

    The histogram is practically perfect (including the clipping).
    This has caused colour-shifts that are especially horrible in skin tone.

    eql_match_noise_sm.jpg eql_match_noise_hist.png

    Make the lightness a Gaussian distribution.

    set mhCOL_SP_IN=-colorspace Lab -channel R
    set mhCOL_SP_OUT=+channel -colorspace sRGB
    
    call %PICTBAT%matchHisto ^
      %SRC1% eql_noise.png eql_match_noise2.tiff
    
    set mhCOL_SP_IN=
    set mhCOL_SP_OUT=
    
    %IMG7%magick ^
      eql_match_noise2.tiff ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_match_noise2_hist.png ^
      %WEB_SIZE% ^
      eql_match_noise2_sm.jpg

    The RGB histograms are not perfect, but we have no colour-shifts.

    The result isn't great, but is acceptable first-pass automatic processing.

    eql_match_noise2_sm.jpg eql_match_noise2_hist.png
    set mhCOL_SP_IN=-colorspace Lab -channel R
    set mhCOL_SP_OUT=+channel -colorspace sRGB
    
    call %PICTBAT%matchHisto %SRC2% ^
      eql_noise.png eql_match_s2_noise2.tiff
    
    set mhCOL_SP_IN=
    set mhCOL_SP_OUT=
    
    %IMG7%magick ^
      eql_match_s2_noise2.tiff ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_match_s2_noise2_hist.png ^
      %WEB_SIZE% ^
      eql_match_s2_noise2_sm.jpg

    The RGB histograms are not perfect, but we have no colour-shifts.

    The result isn't great, but is acceptable first-pass automatic processing.

    eql_match_s2_noise2_sm.jpg eql_match_s2_noise2_hist.png

    We can do this operation more directly, without the noise image.

    %IM7DEV%magick ^
      ( %SRC1% ^
        -process 'mkhisto cumul norm' ^
        +depth +write eql_w_i1_chist.miff ^
        +delete ^
      ) ^
      ( xc: ^
        -process ^
          'mkgauss width 65536 sd 20%% zeroize cumul norm' ^
        -delete 0 ^
        -process 'mkhisto cumul norm' ^
        +write eql_gauss.miff ^
      ) ^
      NULL:
    
    call %PICTBAT%graphLineCol ^
      eql_w_i1_chist.miff . . . eql_w_i1_chist_glc.png
    
    call %PICTBAT%graphLineCol ^
      eql_gauss.miff . . . eql_gauss_glc.png
    eql_w_i1_chist_glc.png eql_gauss_glc.png
    %IMG7%magick ^
      eql_w_i1_chist.miff ^
      eql_gauss.miff ^
      -clut ^
      eql_w_t_ixt.miff
    
    call %PICTBAT%graphLineCol ^
      eql_w_t_ixt.miff . . . eql_w_t_ixt_glc.png
    eql_w_t_ixt_glc.png
    %IMG7%magick ^
      %SRC1% ^
      eql_w_t_ixt.miff ^
      -clut ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_match_gauss_hist.png ^
      %WEB_SIZE% ^
      eql_match_gauss_sm.jpg

    Again, we have a colour shift.

    eql_match_gauss_sm.jpg eql_match_gauss_hist.png

    To avoid colour shift, we find the histogram of the source's L channel (of Lab), and we clut only the L channel.

    %IM7DEV%magick ^
      ( %SRC1% ^
        -colorspace LAB -channel R -separate -set colorspace sRGB ^
        -process 'mkhisto cumul norm' ^
        +depth +write eql_w_i1_L_chist.miff ^
        +delete ^
      ) ^
      ( xc: ^
        -process ^
          'mkgauss width 65536 sd 20%% zeroize cumul norm' ^
        -delete 0 ^
        -process 'mkhisto cumul norm' ^
        +write eql_gauss.miff ^
      ) ^
      NULL:
    
    call %PICTBAT%graphLineCol ^
      eql_w_i1_L_chist.miff . . . eql_w_i1_L_chist_glc.png
    
    call %PICTBAT%graphLineCol ^
      eql_gauss.miff . . . eql_gauss_glc.png
    eql_w_i1_L_chist_glc.png eql_gauss_glc.png
    %IMG7%magick ^
      eql_w_i1_L_chist.miff ^
      eql_gauss.miff ^
      -clut ^
      eql_w_t_L_ixt.miff
    
    call %PICTBAT%graphLineCol ^
      eql_w_t_L_ixt.miff . . . eql_w_t_L_ixt_glc.png
    eql_w_t_L_ixt_glc.png
    %IMG7%magick ^
      %SRC1% ^
      -colorspace Lab -channel R ^
      eql_w_t_L_ixt.miff ^
      -clut ^
      +channel -colorspace sRGB ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_match_gauss_L_hist.png ^
      %WEB_SIZE% ^
      eql_match_gauss_L_sm.jpg

    We have no colour shift.

    eql_match_gauss_L_sm.jpg eql_match_gauss_L_hist.png

    We put this into a script matchGauss.bat.

    call %PICTBAT%matchGauss %SRC1% eql_s1_mg.tiff
    
    %IMG7%magick ^
      %mgOUTFILE% ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_s1_mg_hist.png ^
      %WEB_SIZE% ^
      eql_s1_mg_sm.jpg
    eql_s1_mg_sm.jpg eql_s1_mg_hist.png
    call %PICTBAT%matchGauss %SRC2% eql_s2_mg.tiff
    
    %IMG7%magick ^
      %mgOUTFILE% ^
      -define histogram:unique-colors=false ^
      +write histogram:eql_s2_mg_hist.png ^
      %WEB_SIZE% ^
      eql_s2_mg_sm.jpg
    eql_s2_mg_sm.jpg eql_s2_mg_hist.png

    The match-Gaussian process could also limit the gain in contrast. However, as the source histograms are roughly Gaussian, the process doesn't increase contrast by much. Looking at the results, I can see no point in limiting contrast.

    An adaptive match-Gaussian process might be more useful.

    For auto-processing of photographs, matching the histogram to a Gaussian does not seem useful.

    Cleanup

    We don't need to keep all those large TIFF or MIFF files, so delete them.

    del %SRC1%
    del %SRC2%
    del eql_*_*.tiff
    del eql*.miff

    Scripts

    For convenience, .bat scripts are also available in a single zip file. See Zipped BAT files.

    equSlope.bat

    rem From image %1, makes other image
    rem using a cumulative histogram with specified slopes at shadow and highlight.
    rem
    rem %2 is percentage along x-axis for shadow slope. [0]
    rem %3 is percentage along x-axis for start of highlight slope. [100]
    rem %4 is percentage up y-axis for shadow slope. [same as %2]
    rem %5 is percentage up y-axis for start of highlight slope. [same as %3]
    rem %6 is optional output filename.
    @rem
    @rem Updated:
    @rem   27-July-2022 for IM v7.
    @rem
    
    
    @if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1
    
    @setlocal enabledelayedexpansion
    
    @call echoOffSave
    
    call %PICTBAT%setInOut %1 eqs
    
    if not "%6"=="" set OUTFILE=%6
    
    set TMP_HIST=%INNAME%_%sioCODE%_hist.miff
    
    %IM7DEV%magick ^
      %INFILE% ^
      -colorspace Gray ^
      -process 'mkhisto norm' ^
      %TMP_HIST%
    
    call %PICTBAT%equSlopeH %TMP_HIST% %2 %3 %4 %5
    
    %IM7DEV%magick ^
      %INFILE% ^
      %eqshOUTFILE% ^
      -clut ^
      %OUTFILE%
    
    goto end
    
    
    set AX=%2
    set BX=%3
    set AY=%4
    set BY=%5
    
    if "%AX%"=="." set AX=
    if "%BX%"=="." set BX=
    if "%AY%"=="." set AY=
    if "%BY%"=="." set BY=
    
    if "%AX%"=="" set AX=0
    if "%BX%"=="" set BX=100
    if "%AY%"=="" set AY=%AX%
    if "%BY%"=="" set BY=%BX%
    
    echo %AX% %BX% %AY% %BY%
    
    if not "%6"=="" set OUTFILE=%6
    
    for /F "usebackq" %%L in (`%IMG7%magick identify ^
      -format "Wm1=%%[fx:w-1]\nAXP=%%[fx:int(w*%AX%/100+0.5)]\nBXP=%%[fx:int(w*%BX%/100+0.5)]\nAXP2=%%[fx:w-int(w*%AX%/100+0.5)]\nBXP2=%%[fx:w-int(w*%BX%/100+0.5)]\n" ^
      %INFILE%`) do set %%L
    
    echo AXP=%AXP% BXP=%BXP% AXP2=%AXP2% BXP2=%BXP2%
    
    if %AX%==0 (
      set BKL=
      set WHR=
    ) else (
      set BKL=-size %AXP%x1 xc:#000 -gravity West -composite
      set WHR=-size %AXP2%x1 xc:#fff -gravity East -composite
    
      set G1=  ^( -clone 0 ^
        -sparse-color bilinear 0,0,#000,%Wm1%,0,#fff ^
        !WHR! ^
        +write G1.png ^
      ^) ^
      -evaluate-sequence Min
    
    )
    
    if %BX%==100 (
      set BKR=
      set WHL=
    ) else (
      set BKR=-size %BXP2%x1 xc:#000 -gravity East -composite
      set WHL=-size %BXP%x1 xc:#000 -gravity West -composite
    
      set G2=  ^( -clone 0 ^
        -sparse-color bilinear 0,0,#000,%Wm1%,0,#fff ^
        !WHL! ^
        +write G2.png ^
      ^) ^
      -evaluate-sequence Max
    
    )
    
    %IM7DEV%magick ^
      %INFILE% ^
      %BKL% ^
      %BKR% ^
      -process 'cumulhisto norm' ^
      +level %AY%%%,%BY%%% ^
      %G1% ^
      %G2% ^
      %OUTFILE%
    
    call %PICTBAT%graphLineCol %OUTFILE%
    
    
    :end
    
    call echoRestore
    
    @endlocal & set eqsOUTFILE=%OUTFILE%

    equSlopeH.bat

    rem From %1 a histogram,
    rem makes a cumulative histogram but with specified slopes at shadow and highlight.
    rem
    rem %2 is percentage along x-axis for shadow slope. [0]
    rem %3 is percentage along x-axis for start of highlight slope. [100]
    rem %4 is percentage up y-axis for shadow slope. [same as %2]
    rem %5 is percentage up y-axis for start of highlight slope. [same as %3]
    rem %6 is optional output filename.
    @rem
    @rem Updated:
    @rem   27-July-2022 for IM v7.
    @rem
    
    
    @if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1
    
    @setlocal enabledelayedexpansion
    
    @call echoOffSave
    
    call %PICTBAT%setInOut %1 eqsh
    
    set AX=%2
    set BX=%3
    set AY=%4
    set BY=%5
    
    if "%AX%"=="." set AX=
    if "%BX%"=="." set BX=
    if "%AY%"=="." set AY=
    if "%BY%"=="." set BY=
    
    if "%AX%"=="" set AX=0
    if "%BX%"=="" set BX=100
    if "%AY%"=="" set AY=%AX%
    if "%BY%"=="" set BY=%BX%
    
    rem echo %AX% %BX% %AY% %BY%
    
    if not "%6"=="" set OUTFILE=%6
    
    for /F "usebackq" %%L in (`%IMG7%magick identify ^
      -format "Wm1=%%[fx:w-1]\nAXP=%%[fx:int(w*%AX%/100+0.5)]\nBXP=%%[fx:int(w*%BX%/100+0.5)]\nAXP2=%%[fx:w-int(w*%AX%/100+0.5)]\nBXP2=%%[fx:w-int(w*%BX%/100+0.5)]\n" ^
      %INFILE%`) do set %%L
    
    rem echo AXP=%AXP% BXP=%BXP% AXP2=%AXP2% BXP2=%BXP2%
    
    if "%eqshDEBUG%"=="1" (
      set WR_G1=+write %~n1_G1.png
      set WR_G2=+write %~n1_G2.png
    ) else (
      set WR_G1=
      set WR_G2=
    )
    
    if %AX%==0 (
      set BKL=
      set G1=
    ) else (
      set BKL=-size %AXP%x1 xc:#000 -gravity West -composite
    
      set G1=^( -size %AXP%x1 gradient:black-gray^(%AY%%%^) ^
        -size %AXP2%x1 xc:#fff  ^
        +append ^
        %WR_G1% ^
      ^) ^
      -evaluate-sequence Min
    
    )
    
    if %BX%==100 (
      set BKR=
      set G2=
    ) else (
      set BKR=-size %BXP2%x1 xc:#000 -gravity East -composite
    
      set G2=^( -size %BXP%x1 xc:#000 ^
        -size %BXP2%x1 gradient:gray^(%BY%%%^)-white ^
        +append ^
        %WR_G2% ^
      ^) ^
      -evaluate-sequence Max
    
    )
    
    %IM7DEV%magick ^
      %INFILE% ^
      -set colorspace sRGB ^
      -compose Over ^
      %BKL% ^
      %BKR% ^
      -process 'cumulhisto norm' ^
      +level %AY%%%,%BY%%% ^
      %G1% ^
      %G2% ^
      %OUTFILE%
    
    if "%eqshDEBUG%"=="1" (
      call %PICTBAT%graphLineCol %OUTFILE%
      call %PICTBAT%graphLineCol %~n1_G1.png
      call %PICTBAT%graphLineCol %~n1_G2.png
    )
    
    call echoRestore
    
    @endlocal & set eqshOUTFILE=%OUTFILE%

    eqLimit.bat

    rem From image %1,
    rem make contrast-limited histogram-equalised (with iterative redistribution) version.
    @rem
    @rem Optional parameters:
    @rem   %2 is limiting factor SD_FACT, so limit = mean + SD_FACT * standard_deviation.
    @rem        Default 1.
    @rem   %3 is percentage lift for shadows. Maximum < 100. Default 0, no lift.
    @rem   %4 is percentage drop for highlights. Maximum < 100. Default 0, no drop.
    @rem   %5 is output file, or null: for no output.
    @rem
    @rem Can also use:
    @rem   eqlDEBUG if 1, also creates curve histograms.
    @rem   eqlDIFF_LIMIT iteration stops when the count redistributed is less than this percentage.
    @rem     Set to a value >= 100 to prevent iteration.
    @rem     Default 1.0.
    @rem   eqlSUPPRESS_OUT if 1, suppresses output.
    @rem
    @rem Updated:
    @rem   26-July-2022 for IM v7.
    @rem
    
    
    @if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1
    
    @setlocal enabledelayedexpansion
    
    @call echoOffSave
    
    call %PICTBAT%setInOut %1 eql
    
    set SD_FACT=%2
    if "%SD_FACT%"=="." set SD_FACT=
    if "%SD_FACT%"=="" set SD_FACT=1
    
    set LIFT_SHADOW_PC=%3
    if "%LIFT_SHADOW_PC%"=="." set LIFT_SHADOW_PC=
    if "%LIFT_SHADOW_PC%"=="" set LIFT_SHADOW_PC=0
    
    set DROP_HIGHLIGHT_PC=%4
    if "%DROP_HIGHLIGHT_PC%"=="." set DROP_HIGHLIGHT_PC=
    if "%DROP_HIGHLIGHT_PC%"=="" set DROP_HIGHLIGHT_PC=0
    
    if not "%5"=="" set OUTFILE=%5
    
    if "%5"=="" (
      set EQL_BASE=%~n1_%sioCODE%
    ) else (
      set EQL_BASE=%~n5_%sioCODE%
    )
    
    if "%eqlDIFF_LIMIT%"=="" set eqlDIFF_LIMIT=1
    
    set TMPEXT=miff
    
    for /F "usebackq" %%L in (`cygpath %TEMP%`) do set CYGTEMP=%%L
    
    %IM7DEV%magick ^
      %INFILE% ^
      -colorspace Lab -channel R -separate -set colorspace sRGB ^
      -process 'mkhisto norm' ^
      %CYGTEMP%\%EQL_BASE%_gch.%TMPEXT%
    
    if ERRORLEVEL 1 exit /B 1	
    
    for /F "usebackq" %%L in (`%IMG7%magick ^
      %TEMP%\%EQL_BASE%_gch.%TMPEXT% ^
      -precision 15 ^
      -format "histcap=%%[fx:(mean+%SD_FACT%*standard_deviation)*100]" ^
      info:`) do set %%L
    
    echo %0: histcap=%histcap% 
    
    
    set nIter=0
    :loop
    
    %IM7DEV%magick ^
      %CYGTEMP%\%EQL_BASE%_gch.%TMPEXT% ^
      -channel RGB ^
      -evaluate Min %histcap%%% ^
      +channel ^
      %CYGTEMP%\%EQL_BASE%_gchc_cap.%TMPEXT%
    
    for /F "usebackq" %%L in (`%IMG7%magick ^
      %TEMP%\%EQL_BASE%_gch.%TMPEXT% ^
      %TEMP%\%EQL_BASE%_gchc_cap.%TMPEXT% ^
      -compose MinusSrc -composite ^
      -precision 15 ^
      -format "MeanDiffPC=%%[fx:mean*100]" ^
      info:`) do set %%L
    
    echo %0: MeanDiffPC=%MeanDiffPC%
    
    %IM7DEV%magick ^
      %CYGTEMP%\%EQL_BASE%_gch.%TMPEXT% ^
      -channel RGB ^
      -evaluate Min %histcap%%% ^
      +channel ^
      -evaluate Add %MeanDiffPC%%% ^
      %CYGTEMP%\%EQL_BASE%_gch.%TMPEXT%
    
    for /F "usebackq" %%L in (`%IMG7%magick identify ^
      -format "DO_LOOP=%%[fx:%MeanDiffPC%>%eqlDIFF_LIMIT%?1:0]" ^
      xc:`) do set %%L
    
    rem If max(eql_gch) > histcap + epsilon, repeat.
    rem OR
    rem if %MeanDiffPC% > epsilon, repeat
    
    set /A nIter+=1
    
    if %DO_LOOP%==1 goto loop
    
    echo %0: nIter=%nIter%
    
    
    if %LIFT_SHADOW_PC%==0 if %DROP_HIGHLIGHT_PC%==0 %IM7DEV%magick ^
      %CYGTEMP%\%EQL_BASE%_gch.%TMPEXT% ^
      -auto-level ^
      %CYGTEMP%\%EQL_BASE%_gch.%TMPEXT%
    
    if %LIFT_SHADOW_PC%==0 goto skipShad
    set WX=0
    
    rem In following, "-blur" should really be "decomb".
    set DECOMB=-blur 0x1
    
    for /F "usebackq tokens=2 delims=:, " %%A in (`%IM7DEV%magick ^
      %CYGTEMP%\%EQL_BASE%_gch.%TMPEXT% ^
      -auto-level ^
      +write %CYGTEMP%\%EQL_BASE%_gch.%TMPEXT% ^
      %DECOMB% ^
      -threshold %LIFT_SHADOW_PC%%% ^
      -process onewhite ^
      NULL: 2^>^&1`) do set WX=%%A
    
    rem %0: echo WX=%WX%
    
    if "%WX%"=="none" (
      %IMG7%magick ^
      %TEMP%\%EQL_BASE%_gch.%TMPEXT% ^
      -fill #fff -colorize 100 ^
      %TEMP%\%EQL_BASE%_gch.%TMPEXT%
    ) else if not %WX%==0 %IM7DEV%magick ^
      %CYGTEMP%\%EQL_BASE%_gch.%TMPEXT% ^
      -size %WX%x1 xc:gray(%LIFT_SHADOW_PC%%%) ^
      -gravity West -composite ^
      %CYGTEMP%\%EQL_BASE%_gch.%TMPEXT%
    
    :skipShad
    
    
    if %DROP_HIGHLIGHT_PC%==0 goto skipHigh
    set WX=0
    
    rem In following, "-blur" should really be "decomb".
    set DECOMB=-blur 0x1
    
    for /F "usebackq tokens=2 delims=:, " %%A in (`%IM7DEV%magick ^
      %CYGTEMP%\%EQL_BASE%_gch.%TMPEXT% ^
      -auto-level ^
      +write %CYGTEMP%\%EQL_BASE%_gch.%TMPEXT% ^
      %DECOMB% ^
      -threshold %DROP_HIGHLIGHT_PC%%% ^
      -flop ^
      -process onewhite ^
      NULL: 2^>^&1`) do set WX=%%A
    
    rem %0: echo WX=%WX%
    
    if "%WX%"=="none" (
      %IMG7%magick ^
      %TEMP%\%EQL_BASE%_gch.%TMPEXT% ^
      -fill #fff -colorize 100 ^
      %TEMP%\%EQL_BASE%_gch.%TMPEXT%
    ) else if not %WX%==0 %IM7DEV%magick ^
      %CYGTEMP%\%EQL_BASE%_gch.%TMPEXT% ^
      -size %WX%x1 xc:gray(%DROP_HIGHLIGHT_PC%%%) ^
      -gravity East -composite ^
      %CYGTEMP%\%EQL_BASE%_gch.%TMPEXT%
    
    :skipHigh
    
    
    %IM7DEV%magick ^
      %CYGTEMP%\%EQL_BASE%_gch.%TMPEXT% ^
      -process 'cumulhisto norm' ^
      %CYGTEMP%\%EQL_BASE%_gchc_clhe_red.%TMPEXT%
    
    
    
    if /I "%OUTFILE%" NEQ "null:" if not "%eqlSUPPRESS_OUT%"=="1" %IMG7%magick ^
      %INFILE% ^
      %TEMP%\%EQL_BASE%_gchc_clhe_red.%TMPEXT% ^
      -clut ^
      %OUTFILE%
    
    
    if "%eqlDEBUG%"=="1" (
      call %PICTBAT%graphLineCol %TEMP%\%EQL_BASE%_gch.%TMPEXT% . . 0 %EQL_BASE%_gch.png
      call %PICTBAT%graphLineCol %TEMP%\%EQL_BASE%_gchc_cap.%TMPEXT% . . 0 %EQL_BASE%_gchc_cap.png
      call %PICTBAT%graphLineCol %TEMP%\%EQL_BASE%_gchc_clhe_red.%TMPEXT% . . 0 %EQL_BASE%_gchc_clhe_red.png
    )
    
    
    call echoRestore
    
    @endlocal & set eqlOUTFILE=%OUTFILE% &set eqlCLUT=%TEMP%\%EQL_BASE%_gchc_clhe_red.%TMPEXT%

    matchHisto.bat

    rem Makes version of image %1 with histogram that matches the histogram of image %2.
    rem Optional %3 is output file.
    @rem
    @rem Can also use:
    @rem   mhCOL_SP_IN eg -colorspace Lab -channel R
    @rem   mhCOL_SP_OUT eg +channel -colorspace sRGB
    @rem   mhDEBUG if 1, makes a file of the clut used.
    @rem
    @rem Updated:
    @rem   27-July-2022 for IM v7.
    @rem
    
    
    @if "%2"=="" findstr /B "rem @rem" %~f0 & exit /B 1
    
    @setlocal enabledelayedexpansion
    
    @call echoOffSave
    
    call %PICTBAT%setInOut %1 mh
    
    if not "%3"=="" set OUTFILE=%3
    
    set DBG_NAME=
    set WR_CLUT=
    set DBG_H1=
    set DBG_H2=
    set WR_DBG_H1=
    set WR_DBG_H2=
    
    if "%mhDEBUG%"=="1" (
      set DBG_NAME=%INNAME%_mhcl.miff
      set WR_CLUT= ^( +clone +write %INNAME%_mhcl.miff +delete ^)
    ) else if "%mhDEBUG%"=="2" (
      set DBG_NAME=%INNAME%_mhcl.miff
      set WR_CLUT= ^( +clone +write %INNAME%_mhcl.miff +delete ^)
      set DBG_H1=%INNAME%_h1.miff
      set WR_DBG_H1=+write !DBG_H1!
      set DBG_H2=%INNAME%_h2.miff
      set WR_DBG_H2=+write !DBG_H2!
    )
    
    %IM7DEV%magick ^
      %INFILE% ^
      %mhCOL_SP_IN% ^
      ( -clone 0 ^
        -process 'mkhisto cumul norm v' ^
        %WR_DBG_H1% ^
      ) ^
      ( %2 ^
        %mhCOL_SP_IN% ^
        -process 'mkhisto cumul norm v' ^
        %WR_DBG_H2% ^
        -process 'mkhisto cumul norm v' ^
      ) ^
      ( -clone 1-2 -clut ) ^
      -delete 1-2 ^
      %WR_CLUT% ^
      -clut ^
      %mhCOL_SP_OUT% ^
      %OUTFILE%
    
    if ERRORLEVEL 1 exit /B1
    
    if not "%DBG_NAME%"=="" (
      echo Also created %DBG_NAME%
      call %PICTBAT%graphLineCol %DBG_NAME%
    )
    
    if not "%DBG_H1%"=="" (
      echo Also created %DBG_H1%
      call %PICTBAT%graphLineCol %DBG_H1%
    )
    
    if not "%DBG_H2%"=="" (
      echo Also created %DBG_H2%
      call %PICTBAT%graphLineCol %DBG_H2%
    )
    
    call echoRestore
    
    @endlocal & set mhOUTFILE=%OUTFILE%
    

    matchGauss.bat

    rem Makes version of image %1 with L of Lab histogram that matches a Gaussian distribution.
    rem Optional %2 is output file.
    @rem
    @rem Can also use:
    @rem   mgGAUSS eg width 65536 sd 20%% zeroize
    @rem
    @rem Updated:
    @rem    15-May-2021 IM v7. Output is %2 instead of %3.
    @rem
    
    
    @if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1
    
    @setlocal enabledelayedexpansion
    
    @call echoOffSave
    
    call %PICTBAT%setInOut %1 mg
    
    if not "%2"=="" if not "%2"=="." set OUTFILE=%2
    
    
    set TEMPEXT=miff
    
    
    if "%mgGAUSS%"=="" set mgGAUSS=width 65536 sd 20%% zeroize
    
    set mgGAUSS=mkgauss %mgGAUSS% cumul norm
    
    %IM7DEV%magick ^
      ( %INFILE% ^
        -colorspace LAB -channel 0 -separate -set colorspace sRGB ^
        -process 'mkhisto cumul norm' ^
        +depth +write mg_w_i1_L_chist.%TEMPEXT% ^
        +delete ^
      ) ^
      ( xc: ^
        -process '%mgGAUSS%' ^
        -delete 0 ^
        -process 'mkhisto cumul norm' ^
        +write mg_gauss.%TEMPEXT% ^
      ) ^
      NULL:
    
    %IMG7%magick ^
      mg_w_i1_L_chist.%TEMPEXT% ^
      mg_gauss.%TEMPEXT% ^
      -clut ^
      mg_w_t_L_ixt.%TEMPEXT%
    
    %IMG7%magick ^
      %INFILE% ^
      -colorspace Lab -channel 0 ^
      mg_w_t_L_ixt.%TEMPEXT% ^
      -clut ^
      +channel -colorspace sRGB ^
      %OUTFILE%
    
    
    call echoRestore
    
    @endlocal & set mgOUTFILE=%OUTFILE%

    eqlQtr.bat

    rem Applies contrast-limited histogram-equalisation
    rem (with iterative redistribution) as appropriate for four tiles,
    rem   blending between the four quarters.
    @rem
    @rem Optional parameters:
    @rem   %2 is limiting factor SD_FACT, so limit = mean + SD_FACT * standard_devition.
    @rem        Default 1.
    @rem   %3 is percentage lift for shadows. Default 0, no lift.
    @rem   %4 is percentage drop for highlights. Default 0, no drop.
    @rem   %5 is output file.
    @rem
    @rem Can also use:
    @rem   eqlqDIFF_LIMIT iteration stops when the count redistribted is less than this percentage.
    @rem     Default 1.0.
    @rem
    @rem Updated:
    @rem   27-July-2022 for IM v7.
    @rem
    
    @if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1
    
    @setlocal enabledelayedexpansion
    
    @call echoOffSave
    
    call %PICTBAT%setInOut %1 eqlq
    
    set P2=%2
    if "%P2%"=="" set P2=.
    set P3=%3
    if "%P3%"=="" set P3=.
    set P4=%4
    if "%P4%"=="" set P4=.
    
    if not "%5"=="" set OUTFILE=%5
    
    set eqlSUPPRESS_OUT=1
    set eqlDIFF_LIMIT=%eqlqDIFF_LIMIT%
    
    %IMG7%magick %INFILE% -crop 2x2@ +adjoin eqlq_tmp.miff
    if ERRORLEVEL 1 exit /B 1
    
    call %PICTBAT%eqLimit eqlq_tmp-0.miff %P2% %P3% %P4% eqlq_0
    set eqlCLUT0=%eqlCLUT%
    
    call %PICTBAT%eqLimit eqlq_tmp-1.miff %P2% %P3% %P4% eqlq_1
    set eqlCLUT1=%eqlCLUT%
    
    call %PICTBAT%eqLimit eqlq_tmp-2.miff %P2% %P3% %P4% eqlq_2
    set eqlCLUT2=%eqlCLUT%
    
    call %PICTBAT%eqLimit eqlq_tmp-3.miff %P2% %P3% %P4% eqlq_3
    set eqlCLUT3=%eqlCLUT%
    
    rem %IMG7%magick ^
    rem   %INFILE% ^
    rem   ( +clone %eqlCLUT0% -clut -write eqlq_tmp-0.miff +delete ) ^
    rem   ( +clone %eqlCLUT1% -clut -write eqlq_tmp-1.miff +delete ) ^
    rem   ( +clone %eqlCLUT2% -clut -write eqlq_tmp-2.miff +delete ) ^
    rem   ( +clone %eqlCLUT3% -clut -write eqlq_tmp-3.miff +delete ) ^
    rem   NULL:
    
    %IMG7%magick ^
      %INFILE% ^
      ( -clone 0 %eqlCLUT0% -clut ) ^
      ( -clone 0 %eqlCLUT1% -clut ) ^
      ( -clone 0 %eqlCLUT2% -clut ) ^
      ( -clone 0 %eqlCLUT3% -clut ) ^
      ( -clone 0 -sparse-color Bilinear 0,0,#000,%%[fx:w-1],0,#fff ) ^
      -delete 0 ^
      ( -clone 0,1,4 -composite ) ^
      ( -clone 2,3,4 -composite ) ^
      -delete 0-4 ^
      ( -clone 0 -sparse-color Bilinear 0,0,#000,0,%%[fx:h-1],#fff ) ^
      -composite ^
      +depth ^
      %OUTFILE%
    
    rem del eqlq_tmp-0.miff
    rem del eqlq_tmp-1.miff
    rem del eqlq_tmp-2.miff
    rem del eqlq_tmp-3.miff
    
    call echoRestore
    
    @endlocal & set eqlqOUTFILE=%OUTFILE%

    eqlTile.bat

    rem Applies contrast-limited histogram-equalisation
    rem (with iterative redistribution) as appropriate for NxM tiles,
    rem   blending between the tiles.
    @rem
    @rem Optional parameters:
    @rem   %2 is limiting factor SD_FACT, so limit = mean + SD_FACT * standard_devition.
    @rem        Default 1.
    @rem   %3 is percentage lift for shadows. Default 0, no lift.
    @rem   %4 is percentage drop for highlights. Default 0, no drop.
    @rem   %5 is number of columns of tiles. Deafult 3.
    @rem   %6 is number of rows of tiles. Deafult 3.
    @rem   %7 is output file.
    @rem
    @rem Can also use:
    @rem   eqltDEBUG if 1, also creates curve histograms.
    @rem   eqltDIFF_LIMIT iteration stops when the count redistribted is less than this percentage.
    @rem     Default 1.0.
    @rem   eqltLINEAR if 1, composes in linear colourspace.
    @rem   eqltCLEANUP if not 1, doesn't remove temporary files
    @rem
    @rem Updated:
    @rem   27-July-2022 for IM v7.
    @rem
    
    @if "%1"=="" findstr /B "rem @rem" %~f0 & exit /B 1
    
    @setlocal enabledelayedexpansion
    
    @call echoOffSave
    
    call %PICTBAT%setInOut %1 eqlt
    
    
    set P2=%2
    if "%P2%"=="" set P2=.
    set P3=%3
    if "%P3%"=="" set P3=.
    set P4=%4
    if "%P4%"=="" set P4=.
    
    set N_COL=%5
    if "%N_COL%"=="." set N_COL=
    if "%N_COL%"=="" set N_COL=3
    
    set N_ROW=%6
    if "%N_ROW%"=="." set N_ROW=
    if "%N_ROW%"=="" set N_ROW=3
    
    if not "%7"=="" set OUTFILE=%7
    
    if "%eqltCLEANUP%"=="" set eqltCLEANUP=1
    
    set eqlSUPPRESS_OUT=1
    set eqlDIFF_LIMIT=%eqltDIFF_LIMIT%
    
    set VSN_LIST=%TEMP%\eqltVsn.lis
    del %VSN_LIST% 2>nul
    
    set CMD_FILE=%TEMP%\eqltCommand.bat
    
    for /F "usebackq" %%L in (`%IMG7%magick ^
      %INFILE% ^
      -crop "%N_COL%x%N_ROW%@" +repage ^
      -precision 15 ^
      -format "MAX_N=%%p\n" ^
      -write INFO: ^
      +adjoin ^
      eqltTEMP_TILE.miff`) do @set %%L
    
    echo MAX_N=%MAX_N%
    
    set /A COL_X_ROWm1=%N_COL%*%N_ROW%-1
    
    if not %MAX_N%==%COL_X_ROWm1% (
      echo %0: Bug: %MAX_N% neq %COL_X_ROWm1%
      exit /B 1
    )
    
    set eqlLofLAB=0
    
    echo %IMG7%magick %INFILE% >%CMD_FILE%
    if "%eqlLofLAB%"=="1" (
      echo -colorspace Lab >>%CMD_FILE%
    
      set COL_SP_IN=-channel R
      set COL_SP_OUT=+channel -colorspace sRGB
    ) else (
      set COL_SP_IN=
      set COL_SP_OUT=
    )
    
    for /L %%i in (0,1,%MAX_N%) do (
      call %PICTBAT%eqLimit eqltTEMP_TILE-%%i.miff %P2% %P3% %P4% eqlt_%%i
      set eqltCLUT%%i=!eqlCLUT!
    
      echo eqltCLUT%%i=!eqltCLUT%%i!
    
      set VSN=%TEMP%\eqltTEMP_TILE_%%i.miff
      echo ^( +clone %COL_SP_IN% !eqlCLUT! -clut %COL_SP_OUT% +write !VSN! +delete ^) >>%CMD_FILE%
      echo !VSN! >>%VSN_LIST%
    )
    
    cPrefix /i%CMD_FILE% /r"^"
    echo NULL: >>%CMD_FILE%
    
    type %CMD_FILE%
    
    call %CMD_FILE%
    
    set btLINEAR=%eqltLINEAR%
    
    call %PICTBAT%blendTile %VSN_LIST% %N_COL% %N_ROW% %OUTFILE%
    if ERRORLEVEL 1 exit /B 1
    
    set eqlSUPPRESS_OUT=
    set eqlDIFF_LIMIT=
    
    rem FIXME: cleanup
    if "%eqltCLEANUP%"=="1" (
      del %VSN_LIST%
      del %CMD_FILE%
      del %TEMP%\eqlt*.BAK
      for /L %%i in (0,1,%MAX_N%) do (
        del eqltTEMP_TILE-%%i.miff
        del %TEMP%\eqlt_%%i_*.miff
        del %TEMP%\eqltTEMP_TILE_%%i.miff
      )
    )
    
    call echoRestore
    
    @endlocal & set eqltOUTFILE=%OUTFILE%

    All images on this page were created by the commands shown, using:

    %IMG7%magick -version
    Version: ImageMagick 7.1.0-49 Q16-HDRI x64 7a3f3f1:20220924 https://imagemagick.org
    Copyright: (C) 1999 ImageMagick Studio LLC
    License: https://imagemagick.org/script/license.php
    Features: Cipher DPC HDRI OpenCL 
    Delegates (built-in): bzlib cairo freetype gslib heic jng jp2 jpeg jxl lcms lqr lzma openexr pangocairo png ps raqm raw rsvg tiff webp xml zip zlib
    Compiler: Visual Studio 2022 (193331630)
    %IM7DEV%magick -version
    Version: ImageMagick 7.1.0-20 Q32-HDRI x86_64 2021-12-29 https://imagemagick.org
    Copyright: (C) 1999-2021 ImageMagick Studio LLC
    License: https://imagemagick.org/script/license.php
    Features: Cipher DPC HDRI Modules OpenMP(4.5) 
    Delegates (built-in): bzlib cairo fontconfig fpx freetype jbig jng jpeg lcms ltdl lzma pangocairo png raqm rsvg tiff webp wmf x xml zip zlib
    Compiler: gcc (11.2)

    Source file for this web page is eqlimit.h1. To re-create this web page, execute "procH1 eqlimit".


    This page, including the images, is my copyright. Anyone is permitted to use or adapt any of the code, scripts or images for any purpose, including commercial use.

    Anyone is permitted to re-publish this page, but only for non-commercial use.

    Anyone is permitted to link to this page, including for commercial use.


    Page version v1.0 19-Dec-2014.

    Page created 27-Sep-2022 18:08:51.

    Copyright © 2022 Alan Gibson.