- Index
ImageMagick Examples Preface and Index
Solid Color Canvases
(for image manipulations)
Gradients of Colors
(canvases of smooth color changes)
Sparse Points of Color
(coloring from fixed points)
Randomized Canvases
(for randomized background images)
Tiled Canvases
(canvases using a repeating images)
Canvases are used by ImageMagick both as a starting image for drawing on,
backgrounds to overlay images with transparent areas, or even just as part of
general image processing. They can be a solid color, or a range of colors,
or even a tile of a smaller image. Here we look at some of the more common
methods of generating a canvas image.
Solid Color Canvases
Direct Generation
Generating a canvas of a specific color and size is very simple to do, and is
used all the time...
convert -size 100x100 xc:khaki canvas_khaki.gif
|
|
|
If you have already created a canvas, but need one in a different color you
can replace that color using the "-opaque" operator.
convert canvas_khaki.gif -fill tomato -opaque khaki canvas_opaque.gif
| |
|
You can even grab a single pixel from an existing image, and expand it to the
canvas size you want. We use "
-scale" for a simple and fast resizing of the single pixel.
Here we grab a rose color from the built-in "rose:" image.
convert rose: -crop 1x1+40+30 +repage -scale 100x100\! canvas_pick.gif
| |
|
Create Image of same size
One most basic techniques when using ImageMagick is to generate a canvas the
same size as some existing image. This can be done by converting that
existing image into the canvas need, but preserving the images original size.
Naturally IM provides a large number of ways to do this, usually as a side
effect of other image operations. But only one method currently stands out
from the rest and is obvious in its intent.
|
To the left is 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.
|
|
Overlay a Specific Color
The simplest way is to use "-colorize" to overlay the fill color but with a fully opaque
value. However this will preserve the original images alpha channel, unless
you remove it first, using "+matte".
convert test.png +matte -fill Sienna -colorize 100% color_colorize.gif
|
|
|
As of IM v6.4.2-1 you can also use the "+level-colors" to set all
the colors.
convert test.png -channel RGBA +level-colors Chocolate color_levelc.gif
|
|
|
As of IM v6.4.3-0 you can use the "-sparse-color" operator to
set a single point to the color wanted, using just about any method it
provides (see Sparse Points of Color below).
convert test.png -channel RGBA \
-sparse-color Voronoi '0,0 Peru' color_sparse.gif
|
|
|
A more general way people think of is to use "-draw" to reset all the colors in
the current image to the current "-fill" color.
convert test.png -fill Tan -draw 'color 0,0 reset' color_reset.gif
|
|
|
All these methods will also preserve any meta-data the image may contain (such
as comments or profiles).
Other methods are more complex as it involves using special
Alpha Composition to force various operators to
replace the image with the desired color. This technique only works with
image operators that use "
-compose", to replace the existing image, with the desired color.
If you are just wanting to grab the original images meta-data (such as its
commend an labels, but want a specific color and size of canvas image, the
"-extent" operator (See
Extent, Direct Image Size Adjustment) may be the
simplest. Color will again come from the "-background" setting.
convert test.png -background LemonChiffon \
-compose Dst -extent 100x100 color_extent.gif
|
|
|
Or you can use "-border"
(See Adding a Border), using the "-bordercolor" as the color
source.
convert test.png -bordercolor Khaki \
-compose Dst -border 0 color_border.gif
|
|
|
This last method has the added advantage of also letting you slight enlarge
the image canvas relative to the original images size.
  |
The "-border" method
of generating canvases will not work with versions of IM before version
6.1.4. Before this the background generated by the "-border" operator was not a
simple solid color, but a black canvas surrounded by the border color. Not
very useful.
|
A more flexible (but very slow) method of canvas generation was provided by
the "FX, DIY Operator" operator.
You will also need to use the "+matte" operator to turn off the input images matte channel as by
default "-fx" will not
touch the transparency channel.
convert test.png +matte -fx Gold color_fx_constant.gif
|
|
|
The "-fx" operator will even
let you do a little color mathematics. For example how about a dark gold
color...
convert test.png +matte -fx "Gold*.7" color_fx_math.gif
|
|
|
All the above methods can not only fill using a fully-opaque color, but can
also use semi-transparent colors. However it is a good idea to ensure the
image you are using has a matte channel using the "
-matte" operator before hand.
Here for example we create a canvas that a semi-transparent red. However
when overlaid on the web pages 'bluish' background we get a off purple color.
convert test.png -matte -fill '#FF000040' -draw 'color 0,0 reset' \
color_semitrans.png
|
|
|
Also for the "
-fx" operator
you will need to set "
-channel" to use all four '
RGBA' color channels.
Other Canvas Techniques
Their lots of other ways of generating canvases of very specific colors, but
they are rather obtuse. As such without some heavy commenting, it may not be
obvious which you are doing when you look at your IM script months or years
later.
I don't recommend these techniques, but are useful to know if you are using
older less flexible versions of IM.
Black Canvas
Traditionally you can create a black canvas by using "-threshold", and then turn off
the matte channel.
convert test.png -threshold 100% +matte black_threshold.png
|
|
|
Providing the "-level"
operator with same argument for both 'black' and 'white' points will have the
same effect.
convert test.png -level 100%,100% +matte black_level.png
|
|
|
The "-fx" operator
provides a more obvious way of creating a black canvas by clearing all the
pixels to zero. However you will also need to reset the matte channel to make
it fully opaque.
convert test.png -fx 0 +matte black_fx.png
|
|
|
However the "-evaluate"
version of this should be faster, particularly on larger images.
convert test.png -evaluate set 0 +matte black_evaluate.png
|
|
|
You can also mis-use the "-gamma" operator to make an image all black.
convert test.png -gamma 0 +matte black_gamma.png
|
|
|
A less obvious way is to 'posterize' the image will too few color levels,
resulting in only one color being used, black.
convert test.png -posterize 1 +matte black_posterize.png
|
|
|
You can ensure the image is fully transparent then 'extract' the
images mask, using the Alpha Operator
convert test.png -alpha transparent -alpha extract black_alpha.png
| |
|
White Canvas
The traditional way is again using "-threshold". The value however must be a negative number, just to
be sure that all colors will be mapped to white, in all versions of IM.
convert test.png -threshold -1 +matte white_threshold.png
|
|
|
Providing the "-level"
operator with same argument for both 'black' and 'white' points will have the
same effect.
convert test.png -level -1,-1 +matte white_level.png
|
|
|
You can of course set the pixel values directly using the "-fx" operator.
convert test.png -fx 1.0 +matte white_fx.png
|
|
|
However the "-evaluate"
version of this should be faster, particularly on larger images.
convert test.png -evaluate set 100% +matte white_evaluate.png
|
|
|
You can also mis-use the "-gamma" operator to make an image all white, by using a negative
argument.
convert test.png -gamma -1 +matte white_gamma.png
|
|
|
Or negate some other black canvas generation method.
convert test.png -posterize 1 +matte -negate white_posterize.png
|
|
|
You can ensure the image is fully opaque (no transparency) then
'extract' the images mask, using the Alpha Operator
convert test.png -alpha opaque -alpha extract white_alpha.png
| |
|
Transparent Canvas
Probably the most important canvas you want to generate from a existing image
is a transparent canvas.
The fastest and easiest way it to just get IM to directly clear the image to
transparency, using the "-alpha transparent" operator (added IM v6.4.3-7).
convert test.png -alpha transparent trans_alpha.png
| |
|
However as this is a very recent addition it is probably not widely available
yet.
We can make a fully-transparent 'black' canvas using the 'Clear alpha composition operator, with any
overlay image (a single pixel "null:" in this case) as it will be
ignored.
convert test.png null: -compose Clear -composite trans_compose.png
| |
|
Here we use the "-draw matte" operator to replace the matte
channel value with the tranparency of the "-fill" color setting. In this case
transparent.
convert test.png -fill none -draw 'matte 0,0 reset' color_matte.png
|
|
|
We can also do this more directly with the "-fx" operator.
convert test.png -channel A -fx 0 trans_fx.png
|
|
|
Naturally the "-evaluate" version of this should be faster, particularly on
larger images.
convert test.png -channel A -evaluate set 0 trans_evaluate.png
|
|
|
Another way to just make the image fully transparent is to use "-threshold" but again
limiting its effects to just the transparency channel.
convert test.png -channel A -threshold -1 trans_threshold.png
|
|
|
Actually in this case we are mathematically dealing with a 'matte' channel,
using threshold to set it to the maximum value, rather than zero, as we did
with the "
-fx" operator.
This is why a '
-1' was used in the above, rather than
100%'. (See
Channels and Masks
examples page.)
The original RGB colors are still present in the last set of images above.
That is the original colors of the image are still present, they have just
been made transparent.
For example, here we read in one of the above images and ask IM to turn off
the matte/alpha channel in the image so as to make the colors visible again.
convert trans_fx.png +matte trans_fx_matte.jpg
|
Note however that not all image formats, and very few image operation will
preserve the not fully-transparent RGB colors that are still present in the
image.
|
|
As mentioned before, and worth repeating, many of the above methods rely on an
image already having a matte channel. If it doesn't, add one using the
"
-matte" image operator,
or "
-alpha On", but you
may as well just use "
-alpha
Transparent" in that case. See the examples on
Controlling Image Transparency.
Miscellaneous Canvas Coloring
Other than using a specific color, only the "-gamma" operator is truly
flexible enough to generate a canvas of any primary/secondary color. You
basically use 0 to zero out a channel, and -1 to
maximize a channel values.
For example here I generate a yellow canvas...
convert test.png -gamma -1,-1,0 +matte yellow_gamma.png
|
|
|
As of IM v6.4.2 you can also use the "+level" operator to set a specific grey level for all channels.
convert test.png +level 40%,40% +matte grey_level.png
|
|
|
Gradients of Color
As you saw above you can create canvases of solid colors easy enough. But
sometimes you want something more interesting. And ImageMagick provides a
large number of special image creation operators that will let you do this.
The full list of these creation operators are listed on the
ImageMagick formats.
It is difficult however to find all the good image generators available in IM
as they are all mixed up with the specific image file formats. And then
not all the options and capabilities are detailed. I will try to rectify
that.
One of the most common image creation operators is gradient. For example...
convert -size 100x100 gradient: gradient.jpg
|
|
|
As you can see by default "
gradient:" will create an image with
white at the top, and black at the bottom, and a smooth shading of grey across
the height of the image.
But it does not have to be only a grey-scale gradient, you can also generate
a gradient of different colors by either specifying one color, or both.
convert -size 100x100 gradient:blue gradient_range1.jpg
convert -size 100x100 gradient:yellow gradient_range2.jpg
convert -size 100x100 gradient:green-yellow gradient_range3.jpg
convert -size 100x100 gradient:red-blue gradient_range4.jpg
convert -size 100x100 gradient:tomato-steelblue gradient_range5.jpg
|
Notice that when given a single color the second color will be either
'
white' or '
black', which ever produces the largest
color distance from the given color. As such '
blue' produces a
'
blue-white' gradient, while '
yellow' generated a
'
yellow-black' gradient.
  |
Gradients can not currently be specified at other angles or involving
more than two colors. However as this ability is in integral part of SVG
gradients, this situation will likely change, with a major improvement in
gradient options.
|
  |
"gradient:" currently does not make use of the "-colorspace" setting.
They are generated only in RGB space, so multi-color 'rainbow' gradients
(using HSV space) are not possible.
|
Some particularly nice gradients include...
convert -size 10x120 gradient:snow-navy gradient_ice-sea.jpg
convert -size 10x120 gradient:gold-firebrick gradient_burnished.jpg
convert -size 10x120 gradient:yellow-limegreen gradient_grassland.jpg
convert -size 10x120 gradient:khaki-tomato gradient_sunset.jpg
convert -size 10x120 gradient:darkcyan-snow gradient_snow_scape.jpg
| |
|
  |
As of IM v6.3.1 the algorithm used to generate gradients now produce a
perfect gradients, such that all the pixels of each row in an image being
assigned the same color. That is one color per row.
Before this version the "gradient:" operator worked by ignoring
the width of the image, and just assigning the next increment of color,
going row-by-row from top-left corner to the bottom-right of the image.
As a result the gradient was a predominataly vertical gradient, just as it
is now, but not a perfect one. Usually this fact was only important in
special case such as test images, and image distortion maps.
|
Radial Gradients
As of IM v6.4.4 you can also generate radial gradient images in a simular way.
convert -size 100x100 radial-gradient: rgradient.jpg
|
|
|
Note that the gradient is centered in the middle of the generated image, and
has a diameter set to fit the larger of the X or Y size of the image. So if
the size of the isn't square you will get a 'clipped' radial gradient.
convert -size 100x60 radial-gradient: rgradient_clip.jpg
|
|
|
This lets you easilly generate a square radial gradient from the center to a
corner by making one edge 1.42 (square root of 2) times larger, and crop it.
convert -size 100x142 radial-gradient: \
-gravity center -crop 100x100+0+0 rgradient_crop.jpg
|
|
|
The colors of the gradient itself follow the same conventions as the much
older linear "
gradient:" image
generator.
convert -size 100x100 radial-gradient:blue rgradient_range1.jpg
convert -size 100x100 radial-gradient:yellow rgradient_range2.jpg
convert -size 100x100 radial-gradient:green-yellow rgradient_range3.jpg
convert -size 100x100 radial-gradient:red-blue rgradient_range4.jpg
convert -size 100x100 radial-gradient:tomato-steelblue rgradient_range5.jpg
|
Gradients with Transparency
As of IM v6.2.9-8 the "gradient:" (and later
"radial-gradient:") image creation operator understands the use
of transparent and semi-transparent colors.
convert -size 100x100 gradient:none-firebrick gradient_transparent.png
| |
|
Of course as I used semi-transparent pixels in this gradient, I needed to use
the PNG image format, rather than JPEG.
One word of warning about such a gradient. It is not a pure color to
transparency, but a mix of that color with "
black". The reason
is that the color "
none" is really transparent-black. The cause
of this problem is the the non-linear nature of RGBA
Color Spaces.
For a proper pure color gradient from opaque to transparency, you can use this
method instead...
convert -size 100x100 gradient:none-black \
-fill firebrick -colorize 100% gradient_pure_trans.png
| |
|
On the other hand you can use this impurity to generate interesting shading
effects. For example by using a transparent-red color instead of
"none", with 'Navy'...
convert -size 100x100 gradient:'rgba(255,0,0,0)-Navy' \
gradient_mixed_trans.png
| |
|
You can enhance this weirdness by using "-flatten" to then change transparency to some other color,
to make tri-color gradients. Though the middle color will only be half as
intense as the transparency color used.
convert -size 100x100 gradient:'rgba(255,0,0,0)-navy' \
-background yellow -flatten gradient_tricolor.jpg
| |
|
Gradients by Histogram Adjustment
You can create a non-linear gradient by applying some form of histogram
adjustment to a linear gradient.
For example you can use a
Sigmoidal
Contrast function to create a more natural looking gradient.
convert -size 100x100 gradient: -sigmoidal-contrast 6,50% \
gradient_sigmoidal.jpg
| |
|
This type of gradient is especially good for generating
Overlapping Photos, as it removed the sharp
gradient changes at the beginning of the overlapping region.
Distorted Gradients
Rotated Gradient
While the
Sparse Color method '
Barycentric' (see below), provides a
convenient way to generate gradients at any angle, if your IM is older tha
version 6.4.3-0 then you may need to use other methods to generate a diagonal
or rotated gradient.
For example, by increasing the size of the gradient image (multiply by the
square root of 2 or 1.42), then rotate it 45 degrees, and crop the image to
its final size, you can make a diagonal gradient.
convert -size 142x142 gradient: -rotate -45 \
-gravity center -crop 100x100+0+0 +repage \
gradient_diagonal.jpg
| |
|
As of IM v6.3.5 you have a much faster and simpler way of generating a
rotated gradient by using a
SRT Distortion.
For example, here is a 100 pixel gradient rotated 60 degrees, in a 100x100
pixel image.
convert -size 100x100 gradient: -distort SRT 60 gradient_srt.jpg
| |
|
This uses the default
Virtual Pixel, Edge
setting to ensure the whole image is covered by the requested gradient. You
can also use the expert 'distort:viewport' setting, to map a gradient onto a
larger image, such as for a use in
Overlapping
Photos.
Warping Gradients
But you can use the same distortion methods to do a lot more than simple
rotations.
The gradient can also be twisted up...
convert -size 100x100 gradient: -swirl 180 gradient_swirl.jpg
| |
|
You can re-map the gradient into a trapezoidal shape.
convert -size 100x100 gradient: -rotate -90 \
-distort Perspective '0,0 40,0 99,0 59,0 0,99 -10,99 99,99 109,99' \
gradient_trapezoid.jpg
| |
|
Or wrap the gradient into a arcs and circles using the
General Distortion operator...
convert -size 100x100 gradient: -distort Arc '180 0 50 0' \
gradient_arc.jpg
| |
|
convert -size 100x100 gradient: -distort Arc '360 0 50 0' \
gradient_circle.jpg
| |
|
Though the new "
radial-gradient:"
is probably the more simpler method for generating these gradients.
Even the "
radial-gradient:" can
be warped to produce some interesting non-linear gradients. For example
arcing it using a
Wave Distortion can generate
roughly triangular shaped gradient.
convert -size 100x100 radial-gradient: \
-background black -wave -28x200 -crop 100x100+0+0 +repage \
gradient_triangle.jpg
| |
|
Gradients by Composition
You can also modify gradients by combining them using various composition
methods. For example you can use the
Add
(modulus) compose method to produce venetian blind types of gradients.
convert -size 100x100 gradient: \( +clone +clone \) \
-background gray50 -compose Add -flatten gradient_venetian.jpg
| |
|
And even do this diagonally.
convert -size 100x100 gradient: \( gradient: -rotate -90 \) \
\( -clone 0--1 -clone 0--1 \) \
-background gray50 -compose Add -flatten gradient_vent_diag.jpg
| |
|
Or by blending two plain color gradients using either
Channel Copying, or
Mathematical Blending composition methods, you can generate colorful 2
dimensional colormap gradients.
convert -size 100x100 gradient:yellow-blue \
\( gradient:black-lime -rotate -90 \) \
-compose CopyGreen -composite gradient_colormap.jpg
| |
|
Gradients in other Colorspaces
While "
gradient:" generator currently can not generate gradients
directly in some another
Color Spaces,
(only RGB gradients are created) you can transfer gradients into a different
color space to generate interesting effects. For example a linear gradient
copied into the 'Hue' of a '
HSB' image can produce a rainbow
gradient.
convert -size 30x600 xc:'#0F0' -colorspace HSB \
gradient: -compose CopyRed -composite \
-colorspace RGB -rotate 90 gradient_rainbow.jpg
|
Also see
Combining Channel Images for an
explanation, as well as an example of creating a
Color Wheel image.
Resized Gradient
One trick that was brought up on the
ImageMagick Mailing
List by Glenn Randers-Pehrson, was to create a very small image, two
pixels across, then expand that to the image size needed using "
-resize".
The "
-resize" operator
tries to smooth out enlarged images, to make them look better at the larger
scale. It is this smoothing that we use to generate a non-linear gradient.
For example here we generate the small image using a 'portable bitmap' (or
PBM format) image and feed it into IM for enlargement.
echo "P1 1 2 0 1 " | \
convert - -resize 100x100\! gradient_resize.jpg
|
|
|
  |
Some shells like 'csh' and variants, can not handle the '!'
character in the above resize geometry setting very well -- not even in
quotes. Hence the backslash '\' character may be needed.
Caution is advised.
|
The gradient produced is not linear, with a smooth start and finish to the
colors given, making those colors much more pronounced, than you would get
using a normal gradient.
A simple way to generate that initial two pixel image is actually with
gradient itself! This lets you specify the colors directly. Of course that
will limit you to a vertical gradient, unless you rotate the result as well.
convert -size 1x2 gradient:khaki-tomato \
-resize 100x100\! gradient_resize2.jpg
|
|
|
Of course you are not limited to just a single dimension, with this technique.
Here I use a four pixel 'portable greymap' (or PGM image format) to generate a
2-dimensional gradient.
echo "P2 2 2 2 2 1 1 0 " | \
convert - -resize 100x100\! gradient_resize3.jpg
|
|
|
As you can see this diagonal gradient is not very linear when compared to
the rotated diagonal gradient above.
  |
The Network Portable Bitmap
image formats, are very versatile for generating images from scripts.
They can generate bitmaps (P1), greymaps (P2), and pixmaps (P3), in both
ASCII (see above) and binary (P4,P5,P6) formats. Also the quality, or
color range used in each image is completely controllable, allowing you to
use any number range you like to specify the images (see above).
ASIDE: I was the one to make the 1995 release of NetPBM, so I have
experience using this format in script image generators I have created in
the past.
|
The "-resize" operator
smoothes the color between these pixels according to the current "-filter" setting. By adjusting that
parameter (see Resize Filter), you
can make the resize gradient more edge to edge in effect.
convert -size 1x2 gradient: \
-filter Cubic -resize 100x100\! gradient_resize4.jpg
|
|
|
Here is rough "Rainbow Gradient" created using the 'resize' technique.
convert xc:black xc:red xc:yellow xc:green1 xc:cyan xc:blue xc:black \
+append -filter Cubic -resize 600x30\! gradient_rs_rainbow.jpg
|
Interpolated Lookup Gradients
Another method of generating gradients is to use the special "
-interpolation" setting,
when using a "
-fx" operator.
This setting is used to determine the pixel color returned when the pixel
lookup is not a integer, and thus falls between two or four different pixel
values.
The default setting of '
bilinear' for example will linearly
determine the color for a lookup that falls between two pixels.
convert -size 600x30 xc: \( +size xc:gold xc:firebrick +append \) \
-fx 'v.p{i/(w-1),0}' gradient_interpolated.jpg
|
Here the lookup X position '
i/(w-1)' goes from '
0.0'
to '
1.0' over the second two pixel image. The floating point
number produces a perfect linear gradient.
Interpolated lookup gradients can also be expanded to 2 dimensions, and
generate square linear gradients, just as easily as purely one dimensions
gradients. Here are examples of the default '
bilinear' "
-interpolate" setting.
convert \( xc:red xc:blue +append \) \( xc:yellow xc:cyan +append \) \
-append -size 100x100 xc: +insert \
-fx 'v.p{i/(w-1),j/(h-1)}' gradient_bilinear.jpg
| |
|
This same result can also be achieved faster using a '
Triangle'
"
-filter" setting with
the
Resized Gradient technique above.
The '
mesh' "
-interpolate" setting however is not available as a
Resize Filters. It is a special 2 dimensional
interpolation that divides the intra-pixel area into two flat linear
triangles, hinged along the diagonal connecting the corners with the minimal
color difference.
By making the two diagonal corners the same color, you end up with two joined
diagonal gradients.
convert \( xc:red xc:gold +append \) \( xc:gold xc:green +append \) \
-append -size 100x100 xc: +insert -interpolate mesh \
-fx 'v.p{i/(w-1),j/(h-1)}' gradient_mesh.gif
| |
|
As the two diagonally opposite yellow corners are the same, a diagonal of
yellow was used to join them. With the other colors linearly mapped to those
triangles.
For more information on the "
-interpolate" setting see
Interpolation Setting.
Roll your own gradient
The
FX DIY Operator, lets you define your own
gradients or other image generation, based on the current pixel position.
As this operator requires an image to work with, you can generate your
gradients or other images to match that image. That is you don't have to know
the size of the image to generate a gradient for it!
For example you can easily generate a linear gradient, sized correctly for
the image you may be working on.
convert rose: -channel G -fx 'i/w' -separate gradient_fx_linear.gif
| |
|
  |
When generating gray-scale gradients, you can make the -fx operator 3 times
faster, simply by asking it to only generate one color channel only, such as
the 'G' or green channel in the above example. This channel
can then be Separated to form the
required gray-scale image. This can represent a very large speed boost,
especially when using a very complex "-fx" formula.
|
You can even generate some neat non-linear gradients.
convert rose: -channel G -fx '(i/w)^4' -separate gradient_fx_x4.gif
| |
|
convert rose: -channel G -fx 'cos(pi*(i/w-.5))' \
-separate gradient_fx_cos.gif
| |
|
How about a 2-dimensional circular radial gradient.
convert -size 100x100 xc: -channel G \
-fx 'rr=hypot(i/w-.5, j/h-.5); 1-rr*1.42' \
-separate gradient_fx_radial.gif
| |
|
  |
The "-fx" function
'rr=hypot(xx,yy)' was added to IM v6.3.6 to speed up the very
commonly used expression 'rr=sqrt(xx*xx+yy*yy)'. It also meant
that we no longer need to make extra assignments such as
'xx=i/w-.5' when creating a radial gradient.
|
Note how I use some assignment expressions to simplify the calculation of the
distance from center of the image, then convert it to a gradient. This
feature was added in IM v6.3.0.
The value '
1.42' (or
sqrt(2)) in the above controls
the overall size of the gradient relative to the images dimensions. In this
way the radius of the gradient is diagonal distance to the corner.
You can even remove the 'sqrt()' (built into the
'hypot()' function) from the expression to make a more
interesting spherical gradient, which can be useful for 3D Shading Effects.
convert -size 100x100 xc: -channel G \
-fx 'xx=i/w-.5; yy=j/h-.5; rr=xx*xx+yy*yy; 1-rr*4' \
-separate gradient_fx_spherical.gif
| |
|
Using a high power function, you can give photos a fade off effect around the
rectangular edges of the image. Adjust the power value '4' to
control the amount of fading.
convert -size 100x100 xc: -channel G \
-fx '(1-(2*i/w-1)^4)*(1-(2*j/h-1)^4)' \
-separate gradient_fx_quad2.gif
| |
|
Here is a angular gradient, which is interesting in itself.
convert -size 100x100 xc: -channel G \
-fx '.5 - atan2(j-h/2,w/2-i)/pi/2' \
-separate gradient_fx_angular.gif
| |
|
Note that the '
atan2(y,x)' function returns a angle in radians
from -PI to +PI (see its manpage), so its output needs to be be scaled and
translated to correctly fit a 0.0 to 1.0 color range. This is why the above
looks so much more complex than it really is.
This last example can be generated faster by
Distorting a Gradient using the
Generalized Distortion Operator. For an example see the
Color Wheel Example.
More Complex DIY Gradients
Of course an FX function can generate color gradients. For example here is a
gradient based on distance ratios, using an extremely complex FX expression.
convert -size 100x100 xc: +size xc:red xc:yellow \
-fx 'ar=hypot( i/w-.8, j/h-.3 )*4;
br=hypot( i/w-.3, j/h-.7 )*4;
u[1]*br/(ar+br) + u[2]*ar/(ar+br)' \
gradient_dist_ratio.gif
| |
|
When going from two points to three points the ratio of how much color each
'control point' provides, is a bit more complex, and uses a technique called
Inverse Distance Weighted (IDW) Interpolation. You can see more details math
for this in
Wikipedia, IDW
Here is a inverse distance example for three points.
convert -size 100x100 xc: +size xc:red xc:yellow xc:lime \
-fx 'ar=1/max(1, hypot(i-50,j-10) );
br=1/max(1, hypot(i-10,j-70) );
cr=1/max(1, hypot(i-90,j-90) );
( u[1]*ar + u[2]*br + u[3]*cr )/( ar+br+cr )' \
gradient_shepards.gif
| |
|
And here I use a inverse distance squared which is the more normal method used
for a IDW interpolation. This is also known as Shepard's Interpolation method,
and is now implements using the
Sparse Color
method '
Shepards", (see below).
convert -size 100x100 xc: +size xc:red xc:yellow xc:lime \
-fx 'ar=1/max(1, (i-50)*(i-50)+(j-10)*(j-10) );
br=1/max(1, (i-10)*(i-10)+(j-70)*(j-70) );
cr=1/max(1, (i-90)*(i-90)+(j-90)*(j-90) );
( u[1]*ar + u[2]*br + u[3]*cr )/( ar+br+cr )' \
gradient_shepards_2.gif
| |
|
Note that the '
hypot()' function was not used in the above
as there is no need to generate a square root of the distance.
The problem with Shepard's Method is that all the 'control points' has a
global effect over the whole image. As a result you get a sort of underlying
'average color' in between all the 'control points', and especially at a large
distance from all control points. This, in turn, produces 'spots' of color
rather than a smooth gradient that was wanted.
Here I tried to improve the results by generating the gradient in HSL
colorspace, but this time using blue instead of yellow.
convert -size 100x100 xc: +size xc:red xc:blue xc:lime -colorspace HSL \
-fx 'ar=1/max(1, (i-50)*(i-50)+(j-10)*(j-10) );
br=1/max(1, (i-10)*(i-10)+(j-70)*(j-70) );
cr=1/max(1, (i-90)*(i-90)+(j-90)*(j-90) );
( u[1]*ar + u[2]*br + u[3]*cr )/( ar+br+cr )' \
-colorspace RGB gradient_shepards_HSL.gif
| |
|
As you can see all the colors were nice an bright as we are only generating a
hue gradient. However it also appears very strange, which is caused by the
'cyclic' nature of the 'Hue' color channel. As a consequence the area between
the blue and the red goes the long way round though a green hue, rather than
though a purple hue, as you would expect.
This has no easy solution due to the modulus mathematics that is involved, but
if you have ideas I would welcome them.
Sparse Points of Color
The "
-sparse-color" operator was added to IM v6.4.3-0 will take an
image as set the color given at each of the given floating point
'
x,y' coordinates. That is of the form...
-sparse-color {method} 'x,y color x,y color x,y color ...'
The rest of the pixels in the image will then be mapped to try match those
points of color, according to the method chosen.
Naturally there are lots of ways to define what the intervening color should
be, and which method you choose really depends on what you are attempting to
achieve.
Note that image enlargement (resize magnify) is actually a specialized sub-set
of this, but one where you start with a fixed grid of pixels to be enlarged.
Unfortunately few of the
Resize Filter
Methods will translate well to a free form set of sparsely separated
points of color.
This is also related to "Geographical Information System" methods where
landscapes are measured using sparsely separated points of height (not always
in a strict grid), and the rest of the landscape needs to be determined from
those points.
Voronoi (nearest color)
The "
Voronoi" method, just maps each pixel to the closest
color point you have provided. This basically divides the image into a set of
polygonal 'cells' around each point. For example..
convert -size 100x100 xc: -sparse-color Voronoi \
'30,10 red 10,80 blue 70,60 lime 80,20 yellow' \
-fill white -stroke black \
-draw 'circle 30,10 30,12 circle 10,80 10,82' \
-draw 'circle 70,60 70,62 circle 80,20 80,22' \
sparse_voronoi.gif
| |
|
As you can see no attempt is made to provide anti-aliasing of the colored
'cells' around each point. The edge of each cell actually falls exactly
midway between each point's nearest neighbours.
This can be used for example to generate masks to cut up the image in various
ways. just assign one point as white and all the rest as black to extract one
single 'cell' from the image.
If you want to smooth (anti-alias) the result you can either use some form of
Super Sampling to smooth the
image. For example generate one 4 times as big, and "
-scale" it back to the desired
size.
convert -size 400x400 xc: -sparse-color Voronoi \
'120,40 red 40,320 blue 270,240 lime 320,80 yellow' \
-scale 25% -fill white -stroke black \
-draw 'circle 30,10 30,12 circle 10,80 10,82' \
-draw 'circle 70,60 70,62 circle 80,20 80,22' \
sparse_voronoi_ssampled.png
| |
|
The simpler way (though not very nice) is to just simply blur the image very
slightly...
convert -size 100x100 xc: -sparse-color Voronoi \
'30,10 red 10,80 blue 70,60 lime 80,20 yellow' \
-blur 0x1 -fill white -stroke black \
-draw 'circle 30,10 30,12 circle 10,80 10,82' \
-draw 'circle 70,60 70,62 circle 80,20 80,22' \
sparse_voronoi_smoothed.png
| |
|
By blurring generated image by a large amount you can set up some non-linear
gradients between the 'cells' that was generated.
convert -size 100x100 xc: -sparse-color Voronoi \
'30,10 red 10,80 blue 70,60 lime 80,20 yellow' \
-blur 0x15 -fill white -stroke black \
-draw 'circle 30,10 30,12 circle 10,80 10,82' \
-draw 'circle 70,60 70,62 circle 80,20 80,22' \
sparse_voronoi_blur.png
| |
|
The larger the "
-blur" the
larger the gradient between the various 'cells'. However be warned that this
may not preserve small colored cells, or ensure the original point remains the
color that was given, if it is close to the edge (and another point) of a
different color.
By using a special 'linear blur' technique developed br Fred Weinhaus, you can
produce a fixed width linear gradient between the cells.
convert -size 100x100 xc: -sparse-color Voronoi \
'30,10 red 10,80 blue 70,60 lime 80,20 yellow' \
-blur 10x65535 -fill white -stroke black \
-draw 'circle 30,10 30,12 circle 10,80 10,82' \
-draw 'circle 70,60 70,62 circle 80,20 80,22' \
sparse_voronoi_gradient.png
| |
|
The unblurred output could also passed to various
Edge Detection techniques to generate various bounded edges.
You can remap the image via a
Raster to
Vector Convertor to generate vector lines. However I found the default
'
autotrace' settings may need to be adjusted with
"
-corner-threshold 120" so it will detect the corners better.
Shepards (spots of color)
The "
Shepards" method uses a ratio of the inverse squares of the
distances to each of the given points to determine the color of the canvas at
each point. See
More Complex DIY Gradients
above for examples of how the the mathematics is performed.
It is a bit like having spot lights of color at each point which interacts
with each other, as the light spreads out to a uniform average of all the
given colors at infinity.
convert -size 100x100 xc: -sparse-color Shepards \
'30,10 red 10,80 blue 70,60 lime 80,20 yellow' \
-fill white -stroke black \
-draw 'circle 30,10 30,12 circle 10,80 10,82' \
-draw 'circle 70,60 70,62 circle 80,20 80,22' \
sparse_shepards.png
| |
|
By surrounding a specific area with a similar color you can generate a plateau
of that specific color, though the boundaries between the edging points may
'leak'.
This method is also used to generate a displacement field used in
Shepards Image Distortions. In that case X
and Y vectors are mapped rather than color values.
Channel and Sparse Color
The "
-sparse-color"
operator is effected by the "
-channel" setting which means you can use that setting to limit its
effects to just a single channel, or expand it to the transparency channel.
You can also use the "
-channel" setting to speed up processing of gray-scale images by
only operating on one channel, then "
-separate" that channel (see
Channel Handling for more detail). For
example..
convert -size 100x100 xc: -channel G -sparse-color Shepards \
'30,10 gray70 10,80 black 70,60 white 80,20 gray(33.3333%)' \
-fill white -stroke black \
-draw 'circle 30,10 30,12 circle 10,80 10,82' \
-draw 'circle 70,60 70,62 circle 80,20 80,22' \
-separate +channel sparse_shepards_gray.gif
| |
|
Barycentric (triangle gradient)
The "
Barycentric" method, will map three points into a
linear triangle of color. The colors outside this triangle continue as before.
I have again marked the points to make this continuation clear.
convert -size 100x100 xc: -sparse-color Barycentric \
'30,10 red 10,80 blue 70,60 lime' \
-fill white -stroke black \
-draw 'circle 30,10 30,12 circle 10,80 10,82 circle 70,60 70,62' \
sparse_barycentric.png
| |
|
If more than four points are given a 'best fit' will be performed, over all
the points given, and as such you may not get the exact color specified at the
points you give.
The '
barycentric' method is in reality a mapping of a linear
affine equation to each of the three color channels separately.
As such if I separate each of the color channels of the above three point
example, you get three simple linear gradients in each color channel.
convert sparse_barycentric.png -separate sparse_bary_%d.gif
|
It is only because of the use of primary colors that the above gradients all
were mapped parallel to one of the edges of the triangle. That is not
typically the case.
It does however demonstrate how you can use one point that is the same color
as another point to define the 'angle' of the gradient between the two
original points. For example by making two of the points '
red'
the gradient will be made parallel to the two '
red' points...
convert -size 100x100 xc: -sparse-color Barycentric \
'30,10 red 10,80 red 70,60 lime' \
-fill white -stroke black \
-draw 'circle 30,10 30,12 circle 10,80 10,82 circle 70,60 70,62' \
sparse_bary_gradient.png
| |
|
If only two color points are given, IM will generate the third point
perpendicular to one of the given points so as to generate a simple linear
gradient between the two original points.
convert -size 100x100 xc: -sparse-color Barycentric \
'30,10 red 70,60 lime' \
-fill white -stroke black \
-draw 'circle 30,10 30,12 circle 70,60 70,62' \
sparse_bary_two_point.png
| |
|
This provides a simple way of generating a diagonal gradient.
However be warned that the gradient does not just 'stop' but continues to
change beyond those points. Traditionally a barycentric gradient will be
limited to within the enveloping triangle of points used to generate it.
For example..
convert -size 100x100 xc: \
-sparse-color Barycentric '30,0 red 0,80 blue 99,99 lime' \
\( -size 100x100 xc:black -fill white \
-draw 'polygon 30,5 5,80 95,95' \) \
+matte -compose CopyOpacity -composite \
-fill white -stroke black \
-draw 'circle 30,5 30,7 circle 5,80 5,82 circle 95,95 95,97' \
sparse_bary_triangle.png
| |
|
FUTURE: when a "Triangular Mesh" method is added in the future then you
will get this type of result for the 'mesh' of points given.
Bilinear (4 point gradient)
Like the previous 3 point method, the "
Bilinear" fits an equation
to 4 points, over each color channel to produce a uniform color gradient
between the points, and beyond.
convert -size 100x100 xc: -sparse-color Bilinear \
'30,10 red 10,80 blue 70,60 lime 80,20 yellow' \
-fill white -stroke black \
-draw 'circle 30,10 30,12 circle 10,80 10,82' \
-draw 'circle 70,60 70,62 circle 80,20 80,22' \
sparse_bilinear.png
| |
|
If less than 4 points are given it falls back to a '
Barycentric' method, so this can be used as a
short hand for that method. If more than four points are given it will do a
best fit of all the points.
This method is not a good method, unless the points given for a orthogonally
aligned rectangle (grid) in which case it is equivalent to the default
Bilinear Interpolation method (see
Interpolated Lookup Gradients below).
Here is a repeat of the various, 4 point "
-sparse-color" images, for
comparison.
Voronoi
|
Voronoi (blur)
|
Shepards
|
Bilinear
|
More "-sparse-color" methods are planned. If you have any ideas
mail them to me.
Randomized Canvases
Plasma Gradients
While gradients provide a smooth range of colors, another image creation
operator "
plasma:" provides a different sort of gradient. One
that is ideally suited to generating a random backdrop of color for your
images.
First of all I should point out that "
plasma:" is a randomized
image. As such it can and will produce a different image every time it is run.
For example here we generate three separate 'standard' plasma images, and each
image is different from each other, even though the same command was used to
generate them.
convert -size 100x100 plasma: plasma1.jpg
convert -size 100x100 plasma: plasma2.jpg
convert -size 100x100 plasma: plasma3.jpg
|
You can also see that plasma images are also a type of randomized gradient
of colors, and like "
gradient:" started with white at the top and
black at the bottom.
What isn't well document is that you can specify color for the plasma gradient
in the exact same way as you can for linear gradients above.
convert -size 100x100 plasma:blue plasma_range1.jpg
convert -size 100x100 plasma:yellow plasma_range2.jpg
convert -size 100x100 plasma:green-yellow plasma_range3.jpg
convert -size 100x100 plasma:red-blue plasma_range4.jpg
convert -size 100x100 plasma:tomato-steelblue plasma_range5.jpg
|
You can also see that mid-tone colors like '
tomato' and
'
steelblue' tend to work better than pure colors like
'
red' and '
blue'. That is because it contains at
least some colors from all three color channels, allowing the plasma image
operator more scope in the colors generated.
By using the same color twice with plasma you can produce a background that is
predominantly that color, but with random splotches of colors close to those
of the original colors.
convert -size 100x100 plasma:black-black plasma_black.jpg
convert -size 100x100 plasma:grey-grey plasma_grey.jpg
convert -size 100x100 plasma:white-white plasma_white.jpg
convert -size 100x100 plasma:yellow-yellow plasma_yellow.jpg
convert -size 100x100 plasma:tomato-tomato plasma_tomato.jpg
convert -size 100x100 plasma:steelblue-steelblue plasma_steelblue.jpg
|
Again as you can see, mid-tone colors will generate more varieties of color in
the resulting image, than a extreme color, like black, white, or yellow.
The '
grey' plasma in the above is particularly nice giving a
iridescent 'mother-of-pearl' like effect, basically as grey has total freedom
in the colors that the "
plasma:" will generate.
Normalizing a prefect 50% grey plasma will produce a particularly uniform
multi-color plasma image, over the full range of colors, including white and
black.
convert -size 100x100 plasma:grey50-grey50 -normalize plasma_grey_norm.jpg
| |
|
Alternatively you can just spread the contrast of the colors to just make
them bolder, but without going to extremes.
convert -size 100x100 plasma:grey50-grey50 \
-sigmoidal-contrast 8x50% plasma_grey_contrast.jpg
| |
|
Compare this image with the 'fractal plasma' images below.
Fractal Plasma
The plasma generator also has a special fractal mode, producing highly
colorful effects. The color generated are enhanced to produce more
exaggerated color changes.
convert -size 100x100 plasma:fractal plasma_fractal1.jpg
convert -size 100x100 plasma:fractal plasma_fractal2.jpg
convert -size 100x100 plasma:fractal plasma_fractal3.jpg
|
In fact this is very similar to the constant color plasma images we have
already seen, and in fact these are generated in the same way but with more
pronounced color changes.
I often find that plasma images are a little 'noisy'. As such they usually
will benefit from a little smoothing using "
-blur".
Here I have have smoothed out the noise from the middle plasma image above.
convert plasma_fractal2.jpg -blur 0x2 plasma_smooth.jpg
| |
|
You can use "-paint" to
create random blotches of color.
convert plasma_fractal2.jpg -blur 0x1 -paint 8 plasma_paint.jpg
| |
|
Or make the colors more pronounced and circular using the "-emboss" image operator, after
using "-blur" to remove
the low level noise.
convert plasma_fractal2.jpg -blur 0x5 -emboss 2 plasma_emboss.jpg
| |
|
By using a "-blur"
followed by a "-sharpen" you can produce a more pastel color pattern than we
produced with "-emboss".
convert plasma_fractal2.jpg -blur 0x5 -sharpen 0x15 plasma_sharp.jpg
| |
|
I actually find generating a swirled plasma gradient to be particularly nice,
as a background pattern.
convert -size 160x140 plasma:fractal \
-blur 0x2 -swirl 180 -shave 20x20 plasma_swirl.jpg
| |
|
Greyscale Plasma
Now the plasma generator will always generate color, even on a pure black
solid color. However it is often useful to generate a pure grey-scale plasma.
Well there are two simple ways of doing this.
The simplest way is to take the plasma image and converted it to grey scale.
convert -size 100x100 plasma:fractal -blur 0x2 \
-colorspace Gray plasma_greyscale.jpg
| |
|
Another way is to copy one of the color channel over the other two, for a
stronger, single layer, effect.
convert -size 100x100 plasma:fractal -blur 0x2 \
-channel G -separate plasma_grey_copy.jpg
| |
|
A final technique is to use "-shade" on the plasma.
convert -size 100x100 plasma:fractal -blur 0x5 \
-shade 120x45 -normalize plasma_grey_shade.jpg
| |
|
You'd probably think you would get a lot of light and shadow effects, but the
raw plasma is so random, that "
-shade" only seems to produce a more 'mottled plasma' effect.
Instead of using a fractal plasma, with its highly exaggerated color changes,
you can create a grey-scale plasma using the constant color plasma method. As
a side effect, this method also allows you to control the overall brightness
of the grey-scale plasma image generated.
convert -size 100x100 plasma:black-black \
-blur 0x2 -colorspace Gray plasma_grey0.jpg
convert -size 100x100 plasma:grey25-grey25 \
-blur 0x2 -colorspace Gray plasma_grey1.jpg
convert -size 100x100 plasma:grey50-grey50 \
-blur 0x2 -colorspace Gray plasma_grey2.jpg
convert -size 100x100 plasma:grey75-grey75 \
-blur 0x2 -colorspace Gray plasma_grey3.jpg
convert -size 100x100 plasma:white-white \
-blur 0x2 -colorspace Gray plasma_grey4.jpg
|
If this is not quite bold enough, use the channel copy method of grey-scaling
the plasma image.
convert -size 100x100 plasma:black-black \
-blur 0x2 -channel G -separate plasma_grey5.jpg
convert -size 100x100 plasma:grey25-grey25 \
-blur 0x2 -channel G -separate plasma_grey6.jpg
convert -size 100x100 plasma:grey50-grey50 \
-blur 0x2 -channel G -separate plasma_grey7.jpg
convert -size 100x100 plasma:grey75-grey75 \
-blur 0x2 -channel G -separate plasma_grey8.jpg
convert -size 100x100 plasma:white-white \
-blur 0x2 -channel G -separate plasma_grey9.jpg
|
These grey-scale plasma images are very useful for further processing,
allowing you to generate other image effects.
For example, look at the page on
Background
Images for a huge number of examples where the plasma fractal was used
to produce lots of interesting effects.
Seeding or Repeating a Plasma Image
Remember "
plasma:" can produce areas of near pure black or pure
white, or any other color (though it isn't likely to be pure). And while it
is unlikely you will get a image that is all in one color, it is also a
possible outcome. So when you get a good result you may like to save it, for
later re-use.
Because of this, scripts using plasma images, may like to include options to
generate and re-use such randomized images. That is you may like to separate
the plasma image generation from other parts that use that image, to allow
re-use.
A simpler technique however is to 'seed' or initialize the IM random number
generator so that 'plasma:' will generate the same 'randomized'
image. That way you can tune a script or program to produce a good or
interesting coloration or effect, over and over.
convert -size 100x100 -seed 4321 plasma: plasma_seeded.jpg
| |
|
The above image will never change, so unless I change the "
-seed" number I will always have a
'red' area in the bottom-right corner.
Interestingly using the same seed with different initializing color gradients
can produce a set of images which while random, are similar in their internal
pattern.
convert -size 100x100 -seed 4321 plasma:grey-grey plasma_rnd1.jpg
convert -size 100x100 -seed 4321 plasma:white-blue plasma_rnd2.jpg
convert -size 100x100 -seed 4321 plasma:green-yellow plasma_rnd3.jpg
convert -size 100x100 -seed 4321 plasma:red-blue plasma_rnd4.jpg
convert -size 100x100 -seed 4321 plasma:tomato-steelblue plasma_rnd5.jpg
|
As you can see the same pattern of colors is present in all the above images,
though the underlying color base can highlight or obscure parts of the
shared pattern.
Just one final word of warning. Other IM operators can also use the random
number generator, such as the "
-fx" '
rand()' function, the "
-virtual-pixel"
'
random' setting the "
-random-threshold"
dither operator, and the "
-noise" operator. As such is a good idea to seed the generator
immediately before your specific use of the random number generator.
As of IM v6.3.4-3, you can also re-randomize the generator using "
+seed". So placing this setting
after your 'seeded plasma' will ensure that any later operators
correctly generate a randomized result is desired.
By default the seed is randomized when IM starts, so you normally do not need
to randomize it yourself using "
+seed" to get a random result.
Problems using Plasma
One problem you should avoid with "
plasma:" images, is generating
them with a high aspect ratio. It tends to distort the normal plasma color
effects, pulling the colors out into needle-like streaks.
convert -size 200x50 plasma: plasma_high_aspect.jpg
|
There is no simple solution to this, so unless this is what you are wanting,
caution is advised.
There is also a definite top-left to bottom-right diagonal warp in the plasma
image that should not exist. That is there is some sort of 'spatial bias'
flaw in the algorithm.
For example as Thomas Maus <thomas.maus_AT_alumni.uni-karlsruhe.de>
pointed out if you mirror and append the same plasma image, you will always
see a distinct 'V' in the resulting image...
convert -size 60x60 plasma: \( +clone -flop \) +append plasma_flaw.jpg
|
This should not happen. But the problem seems to be too deep to be able to fix
without basically completely re-writing the whole plasma generator function.
Random Noise Images
As of IM v6.3.5 you can generate a purely random image from an existing image
using Noise Generator, "+noise" method 'Random'.
convert -size 100x100 xc: +noise Random random.png
| |
|
If your IM is older than this you can still generate a pure random noise image
using the slower DIY FX Operator, "-fx".
convert -size 100x100 xc: -fx 'rand()' random_fx.png
| |
|
Now these purely random images are themselves not very useful. But as a source
image for various image transformations, they will allow you to generate
a wide variety of different images.
For example by
Blurring the image
and
Color Adjusting the result, you can create
a mottled pattern of random color.
convert random.png -virtual-pixel tile -blur 0x1 -normalize random_1.png
convert random.png -virtual-pixel tile -blur 0x3 -normalize random_3.png
convert random.png -virtual-pixel tile -blur 0x5 -normalize random_5.png
convert random.png -virtual-pixel tile -blur 0x10 -normalize random_10.png
|