Fred's ImageMagick Scripts


    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:

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


Removes a color cast from an image.

Download Script

last modified: August 15, 2022

USAGE: removecolorcast [-m mixing] [-a autolevel] [-c cspace] [-B brightness] [-C contrast] [-S saturation] [infile] [outfile]
USAGE: removecolorcast [-h|-help]

-m ... mixing ....... mixing amount between input image and color filter;
..................... 0<=integer<=100; default=50
-c ... cpsace ....... colorspace for processing; choices are: sRGB or RGB;
..................... default=sRGB
-a ... autolevel .... stretch the result to full dynamic range; yes or no;
..................... the default=yes
-B ... brightness ... brightness change postprocessing; -100<=integer<=100;
..................... default=0
-C ... contrast ..... contrast change postprocessing; -100<=integer<=100;
..................... default=0
-S ... saturation ... saturation change postprocessing; -100<=integer<=100;
..................... default=0

PURPOSE: To remove a color cast from an image.

DESCRIPTION: REMOVECOLORCAST removes a color cast from an image by blending the image and a color filter generated from the 180 deg hue shifted average color of the image. The method of filtering use -compose colorize.


-m mixing ... MIXING amount between the input image and a self generating color filter. The values are 0<=integers<=100. The default=50.

-c cpsace ... CSPACE is the colorspace for processing. The choices are: sRGB or RGB. The default=sRGB. Using sRGB results in a slightly warmer result. Using RGB results in a slightly cooler result.

-a autolevel ... AUTOLEVEL applies a dynamic range stretch of the result. The choices are: yes or no. The default=yes.

-B brightness ... BRIGHTNESS change as a postprocessing step. Value are -100<=integer<=100. The default=0.

-C contrast ... CONTRAST change as a postprocessing step. Value are -100<=integer<=100. The default=0.

-S saturation ... SATURATION change as a postprocessing step. Value are -100<=integer<=100. The default=0.

RECOMMEND: IM or higher due to fluctuating changes to IM sRGB and RGB color spaces prior to that version. Otherwise, results may or may not reproduce the effect properly, depending upon IM version.

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.


Example 1

Original Image

-c sRGB

-c RGB

Example 2

Original Image

-c sRGB

-c RGB

Example 3

Original Image

-c sRGB

-c RGB

Example 4

Original Image

-c sRGB -B 10

-c RGB -B 10

What the script does for m=morphology is as follows:

  • Reads the input and converts to grayscale
  • Does two different asymmetric morphology closes each on the grayscale image
  • Does a compose difference between the two
  • Stretches to full dynamic range and thresholds
  • Uses connected-components to find each corner region and
    its centroid
  • Draws the points onto the input image and save the result to the output

  • convert -quiet -regard-warnings "$infile" +write $dir/tmpI.mpc \
    -alpha off -colorspace gray +repage $dir/tmpG.mpc
  • if [ "$threshold" != "" ]; then
    thresholding="-threshold $threshold%"
  • if [ "$dilate" != "0" ]; then
    dilate=`convert xc: -format "%[fx:$dilate + 0.5]" info:`
    dilating="-morphology dilate disk:$dilate"
  • convert \
    \( $dir/tmpG.mpc -morphology dilate plus:$region -morphology erode diamond:$region \) \
    \( $dir/tmpG.mpc -morphology dilate cross:$region -morphology erode square:$region \) \
    -compose difference -composite -auto-level $thresholding $dilating \
  • data=`convert $dir/tmpC.miff \
    -define connected-components:verbose=true \
    -connected-components 8 null: | tail -n +2 | \
    sed -n 's/^.*[:][ ]*[^ ]*[ ]*\([^ ]*\)[ ]*[^ ]*[ ]*\([^ ]*\)[ ]*$/\1_\2/p'`
  • i=1
    for item in $data; do
    coords=`echo "$item" | cut -d_ -f1`
    colour=`echo "$item" | cut -d_ -f2`
    if [ "$colour" != "srgb(0,0,0)" -a "$colour" != "gray(0)" -a "$colour" != "black" ]; then
    [ "$print" = "yes" ] && echo "pt=$i coords=$coords"
    points="$points point $coords"
  • convert $dir/tmpI.mpc \
    \( -clone 0 -fill "$color" -colorize 100 \) \
    \( -clone 0 -evaluate set 0 -fill white \
    -draw "$points" -alpha off $dilating \) \
    -compose over -composite "$outfile1"