- Index
ImageMagick Examples Preface and Index
Image Negation
(Making white, black, and black, white)
Converting Color to Gray-Scale
(Making grayscale images)
Histogram Adjustments
(adjusting colors in an image)
Tinting Grays
(adjusting just the mid-tone gray, preserve highlights)
Color Adjustments
(adjusting the colors slightly)
Replacing Colors in an Image
(replacing individual colors)
Recoloring Images with Gradients
Miscellanious Color Operators
(special recoloring operators)
Color modifications to 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.
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.
|
|
Image Negation
The simplest and most basic global color modification you can do is a color
negation, using the "
-negate" image operator.
Essentially this makes white, black, and black, white,
but it also make red, its color negative of a brighter cyan, and blue,
yellow, etc.
convert test.png -negate negate.png
|
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
|
As you can see the results was not all that interesting, except where we also
have some semi-transparent pixels. However it is still very useful when you
are dealing with image masks and other image processing.
On the other hand you can limit the negation to just one channel, say the
green color channel.
convert test.png -channel green -negate negate_green.png
|
The "
-negate" operator is
actually its own inverse. Doing two negations cancels each other out.
convert negate_green.png -channel green -negate negate_restore.png
|
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.
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
|
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_brightness.png
| |
|
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
| |
|
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
| |
|
You can also use 'intensity' if you want the same meaning within the "-fx" operator.
convert test.png -fx intensity gray_intensity.png
| |
|
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
| |
|
  |
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 simular 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
| |
|
Another even faster alturnative is to use the "-recolor" color matrix operator.
convert test.png -recolor '.2 .5 .3 \
.2 .5 .3 \
.2 .5 .3' gray_recolor.png
| |
|
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 recomended 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_luminance.gif
convert rose: -colorspace YUV -channel R -separate channel_luma.gif
|
|
|
Gray RGB
|
Neg Black CMYK
|
Brilliance HSB
|
Luminance HSL
|
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
| |
|
  |
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 ImageMagicks 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 :-)
|
Histogram gray-Scale 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.
Under Construction
This whole section is scheduled for a re-write and possibly moved to a
completely separate page.
First. note that -contrast-stretch and -normalize are the same function.
By default normalize find the highest and lowest color value in any RGB channel
then moves inward by 1% of the color range (to account for JPEG 'ringing'
color distortions) At this point all three color channels are then stretched.
The contrast-stretch does the same thing but you can specify the amount of
inward movement. often it is used with a '0' argument to prevent color
'clipping'.
For exact controls, you can either use -linear-stretch which you provide a
percentage to move the black and white point inward by, either as one or two
arguments. For example -linear-stretch 20% expands the 20% to 80% color
range.
The other exact method is -level which can specify the new black and white
points directly.
Fred Weinhaus, is currently working on a new set of general histogram
handling methods, as a series of shell scripts. These will eventually
be built into IM to revolutionize general color controls within IM.
This includes... linear stretching and de-contrast handling, auto-leveling
using various methods to select the black and white points which is more
like the Photoshop/Gimp auto-leveling methods. LUT histogram color
replacements, 'curves' using various methods of fitting the functions to
control points. and probably lots more.
Ok, back to our regularly scheduled examples.... :-)
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
|
  |
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 equivelent to a
"-contrast-stretch" with a value of '1%' (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
|
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 that 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
| |
|
Alturnativally, you can normalize each channel as seperate images 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
| |
|
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
|
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
| |
|
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.
FUTURE:
-linear-stretch More exact user controls for color stretching.
-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.
It is a image comparision technique?
For a less linear contrast control you should use the "
-sigmoidal-contrast"
operator, that applies a expotential contrasting function. For details see
Sigmoidal Non-linearity Contrast below.
Note that "
-level" can also be used to specify
the actual values to use for the normalization, or contrast stretching.
See
General Color Level Adjustments below.
graying gray-Scale (de-normalize)
Currently the only way of de-normalizing an image, that is making white and
black a specific gray value, is to tint the whole image with a certain amount
of white or black coloring. Hopefully a more versatile solution will be made
available soon.
So lets move on to color tinting images.
Uniformly Color Tinting Images
Typically tinting an image is achieved by overlaying the image with very
specific color that is made semi-transparent (dissolved) by a certain amount.
This can be done using a
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 colorize with a
'
white' color, while its 'dissolve' argument determines how much
'white' is added to each pixel in the image.
convert test.png -fill white -colorize 50% gray_lighten.png
|
Similarly we use a '
black' fill color to darken an image.
convert test.png -fill black -colorize 50% gray_darken.png
|
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% gray_grayer.png
|
You can see this technique used in
Watermarking Images, to adjust the watermark image before it is applied to
the image being watermarked.
  |
If you want to specify a specific gray level to map white and black colors,
you can do so with the following formula to work out the dissolve and gray
percentage.
dissolve_percentage = black_gray_level - white_gray_level + 1
background_gray_level = black_gray_level / disolve_percentage
Where white -> white_gray_level,
and black -> black_gray_level
|
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.
Mathematical Linear Histogram Adjustments
Using "
-colorize" to overlay various shades of gray may seem a complex
way of adjusting the colors of an image, and your right it is. But it is
an easy way to apply such changes.
What you are actually doing in the above is a "Linear Histogram Adjustments"
of the image. That is we are changing what should be a pure white color to
some other color ,and pure black to another color, and then adjusting all the
other colors to match that change.
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 mathematics operator "
-fx".
convert test.png -size 1x1 xc:LightSteelBlue \
-fx 'u*v.p{0,0}' fx_linear_white.png
|
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]](fx_linear_white_plot.gif)
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
|
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
|
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 these two. 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.
The colors to use can of course come from any image source, even the original
image itself, or just inserted directly in the formula. For example...
convert test.png -fx "yellow*u+green*(1-u)" fx_linear.png
| |
|
This general linear color adjustment also makes a great way to lighten,
darken, or de-normalise grayscale images in preparation for further
processing. In fact up until this point just about everything on this page
(with exception of converting images to grayscale) have been linear color or
histogram adjustments. Even "
-negate" and "
-normalize" is a form of linear color adjustment.
Faster gray-scale Linear Adjustments
Unfortunately the "
-fx"
operator is a interpreted function (a slow operation) which is interpreted
three to four times for every pixel. In other words for large images, it can
become extremely slow.
For complex "
-fx" functions
you can speed things up by Converting the
FX function to
Lookup Table Images (see below).
However a faster method for gray-scale or per-channel changes can be done
using the
Evaluate Math Functions.
However remember that the values are clipped to the image color values limits
at the end of every "
-evaluate" option. This makes them harder to use.
Lightening -evaluate multiply .5
Darkening -negate -evaluate multiply .5 -negate
Treshold lower 50% -evaluate Subtract 50%
Mathematical Non-linear Histogram Adjustments
While linear color adjustments are important there are many situations where
that is not what is wanted.
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
|
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
|
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
|
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.
Histogram 'Curves' Adjustments
![[popup]](histogram_curves.gif)
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
|
|
Control Points
|
|
|
| |
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
| |
|
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::Polynomal" 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
|
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
|
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 LUT
(see below).
Tinting Gray Colors
Color Tinting grays
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 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
|
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, becomming
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.
  |
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.
|
Brightening and Darkening the Mid-tones
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
|
While a value less than 100 will darken colors.
convert test.png -fill white -tint 70 tint_darker.png
|
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 seperatally 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 simular way to the "
-colorize" operator. (see
Uniformly Color Tinting Images).
For example here I convert an images '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
| |
|
Note that while simular 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.
The final '
1.0' is equivelent to a 100% level of tinting, so you
can reduce that figure to moderate the amount of tinting. You can also change
the '
intensity' to other things like '
luminosity',
for other tinting methods.
Of course please let me know what you come up with.
Overlay Color Tinting
The special
Alpha Composition method
'
Overlay' was actually
designed with color (and pattern) tinting in mind. This compose 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
| |
|
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
| |
|
This is much more linear than the quadratic funtion 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 if you want to actually control the level of tinting, you will
need to adjust the overlay image's transparency level.
And finally unlike the other tinting methods I have shown so far, you are not
limited to tinting a simple color, but can tint the grays using a 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
| |
|
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.
|
Color Adjustments
The adjustments above are good for general manipulation of a grayscale
histograms, and psuedo-color scientific images, but be general photographic
color adjustments it isn't very good.
For photographic style images, ImageMagick provides a whole range of
color correction and adjustment operators.
General Color Level Adjustments
The "
-level" operator is
designed to adjust both the ends and the the mid-range colors of
photograph-like images. It takes three comma separated numbers as arguments.
The first and second arguments, define the level which will be pegged at black
and white respectively (known as the black-point and white-point). Any colors
which fall outside those grayscale levels will be pegged at the color limits
of the image. Generally it is better to express these as percentages, rather
than pixel level values (which depend on IM compiled 'Q' level).
The third value the 'gamma' level and is equivalent to using the "
-gamma" operator. This will
lighten or darken the overall image according to the factor given. A value of
1.0 produces no change while
0.1 make the image
extremely dark, to
10.0, for blindingly bright. This is a
general non-linear adjustment.
For example a "
-level 0%,100%,1.0" will produce no change in the
image.
convert rose: -level 0%,100%,1.0 rose_no_change.gif
| |
|
While adjusting the black and white 'points' inward will increase the overall
contrast of the image, a little...
convert rose: -level 5%,95%,1.0 rose_contrast.gif
| |
|
Or increase the contrast a LOT...
convert rose: -level 20%,80%,1.0 rose_contrast2.gif
| |
|
By leaving the black point alone and decreasing both the white point,
we can brighten the highlights of the image without destroying shadows
or making the image too bright.
convert rose: -level 0,80%,0.8 rose_highlight.gif
| |
|
The gamma factor in the above was also decreased, so as to also brigthen the
image slightly, to offset the general decrease caused by the reduction in
white point brightness.
Thanks goes to Gabe Schaffer <magick@gabe.com> for the above
examples and explanation.
  |
At the moment you can not specify white and black points that are outside
the 0 to 100% range. Being able to do this will allow you to decrease the
contrast of an image, and not being able to could probably be considered a
bug.
|
Gamma brightness Adjustments
The the "
-gamma" operator
is a general mid-tone gray level adjustment that is closer to changing the
brightness of images in real life. That is, it will lighten or darken the
overall image according to the factor given. A value of
1.0
produces no change while
0.1 make the image extremely dark, to
10.0, for blindingly bright. This is a general non-linear
adjustment.
As you saw above the "
-level" operator provides a general method of gamma adjustment.
However the "
-gamma"
operator provides the means to control the brightness levels of each color
channel separately. For example "
-gamma 1.7,2.3,1.2".
This feature is great for general tint adjustments for images, such as
reducing the red in images involving lots of blue sky.
FUTURE:
Red kite image adjustment.
-contrast and +contrast
-equalize Automatic adjustment? How does this differ to -normalise
  |
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.
|
Sigmoidal Non-linearity Contrast
From a PDF paper on '
Fundamentals of
Image Processing' (page 44) they present a alturnative 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 acutally very simple expotential 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
point of the highest gradient 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
|
Lucky for us IM v6.2.1 had this complex function builtin as a new operator
"-sigmoidal-contrast", allowing a much simpler application.
convert test.png -sigmoidal-contrast 10,50% test_sigmoidal.png
| |
|
As a bonus IM also provides the inverse, a 'sigmodial 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
| |
|
And here we apply it to the rose image...
convert rose: -sigmoidal-contrast 10,50% rose_sigmodial.gif
| |
|
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.
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
| |
|
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
| |
|
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
| |
|
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
| |
|
This may not seem like much, but when you combine it with a
Fuzz Factor see below, this becomes very powerful.
Before IM v6.3.7-10, the inverse operation required the use of some trickiness
using image masks. Basically you replace the color you want to preserve with
transparency, then "
-colorize" all the other colors to the desired color to create an
overlay mask. This is then overlaid on the original image to 'mask out' the
colors that did not match!
convert balloon.gif \
\( +clone -matte -transparent black \
-fill white -colorize 100% \) \
-composite balloon_mask_non-black.gif
| |
|
As you can see the 'plus' form of the operator simplified the 'not this color'
operation enormously.
For more advanced replacement techniques, I suggest you look at
Transparency Masking.
  |
Be warned that as all matching colors (especailly 'fuzzy matched colors',
see below) are replaces with a single uniform color, you will not get any
anti-aliasing of the edges of the colored areas. This can have a
detremental effect to the look off any non-cartoon like images.
This type of color replacement is not designed with practical real world
images in mind, but more for image masking effects. Caution is advised.
|
Replace using a Image Color
You can also use
Draw Color Replacement to
recolor images based on colors present in the image itself, rather than a
specific color.
-fill blue -draw 'color 0,0 replace'
The advantage of using "
-draw" is that you can also replace the color with a tile pattern.
For example..
-tile tile_rings.jpg -draw 'color 0,0 replace'
However unlike "
-opaque"
and "
-transparent"
You can only use a color found at a specific location in the image. If you
want more direct control of the colors being replaced the simplest method is
to just append a one pixel strip of the desired color, do the replacement
then remove it again...
-fill blue -background white -splice 1x0+0+0 \
-draw 'color 0,0 replace' -chop 1x0+0+0
Floodfill Areas of Color
-fill red -fuzz 5% -floodfill +10+10 white
Replace any color that within 5% of 'white' to 'red' that is directly part of
the area surrounding the seeding pixel 10,10. Note that the 'seeding pixel'
must itself be close enough to 'white' to match otherwise no action will be
taken. This 'do nothing if no match' is particularly useful to ensure that
the color of the area is the expected color.
However this operator is
Channel Effected
which basically means by default it will not replace the transparency of an
image. If you want to make holes in an image you will need to use a
a "
-channel" setting of
'
RGBA' to include the alpha or matte channel of the image.
Usually the color being replaced is the background canvas of the image.
However the various parts of the background may not be attached to each other,
for example between a persons legs. Adding a border of the same 'color to
replace' around the image is a good way of ensuring that all outside areas of
the image are also filled.
-fill red -bordercolor white -border 1x1 \
-fuzz 5% -floodfill 0,0 white -shave 1x1
Floodfill a Color in Image
If you just want to select an area to floodfill, without selecting a specific
color for matching purposes, than using a
Draw
Color Replacement method make work better.
-fill red -fuzz 5% -draw 'color 20,20 floodfill'
This will compare any color that is with 5% of the color found at 20,20, and
replace it with the fill color. However unless you initially set the color of
0,0 you do not have direct control of the color that is being replaced.
You can however just set the comparison color at that point, before
flood filling.
-fill navy -draw 'color 20,20 point'
-fill red -draw 'color 20,20 floodfill'
For floodfilling background areas around the outside of the image the same
border method as shown for
-floodfill can be used, but the result is exactly the same as that
option.
-fill red -bordercolor white -border 1x1 \
-draw 'color 0,0 floodfill' -shave 1x1
Both
-floodfill and
Draw Color Replacement can replace colors with a
tile pattern rather than a specific color.
-tile tile_rings.jpg -bordercolor white -border 1x1 \
-draw 'color 0,0 floodfill' -shave 1x1
For more advanced flood filling techniques I suggest you look at
Transparency Masking.
Fuzz Factor - Matching Similar Colors
The overall results of just selecting a single color to replace, as shown in
the previous examples is usually not very nice. The edges or areas of solid
colors generally have a mix of colors at the edge, due to anti-aliasing (See
Anti-Aliasing for more information. As such
you should avoid direct color replace if possible.
EXAMPLE: floodfill
You can improve the selection of the area being recolored, by setting a
"
-fuzz" factor setting.
Here for example we tell IM that other colors 'close' to the one selected is
also OK to be replaced.
EXAMPLE: fuzzy floodfill
As you can see we now replaced even the pixels closer to the edge of the
image. This isn't perfect and replacing the backgrounds of images like this
is a difficult task. For more on this specific problem see
Re-adding Transparency to an Image.
The fuzz factor, technically represents a 'similarity' match in
multi-dimensional spherical distance between colors, using whatever color
space the image is using.
Well okay lets try that in plain English. You have a specific color. Another
color will be treated as being same as the first color if the difference
between these two colors is less than the currently fuzz factor setting.
A "
-fuzz" setting of
'
200' represents a distance of 200 units in the current color
depth of the IM being used, for a IM Q16 (16 bit quality for color store)
this is quite small, for a IM Q8 this is VERY large, and will cause a lot of
colors to match each other.
Here for example I change all the colors that are within 3000 color units of
'blue' to white. With my Q16 ImageMagick programs, that
represents about the distance from 'blue to 'navy
blue' (about 25% as a percentage, see below).
convert colorwheel.png -fuzz 30000 -fill white -opaque blue opaque_blue.jpg
| |
|
To make this easier to understand here I invert the matched colors
turning the unmatched colors to white.
convert colorwheel.png \
-fuzz 30000 -fill white +opaque blue \
opaque_blue_not.png
| |
|
  |
If your IM is older than version 6.3.7-10 when the 'plus' form of the
"-opaque" operator was
added, you can use this masking method to invert the result of the color
match...
convert colorwheel.png \
\( +clone -fuzz 30000 -transparent blue \
-fill white -colorize 100% \) \
-composite opaque_blue_inv.png
| |
|
|
  |
As a matter of interest, in a IM with a Q8 compilation setting, a
"-fuzz" factor of 256
(28) will make the colors 'black' and
'blue' the same. For a IM with a Q16 setting this number is
65536 (216).
To make 'blue' and 'red' colors match this
number must be multiplied by the square root of 2, or 362 for IM Q8,
and with 92682 for IM Q16.
Finally to make all colors match (eg colors 'black' and
'white') you will need to multiply by the square root of 3.
In other words, a fuzz factor setting of 444 for IM Q8 and 113512 for IM
Q16.
|
As you can see from the above formulas, direct color distances is definitely
not a nice way of setting the fuzz factor to use, as it is also dependant on
exactly what compile time
Quality Setting is
used.
Setting the "
-fuzz" factor
as a percentage, makes its use a lot simpler. In this case
'
100%' represents a large enough fuzz factor to cover all colors.
That is it represents the color distance from '
black' to
'
white', across the 3 dimensional diagonal of the RGB color cube.
To demonstrate lets change 95% of all the colors closest to
'white', white. This should result in only the last 5% colors
near 'black' on the image, as black is on the opposite side of
the RGB color cube.
convert colorwheel.png -fuzz 95% -fill white -opaque white opaque_w95.jpg
| |
|
  |
With a "-fuzz" factor of 100%, which equates to a RGB color cube
distance from 'black' to 'white', we can
calculate that a percentage of about 57.7% is the distance between
'black' and 'blue', and 81.6% is the
disance from 'blue' to 'red' or even
'white'.
In summery anying larger than about 25%, (just short of the RGB distance
from 'blue' to 'navy blue' represents a very
large color change.
|
To demonstrate the color distances more, lets use a progressively larger
fuzz factor percentage...
convert colorwheel.png -fuzz 10% -fill white -opaque blue opaque_b10.jpg
convert colorwheel.png -fuzz 25% -fill white -opaque blue opaque_b25.jpg
convert colorwheel.png -fuzz 57% -fill white -opaque blue opaque_b57.jpg
convert colorwheel.png -fuzz 81% -fill white -opaque blue opaque_b81.jpg
convert colorwheel.png -fuzz 95% -fill white -opaque blue opaque_b95.jpg
|
From this you can clearly see that it isn't '
black', or
'
white' that is the most distant color from '
blue',
but that it is actually '
yellow' that is most distant in RGB
color space.
Color matching is actually much more consistent if the image was stored using
some other color scheme than RGB, such as CMYK. The formula is still the same,
just using a different colorspace. CMYK colorspace is also thought to be more
consistent, human wise.
HOW TO USE CMYK with opaque tests ????
Is -fuzz match basied on -colorspace?
Using a "
-fuzz" factor
becomes more complicated when matching involves transparent and
semi-transparent colors, and recent work (for IM version 6.2.6-2) has adjusted
the comparison algorithm so that fully-transparent colors will always match
as being the same, no matter what other color components are present.
Comparing semi-transparent colors will results in the distance between the RGB
color components being divided by amount of transparency involved, as such
semi-transparent colors are thought of by IM as being closer than their
fully-opaque equivalents.
This improves comparisons between image with transparencies, and also
color reduction for images with some semi-transparency, with less
semi-transparent colors being generated in color reductions.
The "
-fuzz" operator effects
just about any operator which compares specific colors within an image. This
includes: "
-opaque",
"
-transparent",
"
-floodfill", "
-trim", "
-deconstruct", "
-layer", "
-draw 'color'", "
-draw 'matte'", and probably others.
Full Color Map Replacement
FUTURE: Replace all the colors in one color map to another.
Suggestions as to how is welcome, perhaps using the ideas presented in
Dithering with Symbols.
Recoloring Images with Gradients
While you can recolor images using the various histogram color adjustments
shown above, there is another technique for recoloring images based on color
lookups of pre-prepared color gradients.
Color Lookup Tables
A common requirement of a image processing tool is the ability to replace the
whole range of colors, from a preprepared table of colors. This allows you to
convert images of one set of colors (generally gray-scale) into completely
different set of colors, just by looking up its replacement color from a
special image known as a Color Lookup Table (or color LUT).
Of course you do need a 'Look Up Table' image from which to read the
replacement colors. For these first few examples, I choose to use a vertical
gradient of colors for the LUT so that the IM "
gradient:" generator can be used to
simplify the generation of the 'color lookup table'.
Well so much for the theory. Let try it out by recoloring a simple
gray-Scale Plasma image, replacing the
grayscale with a dark-blue to off-white gradient of colors.
convert -size 100x100 plasma:fractal -virtual-pixel edge -blur 0x5 \
-shade 140x45 -normalize \
-size 1x100 xc:black -size 9x100 gradient: \
+append gray_image.jpg
convert -size 10x100 gradient:navy-snow gradient_ice-sea.png
convert gray_image.jpg gradient_ice-sea.png -clut gray_recolored.jpg
|
The "
-clut" operator
takes two images. The first is the image to replace color values in, the
second is a gradient image that is either a single row, or a single column.
  |
The "-clut" operator was
added to IM v6.3.5-8.
|
If your IM is too old to understand the the "
-clut" operator or you want to do
something out of the ordinary, such as a 2 dimentional color lookup table,
then you can roll your own using the
General DIY
Operator, FX. For example here is a slow, but equivelent command to the
above.
convert gray_image.jpg gradient_ice-sea.png \
-fx 'v.p{0,u*v.h}' gray_recolored_fx.jpg
| |
|
The problem is that even for a simple process such as the above the "
-fx" operator is very slow, and has
to be designed specifically for either a row or column LUT. But it does work.
The LUT does not have to be very large. For example here we use a very small
LUT, with a very limited number of colors.
convert -size 1x6 gradient:navy-snow gradient_levels.png
convert gray_image.jpg gradient_levels.png -clut gray_levels.jpg
|
I enlarged the gradient image for the web page display above, otherwise it
would be too small to see properly. The LUT is in actual fact only 6 pixels in
size. However if you look at the result you will see that the Color Lookup
Operator smooths out those 6 colors into a smooth gradient.
What is happening is the IM is doing a
Interpolated Lookup of the LUT image. That is instead of just picking
the color found, it does a weighted average of all the nearby colors to better
represent the LUT. In this particular case, it used the default '
Bilinear' setting, that just links each
colored pixels together with linear line segments.
Different "
-interpolate" settings generate different levels of smoothing of
the colors when using a very small color LUT. Here for example I show a
various type of interpolated smoothing of the LUT colors.
convert gray_image.jpg gradient_levels.png \
-interpolate Integer -clut gray_levels_integer.jpg
convert gray_image.jpg gradient_levels.png \
-interpolate NearestNeighbor -clut gray_levels_nearest.jpg
convert gray_image.jpg gradient_levels.png \
-interpolate Average -clut gray_levels_average.jpg
convert gray_image.jpg gradient_levels.png \
-interpolate BiLinear -clut gray_levels_bilinear.jpg
convert gray_image.jpg gradient_levels.png \
-interpolate BiCubic -clut gray_levels_bicubic.jpg
convert gray_image.jpg gradient_levels.png \
-interpolate Spline -clut gray_levels_spline.jpg
|
Integer
|
Nearest Neighbor
|
Average
|
BiLinear
|
BiCubic
|
Spline
|
The '
Integer' and '
NearestNeighbor' settings are
special in that they do no smoothing colors at all. That is no new 'mixed
colors' will be added,
only the exact color values present will be used
used to color a grayscale image. However note how the lookup of the colors are
differ betwen the two. It is a subtile difference but important.
The '
Average' setting on the
other hand also generated bands of color but only using a mix of the colors,
resulting in one less color than the size of the color lookup table image.
This type of color 'banding' (or
Blocking
Artifacts) is actually rather common for geographic maps, and temperature
graphs, as it gives a better representation of the exact shape of the map.
The sharp boundary edges being known as iso-lines. Adding a slight one pixel
Blur to the final image can improve the look
of those edges, making it look a little smoother, without destorying the color
banding.
The '
BiLinear' setting will also
generate bandling but only in the form of sharp gradient changes, as will
'
BiCubic' to a lesser extent.
This is easilly seen in the above.
To avoid this problem you would normally use much longer LUT to produce a
larger range of intermediate colors. Ideally this should cover the full range
of possible intensity values. For ImageMagick Q16 (compiled with 16 bit
quality) that requires a LUT to have a height of 65536 pixels. However thanks
to
Pixel Interpolation, a LUT gradient
image of 500 pixels or more is usually good enough for re-coloring most images
quite well.
Note that the vertical gradient LUT used in the above examples appears
upside-down to our eyes, as the black or '
0' index is at the top
of the image. Normally we humans prefer to see gradients with the black level
at the bottom (thanks to our evolutionary past).
If you rather save the gradient image the 'right way up' you can "
-flip" the image as you reading it
in. For example lets try a more complex LUT, flipping the vertical gradient
before using it on the image.
convert -size 1x33 gradient:wheat-brown gradient:brown-lawngreen \
gradient:dodgerblue-navy -append gradient_planet.png
convert gray_image.jpg \
\( gradient_planet.png -flip \) -clut gray_planet.jpg
|
As you can see for a vertical gradient, flipping it before using makes
a lot of sense.
For more examples of generating gradients see
Gradients of Color.
Function to LUT Conversion
These pre-prepared "Lookup Table Images" (or LUTs) can also be used to greatly
increase the speed of very complex and thus slow "
-fx" operations, so instead of IM
interpreting the functional string 3 or 4 times per pixel, it can do a much
faster lookup of the replacement color.
The procedure for doing this is quite straight forward, either apply the
function to a unmodified linear gradient, or replace the '
u' in
the function with the value '
(i/w)' for a row lut image, or
'
(j/h)' for a column lut image.
For example in the advanced
'Aqua'
Effects examples, I use a complex "
-fx" function to adjust the gray-scale output of "
-shade". Also as this gray-scale
adjustment is also overlaid onto a 'DodgerBlue' shape, there is no reason why
the results of both of these operators could not be combined into a single
gradient lookup table.
That is we generate a LUT from the "
-fx" formula and the color overlay. Also for these examples
I decided to generate a single row of pixels rather than a column as I did
previously.
convert -size 1x512 gradient: -rotate 90 +matte \
-fx '3.5u^3 - 5.05u^2 + 2.05u + 0.3' \
-size 512x1 xc:DodgerBlue -compose Overlay -composite \
aqua_gradient.png
|
This can now be applied to the shaded shape much quicker than using the
"
-fx" function directly as
it only generates the smaller LUT, and not the larger image.
convert -font Candice -pointsize 72 label:A -trim +repage -negate \
\( +clone -blur 0x8 -shade 110x45 -normalize \
aqua_gradient.png -clut \) \
+matte +swap -compose CopyOpacity -composite \
aqua_font.png
|
WARNING: the above is incomplete (edges have not been darkened)
|
|
As you can see, the result is very effective, and once the "
-fx" operation used to create the LUT
is done, you can use the same gradient over and over.
Color Replacement with Transparency
The "
-clut" operator is
controled by the "
-channel" setting, and in reality it only replaces the individual
channel values within the image.
That means normally each individual channel of the source image is usedto
'lookup' the replacement value for just that channel from the color lookup
table. That includes the alpha/matte channel which is usally very
inconvenient, and difficult to apply.
Typically the "
-clut"
operator is used to either colorize a gray-scale source image, (see previous
examples), OR it is used to do a histogram adjustment of a color image using
a gray-scale CLUT (Color Lookup Table).
As of IM v6.3.7-3, if a "
-channel" setting specifies that you are wanting to replace/adjust
the alpha channel of an image (an '
A' is present), and the source
or CLUT image has no alpha/matte channel defined, then IM will assume that you
are doing gray-scale color replacement, and will act accordingally.
For example, here I generate a simple blurred triangle, whcih I can then color
using a Color Lookup Table that includes transparency.
convert -size 100x100 xc: -draw 'polygon 50,10 10,80 90,80' \
-blur 0x10 blurred_shape.jpg
convert -size 1x5 xc:none \
-draw 'fill red point 0,2' \
-draw 'fill yellow rectangle 0,3 0,4' gradient_border.png
convert blurred_shape.jpg +matte \( gradient_border.png -flip \) \
-channel RGBA -interpolate integer -clut -blur 0x.5 clut_shape.png
|
Remember the above will only work as expected if the gray-scale image has no
alpha or matte channel (using either "
-alpha off" or "
+matte"), and you specify that you want it to handle the alpha
channel (using "
-channel
RGBA").
If on the other hand the CLUT image you provide has no matte/alpha channel
defined, then IM v6.3.7-3 will assume you want to use a gray-scale CLUT image
as a histogram adjustment for the "
-channel' specified.
For example here I generated triangle from colored tile, But I want to roughly
feather its outline.
convert -size 100x100 xc:none -draw 'polygon 50,10 10,80 90,80' \
tile_disks.jpg -compose In -composite shape_triangle.gif
convert shape_triangle.gif -channel A -blur 0x10 +channel shape_blurred.png
convert -size 1x50 gradient: xc:black -append -flip \
-sigmoidal-contrast 6x0% feather_histogram.jpg
convert shape_blurred.png \( feather_histogram.jpg +matte \) \
-channel A -clut shape_feathered.png
|
The 'black' halo is caused by the "
-blur" operation making the fully-transparent areas surrounding
the triangle visible. As fulyy-transparent has an undefined color, IM defaults
to black. The CLUT image itself was designed to ensure that any pixel which
was less than 50% transparent will be turned fully-transparent, effectivally
removing the originally undefined parts of the image.
This time the CLUT image is used to do a histogram adjustment of just the
alpha channel. Note that I ensure that the CLUT image does not have a
matte/alpha channel by using a "
+matte" operator when reading it in.
For demonstration purposes I overdo the initial 'blur', then over-correct the
alpha channel adjustment. The result is a sever rounding of the points of the
triangle. You would typically use much smaller values for both the "
-blur" and the "
-sigmoidal-contrast"
alpha adjustment.
Also the above blurred-feathering method, will add undefined semi-transparent
pixels on concave internal facing corners of a mask image. This problem
however could be solved by masking the image with a thresholded mask of the
original outline to ensure no pixel that was fully-transparent in the original
image is added as a semi-transparent pixel in the final feathered result.
Fred Weinhaus, has
implemented a blurred fethering technique in his "
feather" script,
to make it easier to use.
Miscellaneous Color Operators
Sepia Tone Coloring
A special photographic recoloring technique, "
-sepia-tone" is basically
consists to converting the image into a grayscale, and coloring all the
mid-tones to a special brown color.