ImageMagick v6 Examples --
Color Modifications

Index
ImageMagick Examples Preface and Index
Converting Color to Gray-Scale (Making grayscale images)
Color Adjustments (adjusting the colors in images)
Automatic Level Adjustments (automatic enhancement of images)
DIY Level Adjustments (general tinting operators)
Tinting Images (general tinting operators)
Global Color Modifiers
Replacing Colors in an Image (replacing individual colors)
Recoloring Images with Gradients
Miscellaneous Color Operators (special recoloring operators)
Color modification of images without changing the overall image itself is a very common requirement of ImageMagick. Whether it is to lighten or darken the image, or more drastic color modifications.

We will need a test image... Don't worry above how I actually generated this image, it is not important for the exercise. I did design it to contain a range of colors, transparencies and other features, specifically to give IM a good workout when used. [IM Output]

If you are really interested in the commands used to generate this image you can look at the special script, "generate_test", I use to create it.


Converting Color to Gray-Scale

Gray scale images can be very useful for many uses. Either as furthering the processing of the original image, or for use in background compositions. The best method of converting an image to gray-scale is to just ask IM to convert the image into a gray-scale Color Space representation for the image.

  convert  test.png  -colorspace Gray   gray_colorspace.png
[IM Output] ==> [IM Output]

Note how the blue is much darker than the red, due the weighting to match the intensity as they seem to appear to the human eye. That is 'red' is quite a bright color compared to 'blue' which looks darker.


However there a many other methods, and meanings of 'gray-scale'...

For example, you can drain all the color out of the the image by using "-modulate", to set all color saturation levels to zero.

  convert test.png  -modulate 100,0  gray_modulate.png
[IM Output]

Note how the IM 'green' color I used in my test image is not a pure green, but the half-bright green defined by the new SVG -- Scalable Vector Graphics standard. If you need a pure RGB green you can use the color 'lime' instead.

Another way is to use the FX DIY operator to average the three channels together to get a pure mathematical meaning of gray-scale.

  convert test.png -fx '(r+g+b)/3' gray_fx_average.png
[IM Output]

You can use the same technique to control the weighting of the individual color channels. For example this is the normal IM meaning of 'gray-scale' for an RGB image.

  convert test.png -fx '0.3*r+0.6*g+0.1*b' gray_diy.png
[IM Output]

You can also use 'intensity' if you want the same meaning within the "-fx" operator.

  convert  test.png  -fx intensity  gray_intensity.png
[IM Output]


Another technique is to simply add all three channels together and while the resulting image will not loose information due to 'quantum rounding' effects, you may loose information about the brightest colors.

  convert test.png -separate -background black \
          -compose plus -flatten   gray_added.png
[IM Output]

This grayscale image is particularly well suited for generating masks from Difference Images.

However as the FX DIY operator is interpreted, it can run very very slowly. For more complex operations you can use the simpler Evaluate Operator, "-evaluate".

For example here is a 2/5/3 ratio gray-scaled image, though I make no attempt to preserve the transparency channel of the original image.

  convert test.png -channel R -evaluate multiply .2 \
                   -channel G -evaluate multiply .5 \
                   -channel B -evaluate multiply .3 \
                   +channel -separate -compose add -flatten gray_253.png
[IM Output]

The above would suffer from 'quantization' effects for a ImageMagick compiled at a 'Q8' Quality Level. That is because the results of the "-evaluate" will be saved into a small 8 bit integer, used for image values. Only later are those values added together with the resulting loss of accuracy.

An ImageMagick compiled with 'Q16', or better still the HDRI, quality compile options will produce a much more exact result.

A similar technique can be used to generate a pure mathematical gray-scale, by directly averaging the three RGB channels equally.

  convert test.png -separate -average  gray_average.png
[IM Output]

However as you can see, I did not attempt to preserve the alpha channel of the resulting image.

Another fast alternative is to use the "-recolor" color matrix operator, which will let you specify the weighting of the three color channels.

  convert test.png -recolor '.2 .5 .3
                             .2 .5 .3
                             .2 .5 .3'   gray_recolor.png
[IM Output]

Basically the first tree numbers is the channel weighting for the resulting images red channel, next 3 for green, and the final three numbers for blue.


A much more interesting technique is to extract a variety of different meanings of brightness by extracting the appropriate Color Channel from various Color Space representations of the image. The first image is the normal recommended method.

  convert rose: -colorspace Gray                      channel_gray.gif
  convert rose: -colorspace CMYK -channel K -negate -separate channel_black.gif
  convert rose: -colorspace HSB  -channel B -separate channel_brilliance.gif
  convert rose: -colorspace HSL  -channel B -separate channel_lightness.gif
  convert rose: -colorspace YUV  -channel R -separate channel_luma.gif
[IM Output] ==> [IM Output]
Gray
RGB
[IM Output]
Neg Black
CMYK
[IM Output]
Brilliance
HSB
[IM Output]
Lightness
HSL
[IM Output]
Luma (Y)
YUV

Note that none of the gray-scale results are quite the same due to the different meanings of 'brightness' in the various colorspaces.

Alternatively you can use "-type" to tell IM to treat the image as gray-scale, when either reading or writing the image.

  convert  test.png  -type GrayScaleMatte  gray_type.png
[IM Output]

The "-type" setting is generally only used when an image is being read or written to a file. As such its action is delayed to the final write of the image. Its effect is also highly dependant on the capabilities of the image file format involved and is used to override ImageMagick's normal determination during that process. See the Type examples for more information.

Before IM v6.3.5-9 the above will have removed any transparency in the written image (equivalent of a "-type Grayscale") due to a bug. This was fixed as soon as I noted the problem and reported it. (There is a lesson here :-)


Level Adjustments

The most basic form of adjustment you can make to images are known as 'level' adjustments. This basically means taking the individual RGB color values (or even the matte/alpha channel values) and adjusting them so as to either stretch or compress those values.

As only channel values are being adjusted, they are best demonstrated on a gray-scale image, rather than a color image. However if you adjust all the color channels of an image by the same amount you can use them with color images, for the purposes of either enhancing, or adjusting the image. Do not confuse this with the more automatic form of level adjustments, which we will look at in the next major section of examples below, Auto-Level Adjustments. This function will do exactly the same operation regardless of the actual content of the image. It does not matter if the image is bright, or dark, or has a blue, or yellow tint. The operations are blind to the actual image content.

[IM Graph] In demonstrating these operations I will be using a modified "gnuplot" graph such as shown to the right, which I generate using a special script "im_graph_levels". The graph has a red line which maps the given original 'x' value (representing the gray-scale value of the top most gradient) to the 'y' value shown. The resulting color gradient is also shown underneath the input linear gradient.

The graph shown to right is of the IM "-noop" operator which actually does nothing to an image. As such each of the image's color values are just mapped to exactly the same value without change. The lower gradient is thus the same as the upper gradient.

Image Negation

The simplest and most basic global level adjustment you can make is to negate the image, using the "-negate" image operator.

Essentially this makes   white, black,   and   black, white,  , adjusting all the colors to match. That is it will make the color red, its complementary color of cyan,   and blue, yellow, etc.

You can see this with the mapping graph shown below, as I use the "-negate" operator on both the 'test' image and the standard IM 'rose' built-in image. Note how the lower gradient in the mapping graph image is now reversed, so that black and white are swapped, and the same reversal appearing in the negated 'test' image.

  convert  test.png  -negate  test_negate.png
  convert  rose:     -negate  rose_negate.gif
[IM Output]
[IM Output]
==> [IM Graph] ==> [IM Output]
[IM Output]

Internally negate is actually rather stupid. It handles the three color channels independently, and by default ignores the alpha or matte channel. If this was not the case, you would get a very silly result like this...

  convert  test.png -channel RGBA  -negate  negate_rgba.png
[IM Output] ==> [IM Output]

The image is negated, as you can see by the semi-transparent color gradient. But as the transparency channel has also been negated you loose all the opaque colors in the image. This is why the default setting for "-channel" is 'RGB'. See Color Channels for more information.

You can limit the negation to just one channel, say the green color channel. This may not seem very useful, but at times it is vitality important.

  convert  test.png -channel green  -negate  negate_green.png
[IM Output] ==> [IM Output]

The "-negate" operator is actually its own inverse. Doing two negations with the same "-channel" setting cancels each other out.

  convert  negate_green.png  -channel green  -negate  negate_restore.png
[IM Output] ==> [IM Output]

Negation is extremely common in image processing, particularly when dealing with gray-scale images as a step before or after other processing options. As such I recommend you play with it and keep it in mind whenever you are doing anything, as working with negated images can solve some otherwise difficult problems.

Direct Level Adjustments

The "-level" operator is the more general level adjustment operator. You basically give it two values a 'black_point' and a 'white_point', as well as an optional third value (gamma adjustment), which I will look at later.

What it does is map any color values in the image that is equal to or less than the 'black_point', and make them black (or a 0 value). Similarly, any color values which are equal to or brighter that the 'white_point' will make them white (or a Maximum value). The colors in between these two points are then 'stretched' linearly to fill the complete range of values.

The effect of this is to improve the contrast, enhancing the colors within an image. For example here is a 25% contrast enhancement of our test image, using the same values as shown by the graph.

As you commonly adjust both the black and white points by the same amount from the 0% and 100% amounts, you can just specify the 'black_point' only. The white point will be adjusted by the same amount inward.

  convert  test.png  -level 25%,75%  test_level.png
  convert  rose:     -level 25%      rose_level.gif
[IM Output]
[IM Output]
==> [IM Graph] ==> [IM Output]
[IM Output]

Note that 25% is a huge contrast enhancement for any image, but it clearly shows what it does.

You don't have to change both the 'black' and 'white' points. Instead it is quite permissible to just adjust only one end of the color range. For example we can make a very light, or a very dark rose image.

  convert  rose:  -level 0,75%     rose_level_light.gif
  convert  rose:  -level 25%,100%  rose_level_dark.gif
[IM Graph] ==> [IM Output]    [IM Graph] ==> [IM Output]

However I again warn you that the colors outside the given range are 'clipped' or 'burned', and as such will no longer be available for later image processing. This is the biggest problem with using a "-level" operator.

[IM Graph] By using a negative value you can do some rough de-contrasting of an image.

What this means is that rather than providing a color value for the values to be mapped to 'black' and 'white' and thus stretching out the colors in between, you instead compress the color values so as to map the imaginary negative color to black or white. The result is a general graying of the image.

  convert  rose:  -level -25%  rose_decontrast.gif
[IM Output]

This method of decontrasting an image however is very inaccurate and not recommended, unless you have a IM older than version 6.4.2 where you don't have access to the new Reversed Level Operator.

[IM Graph] You can use the "-level" operator to negate an image, just by swapping the 'black' and 'white' point values given, using "-level 100%,0".
[IM Graph] Or by setting them to the same value, you can effectively call all the color values in the image to be thresholded. Using "-level" to threshold an image is exactly the same as if you used the "-threshold" operator with the value. The mapping graph shown right, shows the results of a "-level 50%,50%" operation, and its effect on a grayscale gradient.


And here is the result of applying this thresholding "-level" operation on the built-in rose image. Note that unlike "-threshold" the image is not converted to a grayscale image as part of the thresholding, when used with the default "-channel" setting (see Thresholding Images).

  convert  rose:  -level 50%,50%  rose_level_thres.gif
[IM Output]

The general nature of level to linearly modify an image, makes the "-level" operator a very good for general gray-scale image, and mask adjustments. Add the fact that you can modify individual channels as opposed to the whole image, makes it one of the basic color modification operators available to IM users.

Be warned that the "-level" operator treats the transparency channel as 'matte' values. As such 100% is fully transparent and 0% is opaque. Please take this into account when using -level with a blurred shape image. This is most typically done after blurring an 'shape' image, to expand and stretch the results. For examples of this see Soft Edges, and Shadow Outlines.

Note you can also use various "-evaluate" mathematical methods to achieve the same results for -level both + and - forms) however if more than two operations are needed care must be taken to ensure you do not 'clip' any important data from the image. You do not have that problem with the "-level" operator.

See Evaluate Math Operator for examples of using this simpler operator.

Reversed Level Adjustments

As of IM version 6.4.2 the Level Operator was expanded to provide a 'reversed' form "+level" (note the 'plus'). Alternatively you can use the original "-level" form of the operator but add a '!' to the level argument given (for older API interfaces).

The arguments for this variant is exactly the same, but instead of stretching the values so as to map the 'black_point' and 'white_point' to 'black' and 'white', it maps 'black' and 'white' to the given points. In other words "+level" is the exact reverse of "-level".

For example here we map 'black' to a 25% gray, and white to 75% gray, effectively de-contrasting the image in a very exact way.

  convert  test.png  +level 25%   test_level_plus.png
  convert  rose:     +level 25%   rose_level_plus.gif
[IM Output]
[IM Output]
==> [IM Graph] ==> [IM Output]
[IM Output]

If you compare the above "+level 25%" operation with the use of a a negative de-contrasting, "-level -25%" operator we showed previously, you will see that are not the same. The 'plus' version produces a much stronger de-contrasted image (it is greyer), but does so by mapping to the exact values you give the operator, and not the 'imaginary' values the 'minus' form used. This exact value usage is important, and one of the reasons why the 'plus' form of the operator was added.

Of course a '25%' is again a very large value, and it is not recommended for use with typical image work.

Note that the "-level" and "+level", are in actual fact the exact reverse of each other when given the same argument. That is one maps values to the range extremes, while the other maps from the range extremes.

However while you can use one to 'undo' the other, the result may not be exactly the same, due to 'clipping' and 'quantum rounding' effects on the image values.

For example here we compress the colors of the test image using "+level", then decompress them again using "-level", so as to restore the image close to its original appearance.

  convert  test.png  +level 20%  -level 20%  test_level_undo.png
[IM Output] ==> [IM Graph] ==> [IM Output]

The two images appear to be very very similar, and as I am using a high quality 'Q16' version of IM, you will be hard pressed to notice any difference at all. However the values may not be exactly the same (especially with a Q8 version of IM), as you have effectively compressed, the un-compressed the image, which can produce some 'rounding' effects (unless you use a floating point HDRI version of ImageMagick).

Unfortunately, doing these two operations in the opposite order (stretch, then compress the color values) produces a very different result...

  convert  test.png  -level 20%  +level 20%  test_level_undo2.png
[IM Output] ==> [IM Graph] ==> [IM Output]

Notice how the center values of the color range are restored correctly, but the bright and dark ends have been clipped during the stretching by the "-level" operator. Then when the "+level" operator was applied the 'clipped' or 'burned' values was moved to the given grey levels, effectively clipping the brightest and darkest pixels to specific values. This can be a extremely useful technique.

One other useful aspect of the "+level" operator is that you can completely compress all the color values in an image to the same gray-scale level.

  convert  test.png  +level 30%,30%  test_level_const.png
[IM Output] ==> [IM Graph] ==> [IM Output]

By specifying levels according to the values of specific colors for each individual channel, you can effectively convert a greyscale gradient into a specific color gradient. However this is rather difficult to calculate and do. As such, as of IM v6.4.2, a "-level-colors" operator has been provided that will let you specify the black and white points in terms of specific colors rather than 'level' values. See Level by Color below.

Level Gamma Adjustments

Both the above "-level" variants also allow you to use a third setting. The 'gamma' adjustment value. By default this is set to a value of 1.0', which does not do any sort of mid-tone adjustment of the resulting image, producing a pure linear mapping of the values from the old image to the new image.

However by making this value larger, you will curve the resulting line so as to brighten the image, while shrinking that value will darken the image.

For example here I use just the 'gamma' setting to brighten and darken just the mid-tones of the image.

  convert  rose:  -level 0%,100%,2.0   rose_level_gamma_light.gif
  convert  rose:  -level 0%,100%,0.5   rose_level_gamma_dark.gif
[IM Graph] ==> [IM Output]    [IM Graph] ==> [IM Output]

Values generally range from 10 for a blinding bright image, to .2 for very dark image. As mentioned a value of 1.0 will make no 'gamma' changes to the image. However the special value of '2.0' (see above) can be used to get the square root of the images normalized color.

Both versions of the "-level" operate handles 'gamma' in the same way. This means you can combine the level adjustment of the 'black' and 'white' ends with a non-linear 'gamma' adjustment. You can also only adjust a single channel of an image. For example, here we give an image a subtle tint at the black end of just the blue channel, while using gamma to preserve the mid-tone color levels of the image.

  convert  test.png  -channel B +level 25%,100%,.6 test_blue_tint.png
[IM Output] ==> [IM Graph] ==> [IM Output]

This specific example, could be used to tint a weather satellite photo, where only the sea is pure black, while land is more grey.


The "-gamma" operator is also provided, and has exactly the same effect as the 'gamma' setting in the "-level" operator. However it will let you adjust the 'gamma' adjustment level for each individual channel as well.

For example here we brighten the image differently for each individual RGB channel.

  convert  rose:  -gamma 0.8,1.3,1.0  gamma_channel.gif
[IM Output]

As you can see this can be used to do some subtle tinting and color adjustments to an image, or correct images with contain too much of a specific color.

One of the most important things when resizing, filtering or modifying images (even more important anything else) is to do it in linear space, so if your image is gamma corrected, you should transform it to linear space, scale and then transform back to gamma space.

One less obvious use of "-gamma" is to zero out specific image channels (See Other Channel Separation Methods). Or color an image completely 'black', 'white' or some other primary color. See Primary Colored Canvases.

Level Adjustment by Color

The "-level-colors" operator was added to IM v6.2.4-1. Essentially, it is exactly the same as the Level Operator we discussed above, but with the value for each channel specified as a color value.

That is the "-level-colors" option will map the given colors to 'black' and 'white' and stretching all the other colors between then linearly. This effectively removes the range of colors given from the image.

And while this works, it is not particularly useful, as it is prone to fail for colors which have common values in some channel. For example the colors 'DodgerBlue' and 'White' have the same color values in the blue channel, as such "-level-colors DodgerBlue,White" will not convert those colors to black and white.

The better technique in that case is to extract a greyscale image of the channel with the highest differences (such as red) and level or normalize that channel.

WARNING: watch out for 'transparent' colors.


The plus form of the operator "+level-colors" on the other hand is extremely useful as it will map the 'black' and 'white' color to the given values compressing all the other colors linearly to fit the two colors you give.

For example lets map 'black' and 'white' to 'green', and 'gold'...

  convert  test.png  +level-colors green,gold   levelc_grn-gold.png
[IM Output] ==> [IM Output]

As you can see the grayscale gradient is remapped into the a gradient bound by the colors given, and although colors outside a gray-scale range are also modified, they will also follow the basic style of the color range specified. This makes the "+level-colors" operator an extremely useful one, especially when mapping grayscale images.

If you only supply one colorname but include a comma, the missing color will default either to 'black' or 'white' as appropriate. This makes it easy to convert grayscale images into a gradient for any color you like.

  convert test.png  +level-colors ,DodgerBlue   levelc_dodger.png
  convert test.png  +level-colors ,Gold         levelc_gold.png
  convert test.png  +level-colors ,Lime         levelc_lime.png
  convert test.png  +level-colors ,Red          levelc_red.png

  convert test.png  +level-colors Navy,         levelc_navy.png
  convert test.png  +level-colors DarkGreen,    levelc_darkgreen.png
  convert test.png  +level-colors Firebrick,    levelc_firebrick.png
[IM Output] [IM Output] [IM Output] [IM Output]
[IM Output] [IM Output] [IM Output]

If you only specify a single color without any 'comma' separator, that color will be used for both black and white points. That means all the colors in the image will be reset to that one color. (according to the current "-channel" setting limitations).

  convert  test.png  +level-colors dodgerblue  levelc_blue.png
[IM Output]

If you want to set the images transparency setting as well you will need to set "-channel" to include the transparency channel, OR set the Alpha Channel to filly-opaque, using either "-alpha opaque" or "-alpha off.

  convert  test.png -channel ALL +level-colors dodgerblue levelc_blue2.png
[IM Output]

Here are a few more examples of using this to adjust or 'tint' a colorful image, rather than a gray-scale image. Also see Blanking Existing Images.


  convert rose: +level-colors             navy,lemonchiffon  levelc_faded.gif
  convert rose: +level-colors        firebrick,gold          levelc_fire.gif
  convert rose: +level-colors 'rgb(102,75,25)',lemonchiffon  levelc_tan.gif
[IM Output] ==> [IM Output] [IM Output] [IM Output]

In summary the "+level-colors" is a gradient color replacement, a linear tinting operator, and can also completely reset colors.

Sigmoidal Non-linearity Contrast

From a PDF paper on 'Fundamentals of Image Processing' (page 44) they present an alternative from the linear contrast control with gamma correction known as 'sigmoidal non-linearity contrast control'.

The result is a non-linear, smooth contrast change (a 'Sigmoidal Function' in mathematical terms) over the whole color range, preserving the white and black colors, much better for photo color adjustments.

The exact formula from the paper is very complex, and even has a mistake, but essentially requires with two adjustment values. A threshold level for the the contrast function to center on (typically '50%'), and a contrast factor ('10 being very high, and '0.5' very low).

For those interested, the corrected formula for the 'sigmoidal non-linearity contrast control' is...
(1/(1+exp(β(α-u))) - 1/(1+exp(β))) / (1/(1+exp(β(α-u))/(1+exp(β))))
Where α is the threshold level, and β the contrast factor to be applied.

The formula is actually very simple exponential curve, with the bulk of the above formula is designed to ensure that 0 remains 0 and 1 remains one. That is the graph always goes though the points 0,0 and 1,1. And the highest gradient of change is at the given threshold.

Here for example is a "-fx" implementation of the above formula, resulting from a very high contrast value of '10' and a '50%' threshold value. These values have been rolled into the floating point constants, to speed up the function.

  convert test.png  -fx '(1/(1+exp(10*(.5-u)))-0.0066928509)*1.0092503' \
              sigmoidal.png
[IM Output] ==> [IM Graph] ==> [IM Output]

Lucky for us IM v6.2.1 had this complex function built in as a new operator "-sigmoidal-contrast", allowing a much simpler application.

    convert test.png  -sigmoidal-contrast 10,50% test_sigmoidal.png
[IM Output]

As a bonus IM also provides the inverse, a 'sigmoidal contrast reduction' function (as plus '+' form of the operator), which if applied with the same arguments restores our original image (almost exactly).

    convert test_sigmoidal.png +sigmoidal-contrast 10,50% \
                                             test_sigmoidal_inv.png
[IM Output]

And here we apply it to the rose image...

    convert  rose:  -sigmoidal-contrast 10,50%  rose_sigmoidal.gif
[IM Output]

I did say '10' was a very heavy contrast factor. In fact anything higher than this value can be considered to me more like a fuzzy threshold operation, rather than a contrast enhancement.

For a practical example of using this operator see the advanced "Gel" Effects Example, where it is used to sharpen the bright area being added to a shaped area color.

Miscellaneous Contrast Operators

Under Construction

   -contrast  and   +contrast
         Rather useless minor contrast adjustment operator

-threshold
   Threshold the image, any value less than or equal to the given value is
   set to 0 and anything greater is set to the maximum value.

   Note that like level, this is a channel operator, but if the default
   'channel setting' is used only the gray-scale intensity of the image is
   thresholded producing a black and white image.

   convert rose: -threshold 45%  x:

   You can force normal channel behaviour, where each channel is thresholded
   individually buy using "-channel All"

   convert rose: -channel All -threshold 45%  x:

-black-threshold
-white-threshold
   This is like -threshold except that only one side of the threshold value is
   actually modified.

   For example, here anything that is darker than 30% is set to black.

   convert rose: -black-threshold 30%  x:
   convert rose: -white-threshold 50%  x:

   These operators however do not seem to be channel effected, so may only be
   suitable for gray-scale images!

Then
-colorize, and -tint
-opaque  -transparency floodfill -fuzz
-recolor


Automatic Level Adjustments

Being able to adjust the color range of a gray scale image can be crucial to general image manipulation. This is generally known as Histogram Adjustment. The following are just some of the methods that can be used to do this.

FUTURE:

-normalise
     Try to stretch the image uniformly across all color channels so as to
     enhance the image.

     The channel operator can be used to 'disconnect' the uniformity across
     all channels, or alternatively you can separate and normalize each
     channel individually.  However when recombined you may find you get some
     color distortion due to each channel being stretched out unequally.

     Normalizing a intensity, or equivalent channel in some other colorspace
     can also be used to ensure correct normalization of the image without
     color distortions, though this is a much more trickier method.

     See also equalize, and (future) -equalize-gaussian, also look at Fred
     Weinhaus's scripts for various methods of image enhancements.

     In reality this operator is equivalent to  "-contrast-stretch 2%,99%"
     Which means at least 2% of the darkest color values will be set to zero
     (black) while the top 1% of the brightest pixels will be set to maximum
     (white) all the other pixels in the image are the stretched out to fill
     the whole range from black to white.

     If you do not which to 'burn' those top and bottom pixels, use
     "-contrast-stretch 0" to do a more 'logical normalize' of the image,
     without clipping or burning the top and bottom values.

-contrast-stretch
     normalize the image so that the given percentage of pixels in a greyscale
     image are mapped to black and white respectively.

     That is -contrast-stretch 5% will make at least 5% of all pixels in a
     greyscale image black, and at least 5% of the pixels white.

     NOTE that -normalize is defined as   -contrast-stretch 2%,99%

     If you really want a 'true' normalize using the exact minimum and maximum
     values, use   -contrast-stretch 0

     ASIDE: This currently does the value remapping using 'binned' color
     values, as as a result produces a slightly distorted 'stretch'.
     We are endeavouring to have this fixed to stretch the color values using
     the internal -level operator.

     Example:  an image that does not span the histogram. You
     can show a histogram plot or list. Then do -contrast-stretch 0% to
     show that the min and max of the image are now at black and white,
     resp. I think this is a good example as it stretches the histogram
     just enough to span the range as opposed to normalize with clip or
     burns or whatever you want to call it by 2% on the low end and 1% on
     the high end.

     People need to know that they can stretch the image to just exactly span
     the histogram and do not have to use -normalize and lose data.

-linear-stretch
     Finds the 'level' points for stretching by counting the number of pixels
     from each end, until it exceeds the counts given.


-equalize         histogram equalization of the image
     When one wishes to compare two or more images on a specific basis, such
     as texture, it is common to first normalize their histograms to a
     "standard" histogram.  The most common histogram normalization technique
     is histogram equalization where one attempts to change the histogram so
     that all the histogram colors are spread out equally over all brightness
     values. This would correspond to a brightness distribution where all
     values are equally probable. Unfortunately, for an arbitrary image, one
     can only approximate this result.

     Is it a image comparison technique?

Expand or Normalize gray-scale

To expand the gray scale image so it occupies the full range of gray values (maximize contrast) is straight forward using the "-normalize" operator. That is, the lightest gray becomes white and darkest gray, black.

Here we create a gray-scale gradient, and expand it to the full black and white range.

  convert -size 150x100 gradient:gray70-gray30 gray_range.jpg
  convert gray_range.jpg  -normalize  normalize_gray.jpg
[IM Output] ==> [IM Output]

For practical reasons to do with JPEG color inaccuracies (see JPEG Color Distortion for more details) and scanned image noise, "-normalize" does not expand the very brightest and darkest colors, but a little beyond those values. That is it is equivalent to a "-contrast-stretch" with a value of '2%,99%' (see below).

This means if highest and lowest color values are very close together, "-normalize" will fail, an no action will be taken.

If you really want to expand the exact brightest and darkest color values to their extremes use "-contrast-stretch" with a value of '0' instead.

Up until IM version 6.2.5-5, "-normalize" worked purely as a grayscale operator. That is each of the red, green, blue, and alpha channels were expanded independently of each other according to the "-channel" setting. As of IM version 6.2.5-5, if only the default "+channel" setting 'RGB' is given, then "-normalize" will tie together all the color channels, and normalizes them all by the same amount. This ensures that any grayscale that is in the image, remains grayscale. However if non-grayscale colors are present, it may not expand the image to produce a pure white or black level.

For example here we added some extra colors (a blue to navy gradient) to our normalization test image.

  convert -size 100x100 gradient:gray70-gray30 \
          -size  50x100 gradient:blue-navy  +append  color_range.jpg
  convert color_range.jpg -normalize  normalize.jpg
[IM Output] ==> [IM Output]

As you can see from the last example, for color images "-normalize" maximized all the channels together so one channel has a zero value, and another channel has a maximum value. That is, no black pixels were generated, as all the added blue colors already contains 'zero' values in the 'red' and 'green' channels. As such the lower bounds of the image did not expand.

If you want the old "-normalize" behaviour, you will need to use a different "-channel" setting than the default 'RGB' setting. For images that contain no alpha (or matte) channel, you can just use the 'all' channel setting.

  convert color_range.jpg -channel all  -normalize   normalize_all.jpg
[IM Output]

Alternatively, you can normalize each channel as a separate image using the "-separate" operator (as of IM v6.2.9-2), then "-combine" them back into a single image again.

  convert color_range.jpg -separate -normalize -combine normalize_sep.jpg
[IM Output]

The results of the above turns the grayscale areas of the image yellow As the 'red' and 'green' channels lightened. The 'blue' channel however is only darkened slightly.

This brings use to an important point
Normalise is really a grayscale operator,
caution is needed when used with color images.

contrast-stretch -- controlled normalize

The "-contrast-stretch" (added IM v6.2.6), is a more controlled version of "-normalize". It first finds the maximum and minimum bounds in the image, as normal, but then shifts those bounds further inward by the given amount of color inward before selecting the colors that will be mapped to white and black.

In other words it is still a "-normalize" type of operator, but then ignores the most extreme colors by the amount given (generally as a percentage of gray scale).

For example, this will replace both the top and bottom 15% of colors with their extremes (white and black), stretching the rest of the color to improve the overall contrast.

  convert gray_range.jpg  -contrast-stretch 15%  stretch_gray.jpg
[IM Output] ==> [IM Output]

And here I just grab the brightest 5% of colors, stretching them linearly, and making all other colors black.

  convert gray_range.jpg  -contrast-stretch 95x100%  stretch_black.jpg
[IM Output]

This can be quite useful, to find bright points in images. It is a bit like a normalized version "-black-threshold" operator, but with the other colors stretched to fill the full color range, rather than just turning the thresholded color black.

Note that "-contrast-stretch" is not a true contrast operator, as it normalizes the image first. If you want to improve the contrast of an image by a fixed amount that is independent of the actual images current content, then you should use "-level" instead.


DIY Level Adjustments

Mathematical Linear Histogram Adjustments

The various basic forms of "Level Adjustments shown above linearly adjust the colors of the image.

These changes can be applied mathematically as well. For example by multiplying the image with a specific color, we set all pure white areas to that color. So lets just read in our image, create an image containing the color we want, then multiply the original image with this color using the IM free-form "-fx" or DIY Operator.


  convert test.png  -size 1x1 xc:Yellow \
          -fx 'u*v.p{0,0}'    fx_linear_white.png
[IM Output] ==> [IM Output]

By getting "-fx" to read the color from a second 'v' image makes it easy to change the color, without needing to convert colors to RGB values for use in the mathematics.

If you were using a fancy graphical image processing package like "Gimp" and "Photoshop" the above operation would have been applied to an image by adjusting the images color histogram graph 'curve'.

[IM Output] For example to the right is a "gnuplot" generated graph (See the script "im_histogram") of the mathematical formula showing what happens to just one of the three RGB channels. The original color (green line) is remapped to a darker color (red line) linearly.

Linearly tinting the black colors is also quite simple. For example to linear map 'black' to a gold like color 'rgb(204,153,51)', (while leaving 'white' as 'white'), would require a mathematical formula such as...
          result = 1-(1-color)*(1-intensity)
This formula negates the colors, multiples the image with the negated color wanted, and negates the image back again. The result is tinting of the black side of the gray scale, leaving white unchanged.


  convert test.png  -size 1x1 xc:'rgb(204,153,51)'  \
          -fx '1-(1-v.p{0,0})*(1-u)'   fx_linear_black.png
[IM Output] ==> [IM Output] ==> [IM Output]

A "gnuplot" histogram graph of the remapping formula is also displayed in the above for your reference.

With a slightly more complicated formula you can linearly replace both the 'black' and 'white' end of the grayscale with specific colors.

  convert test.png  -size 1x2  gradient:gold-firebrick \
          -fx 'v.p{0,0}*u+v.p{0,1}*(1-u)'   fx_linear_color.png
[IM Output] ==> [IM Output] ==> [IM Output]

The "-size 1x2 gradient:color1-color2" in the above is only used to generate a two color pixel image for the "-fx" formula to reference. The first color replaces white, while the second replaces black, while all others are interpolated between white and black. As is typical of a gray-scale operator, each RGB channel is treated as a separate gray scale channel, though the linear interpolation is different for each channel.

This by the way is exactly equivalent to the Level Adjustments by Color operator "+level-colors"

However unlike "+level-colors", the colors to use can of course come from any image source, and not just the color names provided as an argument. However even direct use of color names is posible.

  convert test.png   -fx "yellow*u+green*(1-u)"  fx_linear.png
[IM Output]

Mathematical Non-linear Histogram Adjustments

While linear color adjustments are important, and faster methods ar available, there are many situations where a linear 'level' adjustment, is not what is wanted, and this is where the "-fx" DIY Operator, becomes more useful.

Well an alternative formula for linear adjustment is "-fx 'v.p{0,1}+(v.p{0,0}-v.p{0,1})*u'", which has the advantage that the 'u' can be replaced by a single random function 'f(u)' to produce non-linear color change.

This lets you do more interesting things. For example what if in the last example you wanted to push all the colors toward the 'black' side, resulting in the image being a more 'firebrick' color.

  convert test.png -size 1x2  gradient:gold-firebrick \
          -fx 'v.p{0,1}+(v.p{0,0}-v.p{0,1})*u^4'  fx_non-linear.png
[IM Output] ==> [IM Output] ==> [IM Output]

In a more practical example, Adelmo Gomes needed a color adjustment for a automated Weather Map Recoloring script he was developing.

In this case he wanted to tint pure black parts of the image to a .25 blue, but leave the rest of the gray-scale alone, especially the white and mid-tone grays of the image. Only the blue color needed such adjustment, which he currently was doing by hand in an image editor.

For example you could use a quadratic formula like 'u^2' to tint the black end of the histogram to a '.25' blue color. Only the blue channel needs to be modified, so the value was inserted directly into the formula.

  convert test.png  -channel B  -fx '.25+(1-.25)*u^2'  fx_quadratic.png
[IM Output] ==> [IM Output] ==> [IM Output]

However while this produced a reasonable result it does darken the mid-tone grays slightly, producing a sickly off-yellow color.

To avoid this a 'exponential' function can be used instead, to give better control of the tinting process.

  convert test.png  -channel B  -fx '.3*exp(-u*4.9)+u'  fx_expotential.png
[IM Output] ==> [IM Output] ==> [IM Output]

Again the graph show how blue channel was modified to give black a distinctive dark blue tint.

The second value ('4.9') is the falloff back to a linear '+u' graph. The smaller this value is the slower the fall off, and the more linear the adjustment becomes. The larger the value, the more dramatic the 'fall-off'. The value may need to be adjusted for different color values, so this is not a good general formula for general black color tinting, but perfect for tinting weather maps.

Generally if you can express the color adjustment you want mathematically, you can then use "-fx" operator to achieve the results you want.

'Curves' Adjustments

[popup] Normally in a graphical photo editor you would be presented with a histogram 'curves' chart such as I have shown to the left. The user can then edit the 'curve' by moving four (or more) control points, and the histogram adjustment function will follow those points.

The control points generally specify that the first grayscale level is after adjustment to become the second grayscale level. So a point like 0.0,0.2 basically means that a 0% gray (black) should after adjustment be a 20% gray level.

Now IM does not allow you to directly specify 'control points' to generate a 'curve' adjustment, what it wants is the mathematical formula of that 'curve' generated. Lucky for us there are programs that can generate that curve formula from the control points, including "gnuplot", "fudgit", "mathematica", and "matlab", as well as many more mathematical software packages.

The following is one method you can use to generate the formula from four control points using "gnuplot" which is a standard extra package you can install on most linux distributions (and is available for Windows too)...

  ( echo "0.0 0.2";  echo "1.0 0.9"; \
    echo "0.2 0.8";  echo "0.7 0.5"; )   > fx_control.txt

  ( echo 'f(x) = a*x**3 + b*x**2 + c*x + d'; \
    echo 'fit f(x) "fx_control.txt" via a, b, c, d'; \
    echo 'print a,"*u^3 + ",b,"*u^2 + ",c,"*u + ",d'; \
  ) | gnuplot 2>&1 | tail -1             > fx_funct.txt
[Data]
Control Points
==> [Gnuplot]
[Gnuplot]
Gnuplot Fitted FX Function

Note that the number of parameters ('a' to 'd' in above) needed for curve fitting, must equal the number of control points you provide. As such if you want five control points you need to include another 'e' term to the function.

If your histogram curve goes though the fixed control points 0,0 and 1,1, you really only need two parameters as 'd' will be equal to '0', and 'c' will be equal to '1-a-b'.

As you can see from the extra "gnuplot" generated image above, the function generated fits the control points perfectly. Also as it generated a "-fx" style formula it can be used as is as an IM argument.

For example...

  convert test.png    -fx "`cat fx_funct.txt`"     fx_funct_curve.png
[IM Output]

To make it easier for users to convert control points into a histogram adjustment function, I have created a shell script called "im_fx_curves" to call "gnuplot", and output a nicer looking polynomial equation of the given the control points. Gabe Schaffer, also provided a perl version (using a downloaded "Math::Polynomial" library module) called "im_fx_curves.pl" to do the same thing. Either script can be used.

For example here is a different curve with 5 control points...

    im_fx_curves  0,0.2  0.3,0.7  0.6,0.5  0.8,0.8  1,0.6  > fx_curve.txt
[Gnuplot] ==>
[Gnuplot]

Or you can use it to generate linear histogram adjustment functions, by using only two control points, which do not need to be the black and white points either.

    im_fx_curves -p   20,60  80,10    > fx_linear.txt
[Gnuplot] ==>
[Gnuplot]

Note that in the above I used a '-p' option, allowing me to specify the control points as percentiles of gray scale levels, which is easier for us humans to handle.

The function produced above is only useful as a grayscale adjustment, you can not normally use this method to convert a grayscale into a specific color gradient, as we did above in Linear Histogram Adjustments. Of course you can tint or add color to the result afterward.

For a practical example of this method is detailed in the advanced "Aqua" Effects example.

Remember a complex "-fx" functions, are very slow as it is being interpreted by IM three to four times for every pixel. If you plan to use a complex "-fx" function such as this, over a lot of images, you can speed it up enormously by converting the Function into a CLUT (see below).


Tinting Images

Uniformly Color Tinting Images

Typically tinting an image is achieved by overlaying the image with a very specific color that is made semi-transparent (dissolved) by a certain amount. This can be done using an Evaluate Operator or Blend Images techniques, but these are not simple to use.

Lucky for us a simpler method of overlaying a uniform color over an image is available by using the "-colorize" image operator. This operator overlays the current "-fill" color, dissolved by the percentage argument, over the current image in memory. The alpha channel of the original image is preserved, with only the colors being tinted by the dissolved overlay color.

For example lighten an image (gray scale or otherwise) we use "-colorize" to overlay a semi-transparent white image. The argument given defined how transparent the overlay color is.

  convert test.png  -fill white -colorize 50%  colorize_lighten.png
[IM Output] ==> [IM Output]

Similarly we use a 'black' fill color to darken an image.

  convert test.png  -fill black -colorize 50%  colorize_darken.png
[IM Output] ==> [IM Output]

To gray both ends of the image toward the mid-tones, you would use a specific gray fill color. The color 'gray50' is the exact middle color of the RGB color spectrum.

  convert test.png  -fill gray50 -colorize 40%  colorize_grayer.png
[IM Output] ==> [IM Output]

The "-colorize" operator also allows you to specify dissolve percentages for each of the three color channels separately. This is useful for linearly darkening (or lightening) an image in a special way.

One common use of the "-colorize" operator is to simply replace all the colors in an existing image (tinting '100%') to generat a shape mask.

  convert test.png -fill blue -colorize 100%   colorize_shape.png
[IM Output]

Or by reseting the alpha channel, make a completely blank canvas..

  convert test.png -fill blue -colorize 100% -alpha opaque colorize_blank.png
[IM Output]

However these functions can be handles faster by using Level Adjustments by Color operator, with a single color. See also Blank Canvases.

Midtone Color Tinting

While a "-colorize" operator applies the "-fill" color to tint all the colors in an image linearly, the "-tint" operator applies the "-fill" color in such a way as to only tint the mid-tone colors of an image.

The operator is a grayscale operator, and the color is moderated or enhanced by the percentage given (0 to 200). To limit its effects it is also adjusted using a a mathematical formula so that it will not effect black and white. but have the greatest effect on mid-tone colors of each color channel.

A "-tint 100" essentially will tint a perfect gray color so that it becomes the current fill color. A lower value will tint it to a darker color while a higher value will tint to a lighter shade of that color.


  convert  test.png  -fill red  -tint 40 tint_red.png
[IM Output] ==> [IM Output]

The green color in the test image is not a true RGB green, but a Scaled Vector Graphics 'green', which is only half as bright as a true green color. As such it is also a mid-tone color, and thus is effected by the "-tint" operator, becoming darker, unlike red and blue color spots of the test image.

Also you can tint the individual color components, by using a comma separated list of percentages. For example "-tint 30,40,20,10". This however can be tricky to use and may need some experimentation to get right.

The tinting operator is perfect to adjust the results of the output of "-shade", (See Shade Overlay Highlight Images), such as the examples in 3d Bullet Images.

[IM Output] The "-tint" operator works by taking the color and percentages given then then adjusting the individual colors in the image according to the "-fill" colors intensity, as per the following formula. (see graph right)
f(x)=(1-(4.0*((x-0.5)*(x-0.5))))
A quadratic function, the result of which is used as vector for the existing color in the image. As you can see gives a complete replacement of the color for a pure mid-gray, with no adjustment for either white or black.

You can also use "-tint" to brighten or darken the mid-tone colors of an image. This is sort of like a 'gamma adjustment' for images, though not exactly.

For example using a tint value greater than 100 with a 'white' color will brighten the mid-tones.

  convert  test.png  -fill white  -tint 130 tint_lighter.png
[IM Output] ==> [IM Output]

While a value less than 100 will darken colors.

  convert  test.png  -fill white  -tint 70 tint_darker.png
[IM Output] ==> [IM Output]

As "-tint" uses the color as a 'vector' in color space, a "-fill" color of 'black' will have no effect on the result, as it produces a zero color vector.

Of course their are other ways of color tinting images...

DIY Color Tinting

One of the biggest problems with "-tint" is that it is a grayscale (or vector) operator. That is it handles each of the red,green,blue channels completely separately to each other. That in turn means that a primary and secondary color like 'blue' or 'yellow' are not effected by "-tint".

However thanks to the "-fx" you can create your own tinting method, by using it to create a color overlay so that it works in a similar way to the "-colorize" operator. (see Uniformly Color Tinting Images).

For example, here I convert an image's 'intensity' or grayscale brightness level into a 'mid-tone tinting overlay' image to tint grayscale midtone 'gold'.

  convert test.png \( +clone -matte  -channel A \
          -fx 'tint=intensity-.5; (1-4*tint*tint)*a* 1.0' +channel \
          -fill gold -colorize 100% \) -composite  tint_diy.png
[IM Output]

The final '1.0' is equivalent to a 100% level of tinting, so you can reduce that figure to moderate the amount of tinting.

Note that while similar to "-tint" it uses the "-colorize" overlay method instead of a color vector approach, so primary colors are also tinted 'gold' leaving only 'white' and 'black' colors as is.

You can also change the 'intensity' to other things like 'lightness', for other tinting methods.

Of course please let me know what you come up with.

Overlay Color Tinting

The special Alpha Composition methods 'Overlay' and 'Hardlight' were actually designed with color (and pattern) tinting in mind. These compose methods also will replace mid-tone grays leaving black and white highlights in the image alone.

For example here I quickly generate a colored overlay image, and compose it to tint the original image.

  convert test.png \( +clone +matte -fill gold -colorize 100% \) \
          -compose overlay -composite  tint_overlay.png
[IM Output]

As you can see the alpha composition does not preserve any transparency of the original image, requiring the use of a second alpha composition operation to fix this problem.

  convert test.png \
          \( +clone +matte -fill gold -colorize 100% \
             +clone +swap -compose overlay -composite \) \
          -compose SrcIn -composite  tint_overlay_fixed.png
[IM Output]

Alternatively, as we are generating a solid color overlay from the source image, you can leave the alpha channel in the source image intact, to active a similar result, though it doesn't quite the correct transparency.

  convert test.png \( +clone -fill gold -colorize 100% \) \
          -compose overlay -composite tint_overlay_alpha.png
[IM Output]

Using 'Overlay' is much more linear form of tinting than the quadratic function used above, and like "-tint" is applied to each channel of the image separately such that primary and secondary colors are also left unchanged. The 'SVG green' color is of course effected as it is a half bright green.

Also no adjustment control is provided by this alpha composition method, so if you want to control the level of tinting, you will need to adjust the overlay image transparency before applying the tint.

Of course unlike the other tinting methods I have shown so far, you are not limited to tinting a simple color, but can apply a tint using an image, or tile pattern.

  convert test.png \
          \( -size 150x100 tile:tile_disks.jpg \
             +clone +swap -compose overlay -composite \) \
          -compose SrcIn -composite  tint_overlay_pattern.png
[IM Output]

This however is getting outside the scope of basic color handling so I'll leave image tinting at that.

The alpha composition method 'HardLight' will produce the same results as 'Overlay' but with the source and destination images swapped.

This could have been used instead of the "+swap" in the last two examples.


Global Color Modifiers

Modulate Brightness, Satuartion, and Hue

The "-modulate" operator is special in that it modifies an image in the special HSB (hue-saturation-brightness) colorspace. It converts each color pixel in into this color space and modifys it and converts it back to its original color space.

It takes three values (though later values are optional) as a percentage such that 100 will make no change to an image. For example..

  convert  rose:  -modulate 100,100,100  mod_noop.gif
[IM Output]

The first value, brightness is a multiplier of the images overall brightness.

  convert rose:   -modulate 0     mod_bright_0.gif
  convert rose:   -modulate 50    mod_bright_50.gif
  convert rose:   -modulate 80    mod_bright_80.gif
  convert rose:   -modulate 100   mod_bright_100.gif
  convert rose:   -modulate 150   mod_bright_150.gif
  convert rose:   -modulate 200   mod_bright_200.gif
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Note that while a brightness argument of '0' will produce a pure black image, you can not produce a pure white image using this operator on its own.

The second value saturation is also a multiplier adjusting the overall amount of color that is present in the image.

  convert rose:   -modulate 100,0     mod_sat_0.gif
  convert rose:   -modulate 100,20    mod_sat_20.gif
  convert rose:   -modulate 100,70    mod_sat_70.gif
  convert rose:   -modulate 100,100   mod_sat_100.gif
  convert rose:   -modulate 100,150   mod_sat_150.gif
  convert rose:   -modulate 100,200   mod_sat_200.gif
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

A saturation of '0' will produce a grayscale image, as was exampled in Converting Color to Gray-Scale above. The gray however mixes all three color channels equally, as defined by the HSB colorspace. Small values produce more 'pastel' colors, while values larger than '100' will produce more cartoon-like colorful images.

The final value, Hue, rotates the colors of the image, in a cyclic manner.

  convert rose:   -modulate 100,100,0      mod_hue_0.gif
  convert rose:   -modulate 100,100,33.3   mod_hue_33.gif
  convert rose:   -modulate 100,100,66.6   mod_hue_66.gif
  convert rose:   -modulate 100,100,100    mod_hue_100.gif
  convert rose:   -modulate 100,100,133.3  mod_hue_133.gif
  convert rose:   -modulate 100,100,166.6  mod_hue_166.gif
  convert rose:   -modulate 100,100,200    mod_hue_200.gif
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

As you can see a value of '33' produces a negative, or counter-clockwise rotation of all the colors by 60 degrees, effectivally mapping the red to blue, blue to green, and green to red. Using values of '0' or '200' produces a compete 180 degree negation of the colors, without negating the brightness of the image. A value of '300' will produce a 360 degree in color rotation resulting in no change to the image.

These type of operations and more can be applied using advanced Color Space techniques, such as demonstrated in Combining non-RGB Channel Images, but for basic 'modulation' of an image the above simplifies things.

Recolor Matrix Operator


-recolor   translate, scale, shear, or rotate image colors
           (good for hue changes)

  Each of the rows of the matrix represents the value assignment
  for each channel in the image.
  As such the first three numbers is the color formula for the
  'red' channel. the next for 'green' and so on

  As such the following will swap the red and blue channel color,
  but leave the green channel as is.

        convert rose: -recolor ' 0 0 1
                                 0 1 0
                                 1 0 0 '  rose_blue.png

  And this example makes a grayscale image using a 2/5/3 ratio
  by using the same formula for all color channels.

        convert rose: -recolor ' .2 .5 .3
                                 .2 .5 .3
                                 .2 .5 .3 '  rose_gray_253.png

  The matrix is applied such that each row represents the formula
  for each channel in turn.  As such the first row translates to

       new_red =  .2*red + .5*green + .3*blue

  And so on, with all the colors being calculated before finally being
  assigned back into the original image.


  If a 4x4 matrix is used the transparency channel is also included
  While a 5x5 matrix will also include the 'blacK' channel for CMYKA images.


  Vivid colors, in a technique called  Digital Velvia
     From http://www.reflectiveimages.com/digitalvelvia.htm
  For example this will produce a 20% vivid color image operation...
        convert rose: -recolor ' 1.2 -0.1 -0.1
                                -0.1  1.2 -0.1
                                -0.1 -0.1  1.2 '  rose_vivid.png

  These matrices brighten that color channel while subtracting
  the colors from the other channels, making colors more vivid
  in the RGB image.  Each row should add to a value of 1.0 to preserve
  the images overall brightness.

  Note that this is not the same as using -modulate to increase an images
  color saturation by 20%.


Replacing Colors in Images

Replace a Specific Color

The "-opaque" and "-transparent" operators are designed for replacing one color in an image with another.

For example to replace a 'blue' color with say 'white' you would use a command like this...

  convert balloon.gif  -fill white -opaque blue   balloon_white.gif
[IM Output] ==> [IM Output]

Basically any color that was 'blue' has been replaced with the current "-fill" color.

However as of IM v6.2.7, this operator limited by the -channel setting. As such to convert a color (say blue) to transparency you will need to specify a "-channel" to include the alpha channel in the output changes, You will also need to ensure the image has a 'matte' or alpha channel too.


  convert balloon.gif   -matte -channel RGBA \
                        -fill none -opaque blue   balloon_none.gif
[IM Output] ==> [IM Output]

Because replacing a color with transparency is such a common operation the above has its own special replace with transparency operator "-transparent".

  convert balloon.gif  -matte -transparent blue   balloon_trans.gif
[IM Output] ==> [IM Output]

As of IM version 6.3.7-10, the 'plus' versions of these operators invert the color selection. That is the colors that do NOT match the given color will be replaced. For example here I replace any color that is NOT black, with white, leaving just the black borders of this image.

  convert balloon.gif  -fill white +opaque black   balloon_borders.gif