ImageMagick v6 Examples --
Convolve Images

Index
ImageMagick Examples Preface and Index
'Neighbourhood' of Convolution Operators (Under Construction)
Sharpening Images (Under Construction)
Blurring Images
Generating Shadows
Specialised Blurs
Feathering Shapes (under construction)
Convolution Kernels (under construction)

These operators make changes to images one pixel at a time until all the pixels in the image has been operated on, and copied to the new replacement image Also each pixel is usually only modified slightly and only in response to other nearby pixels in the local neighbourhood.

In other words the color of a specific pixel in an image is only modified based on the colors and transparency of the other nearby pixels. As such big block of color in one part of the image will have little if any effect on another distant area of the image.

These special image operations, known as 'convolutions', are typically used to blur, sharpen, clean up, or even make an image look dirty. They are also some of the most important image operators and are used to generate a huge range of effects.


'Neighbourhood' of Convolution Operators

As each pixel is modified depending on the values of the pixels around it, each pixel depends on a 'neighbourhood' surrounding it. The larger the neighbourhood, the more pixels that are involved in calculating the final result.

Under Construction

FUTURE:
MOVE  Discussion of  radius and sigma values from blur below to
here, as part of the general overall discussion of convolution operators.

Demonstration with circles and bell curve graphs.

Sigma is a density function in Statistics, as represents a distance for
with in which 90% of the effect (whatever that is) applies.

The sigma value determines the 'neighbourhood'.

The radius just limits the overall distance from the pixel and is more a
'memory' and processing speed factor. (graph example)

If you must set its value set it to at least 2 times that of the sigma.
Otherwise set it to zero and let IM decide on a good value to use (which
internally can be very large).

In other words 0x5  will set the value of the current pixel, based on all the
pixels surrounding with 90% of the effect from the pixels within 5 pixels
radius.

The Game of Life
   A mathematical 'game' of Cellular Automation, a good introduction of
   convolution.

Basic image modifications
  -despeckle -enhance
  -sharpen  -unsharp
  -noise  -spread -displace

  -median
    Set pixel to the median of all pixels within a given radius (median =
    half pixels on one side, half on the other).  A way of "de-speckling" an
    image  (such a dust in a scan).  It could distort edges and remove thin
    lines.

    This filter is the best technique to use for removing Salt & Pepper
    noise.

    It is suggested that a trim for an original image, should use the
    diagnostic output from the median operation to find the bounding box.

  -adaptive-sharpen  radius x sigma
    Adjust sharpening so that it is restricted to close to image edges
    as defined by edge detection.

  -adaptive-blur   radius x sigma
    Blur images, except close to the edges as defined by an edge detection
    on the image.  Eg make the colors smoother, but don't destroy any
    sharp edges the image may have.

  -adaptive-resize
    Resize but attempt not to blur across sharp color changes

Sharpening Images

Sharpening is a the computer graphics algorithm that is most often see on TV shows and movies. Picture the police force 'cleaning up' a 'zoomed in' photo of a licence plate of a bank robbers car, or the face of a man on a fuzzy shop camera video, and you see what I mean.

Basically what they are doing is attempting to recover the fine detail of an image which was lost due to an image natural blurring from camera lens or low scale resolution images.

Sharpen Arguments? (expand)

The most important factor is the sigma. As it is the real control of the
sharpening operation.  It is only due to historical accident it is the second
term in the above.
It can be any floating point value from  .1  for practically no sharpening to
3 or more for sever sharpening.   0.5 to 1.0 is rather good. 

Radius is just a limit of the effect as is the threshold.

Radius is only in integer units as that is the way the algorithm works, the
larger it is the slower it is.  But it should be at a minimum 1 or better
still 2 times the sigma.
First forget the first number, just use 0 which will then use the best number for the 'sigma' factor you give. The larger the sigma the more it sharpens.

-sharpen 0x.4 very small
-sharpen 0x1.0 about one pixel size sharpen
-sharpen 0x3.0 probably getting too large

The "-sharpen" operator is sort of an inverted blur. In fact it works in just about the same way. For examples which show how this is related to blur see, Image Processing By Interpolation and Extrapolation.

For example lets blur a simple image then attempt to sharpen it again to remove the blur.


  convert  -font Gecko -pointsize 72 label:A  A_original.jpg
  convert  A_original.jpg     -blur    0x3    A_blur.jpg
  convert  A_blur.jpg         -sharpen 0x3    A_blur_sharp.jpg
  convert  A_blur_sharp.jpg   -sharpen 0x3    A_blur_sharp_x2.jpg
[IM Output] ==> [IM Output] ==> [IM Output] ==> [IM Output]

As you can see the result is not perfect, as spreading the pixels out will make the sharp corners of the image less distinct. Particularly notice the extra thickening that resulted at the corner of the two lines at the very top of the image, as well and the near disappearance of the thin lines.

Even repeating the operation or increasing the size of the area of the sharpen will not help return the image back to the exact original as you have basically lost the finer detail from the image blurring. However the macro detail can be recovered quite well.

It is sharpening algorithms which can recover of finer detail in a blurred, or heavily zoomed image, that makes big money in software packages used by police forces, astronomers, and government spy agencies.

Under Construction

Unsharp? How does this differ to sharpen?

  convert  A_blur.jpg       -unsharp 0x5        A_blur_unsharp.jpg
[IM Output] ==> [IM Output]


Blurring Images

Blurring images so they become fuzzy may not seem like a useful operation, but actually is very useful for generating background effects and shadows. It is also very useful for smoothing the effects of the 'jaggies' to anti-alias the edges of images, and to round out features to produce highlighting effects.

Blurring is so important it is an integral part of image resizing, though a different method of blurring, which is restricted to within the boundaries of a single pixel of the original image.

Their are two general image blurring operators in ImageMagick. The "-gaussian" spread and "-blur". The results of the two as very close, but as "-blur" is a faster algorithm, it is generally preferred to the former even though the former is more mathematically correct. (See Blur vs the Gaussian operator.)

Blur/Gaussian Arguments

The arguments for "-blur" and "-gaussian" are the same, but to someone new to image processing, the argument values can be confusing.

     -blur  {radius}x{sigma} 
The important setting in the above is the second sigma value. It can be thought of as an approximation of just how much your want the image to 'spread' or blur, in pixels. Think of it as the size of the brush used to blur the image. The numbers are floating point values, so you can use a very small value like '0.5'.

The first value radius, is also important as it controls how big an area the operator should look at when spreading pixels. This value should typically be either '0' or at a minimum double that of the sigma.

To show you the effects of the options lets take this simple image, with a lot of surrounding space (blur operators need lots of room to work), and create a table of the results for various operator settings. I also purposely used a font that contains both thick and thin lines see the fuzzing of small line details and large areas of color.


  convert -font Gecko -pointsize 48  label:A \
          -bordercolor white -border 20x10  blur_source.png
[IM Output]

[IM Output]

A small radius limits any effect of the blur to a circle of that size. As such using a very small radius such as '1' effectively turns off blurring.

Also notice that for a smallish radius but a large sigma you see a slight squaring of the result. Especially for the output of "-blur 5x8". This is caused by the small radius 'cutting off' the area blurred in a detrimental way. As such...
Never use a radius smaller than the sigma for blurs

The exception to this and the ideal solution is to use a radius of zero (See the last line of the above table). In that case the operator will try to automatically determine the best radius for the sigma given. The only time I would use a radius was when the IM starts reporting that it has become too large for the image involved. So..

When possible use a radius of zero for blurring operations

Small values for the sigma are typically only used to fuzz lines and smooth edges on images for which no anti-aliasing was used (see Anti-Aliasing for more info). In that situation I find a blur of '1x0.3' a useful value to remove most of the 'jaggies' from images. Did I mention all values are floating point numbers?

Large values however are useful for producing fuzzy images, for backgrounds or shadow effects (see Compound Fonts), or even image highlighting effects (as shown thought the Advanced Examples page).

Due to the way IM handles 'x' style of arguments, the sigma in the above is optional. However it is the more important value, so it should be radius that is optional, as radius can be automatically determined and has little effect on the result. As such the a single value argument to these type of convolution operators is useless. This is unlikely to change as it has been this way for a very long time, and would break too many things.

Blur uses the Channel Setting

To demonstrate blur, lets start simply by generating a fuzzy black circle on a light blue background...

  convert -size 70x70 xc:lightblue \
          -fill black -draw 'circle 35,35 20,25'  circle_on_blue.png
  convert circle_on_blue.png    -blur 0x8         circle_on_blue_blur.png
[IM Output] [IM Output]

As you can see a blurring a plain image like this has no problems. It just works, as you would expect.

But if we try this again with an image containing a transparent background...

  convert -size 70x70 xc:none \
          -fill black -draw 'circle 35,35 20,25'  black_circle.png
  convert black_circle.png       -blur 0x8        black_blurred.png
[IM Output] [IM Output]

Hang on, what happened! The image didn't change!

Well in actual fact the operator did work. But "-blur" as a grey-scale channel operator, is limited by the "-channel" setting, to just the three colour channels.

That means only the three color channels of the image were blurred, leaving the transparency or alpha channel of the image as is. In the above however, the image is a fully opaque circle on a background canvas of the color 'none', which IM defines as fully-transparent black! That which means we have a black circle, on a transparent black background. In other words a image in which all the colors are black, with some parts opaque, and other parts transparent.

Consequently when we blurred the image we only blurred black with black, which as you can probably guess, produced, black! Thus the result had no change in color.

Also we never touched the alpha or transparency channel of the image, so we just ended up with the transparency of the image being unchanged. That is a black circle!

What we really wanted to do, is blur all four image channels, particularly the alpha channel. To do this we set the "-channel" setting to all four channels of the image (EG: using a value of 'RGBA').

  convert black_circle.png  -channel RGBA  -blur 0x8  black_blurred_RGBA.png
[IM Output]

Just to summarize...
Always use a "-channel RGBA" setting when blurring images with transparency.

IM version 5.5.7 would have blurred all four color channels automatically but the operator has other, buggy effects for images with transparency. See Blur with Transparency Bug for more details.

Some image formats such as GIF and JPEG do not handle semi-transparent pixels. As such I suggest you use PNG format for any images with some form of semi-transparent colors, if possible.

As you can see from the above, the "-channel" setting is very important for a grey-scale operator such as "-blur". But is not the only thing that can be important when using such an operator.

For example lets try that last 'forgot the "-channel" setting' example again, but this time with a yellow circle.


  convert -size 70x70 xc:none \
          -fill yellow   -draw 'circle 35,35 20,25'   yellow_circle.png
  convert yellow_circle.png       -blur 0x8           yellow_blurred.png
[IM Output] [IM Output]

Notice that instead of getting unchanged image as we did with a black circle, we instead produces a horrible looking yellow circle with black creeping in around the edges. Yuck!

This problem is caused by a fact that few new IM users realise.
Transparent pixels has Color, even if you can't see it.

In the above case that transparent color was black, which leaked into the yellow circle.

Of course we can fix this by setting the "-channel" setting correctly for a transparent image, things do work as expected.

  convert yellow_circle.png  -channel RGBA  -blur 0x8  yellow_blurred_RGBA.png
[IM Output]

Blur Internals

Lets take this step further with a more complicated example, which will let use explore exactly what "-blur" is doing internally.

Here we create a very special image of a yellow circle, which has been drawn on a fully-transparent red background. This will let us see the effect of a transparent color has when blurring images.

  convert -size 70x70 xc:'#F000' \
          -fill yellow   -draw 'circle 35,35 20,25'   yellow_on_red.png
[IM Output]

We can see the color of the transparent parts of the image by effectively deleting the alpha or matte channel of the image using the "+matte" operator.

  convert yellow_on_red.png   +matte  yellow_on_red_matte.png
[IM Output]

Now lets try blurring just the colors of the image again, using the default 'RGB', "-channel" setting.

  convert yellow_on_red.png   -blur 0x8   yellow_on_red_RGB.png
[IM Output]

As you can see the fully-transparent red background of the image has now crept into the visible yellow circle, giving it an interesting orange edge, as as it did previously. You may like this effect, but their are better ways of generating it, than to rely on invisible fully-transparent colors.

Just prove you can blur this image correctly, lets do it properly...

  convert yellow_on_red.png  -channel RGBA  -blur 0x8  yellow_on_red_RGBA.png
[IM Output]

The reason that blurring with the alpha channel produces no orange colors as it did previously, is that when the "-blur" operator sees that the alpha channel is involved (according to the current "-channel" setting), it will only blur using the pixels which are visible according to that alpha channel. If the alpha channel is not involved, it will completely ignore it, and the fully-transparent red will blur with the yellow to produce various shades of orange.

Basically the blur algorithm has been modified to ignore all the fully-transparent pixels in the image, no matter what color they may have. Any semi-transparent pixels are still involved, but their effect on the result is also moderated by just how visible they are. The result is that the circle has become a fuzzy semi-transparent yellow spot. Just what the user probably was trying to achieve.

If you really like you can blur both the colors and the alpha channel separately, thus effectually disconnecting the algorithms 'visibility adjustment' on the color channels. The result is more like a sun shining through a dirty brown haze.

  convert yellow_on_red.png  -channel  A  -blur 0x8 \
                             -channel RGB -blur 0x8  yellow_on_red_GS.png
[IM Output]

This last example produced what a pure grey-scale operator would have produced if there was absolutely no interaction between the alpha channel and the colors within the image (transparent or otherwise). That is each of the red, green, blue, and alpha channels are blurred completely separately to each other as if they were each a separate grey-scale image.

Just remember, as the default "-channel" setting is 'RGB', the default action is not to blur the alpha channel, and to blur invisible colors with the visible color within the image.

Aren't you glad that "-blur" is no longer always a pure grey-scale operator. Though you can use it in that way if you really want. You didn't always have this choice however...

Before IM version 6.2.4-4, the "-blur", and "-gaussian" operators were applied as pure grey-scale operation, and as such did not adjust colors according to their alpha channel 'visibility'. The result was that any form of blurring with transparency, almost always produced horrible 'black halo' effects, such as purposefully generated in the previous example.

This was classed as a major long term bug within the IM distribution, and one that was very hard to workaround. For more details of this problem, see the Blur with Transparency Bug page.

FUTURE: Blur and Trimming Images. 

Blur vs Gaussian

There has been some confusion as to which operator, "-blur" or the "-gaussian" is better for blurring images. First of all "-blur" is faster, but it does this using two stage technique. First in one axis, then in the other. The "-gaussian" operator on the other hand is more mathematically correct as it blurs in all directions simultaneously, using a proper 'convolve' operation, but at a large speed cost.

In a more technical context, "-blur" is a 2 pass, 1 dimensional orthogonal convolution filter, while "-gaussian" is a 2 dimensional cylindrical convolution filter. For a blurring function, the results should be the same, unlike the use of other 'filtered' convolution operations. However the two pass system means that there is an intermediate stage in which rounding, or quantum effects, can occur.

Cristy also bears this out when he reported... You should always use "-blur" instead of "-gaussian" because its faster. Some pixels will be different on the interior due to rounding, and the edge pixels may be different because 'BlurImage()' uses a different edge algorithm to the 'GaussianBlur()' API.

In summary, the two operators are slightly different, but only minimally. As "-blur" is much faster, use it. I do.


Generating Shadows

The "-shadow" operator is a advanced operator that was developed with the IM example pages. Basically it represents a very complex blur and re-coloring of transparency shape of the given image. This is an operation that IM users performed all the time, but required a good deal of knowledge to figure how to achieve correctly.

The operator will take an image (usually a clone, and may already have some transparency) and convert it into a shadow image that can then be positioned under the original image at given offset, (generally by using the special Layer Merge operator.

Here for example is a standard method of shadowing an existing image, using a navy shadow color to match this web page.

  convert rose: \( +clone  -background navy  -shadow 80x3+5+5 \) +swap \
          -background none   -layers merge  +repage   shadow.png
[IM Output]

Note how the shadow image is correctly offset from the image.

You can even zero the blur 'sigma' value and create a hard shadow, but semi-transparent shadow.

  convert rose: \( +clone  -background navy  -shadow 60x0+4+4 \) +swap \
          -background none   -layers merge +repage  shadow_hard.png
[IM Output]

The use of "-layers merge" to layer shadow images with the original image makes it easy to generate shadows from a light source from any direction, not just the upper left side.

  convert rose: \( +clone -background navy -shadow 80x3-5+5 \) +swap \
          -background none  -layers merge +repage  shadow_other.png
[IM Output]

Shaped Shadows

Now "-shadow" was designed with shaped images in mind, (and this is the reason for its complexity). For example here is a typical shadowed font.

  convert -background none -stroke black -fill white \
          -font Candice -pointsize 48 label:A -trim 
          \( +clone   -background navy   -shadow 80x3+3+3 \) +swap \
          -background none   -layers merge +repage  shadow_a.png
[IM Output]

The Layers Merge method was added to IM v6.3.6-2. Before this you would need to use the similar layer flattening operator "-mosaic" instead. However this operator has problems (see next).

Shadows and the Offset Problem

The problem with shadow is that a blurry shadow extends in all directions. To compensate the "-shadow" operator enlarges the actual original image by adding a border 2 times the size of the blur 'sigma' value given. That is if you blur a shadow using 'x3', it will enlarge the image by 12 pixels (2 times 3 pixels on every side).

To compensate for this enlargement, a shadow image is also given an appropriate negative Virtual Canvas Offset so that it will be positioned correctly relative to the image being shadowed. For a normal image that means the shadow image generated will have a negative offset.

This however generates a problem when your IM does not have a the "-layers" method 'merge' available. For example here we try to add a shadow on the left side, of the image as if a light shone from the upper right.

    convert rose: \( +clone  -background navy  -shadow 60x3-5+5 \) +swap \
            -background none   -mosaic   shadow_left_clipped.png
[IM Output]

As you can see as the shadow, was clipped by the "-mosaic" operator, because of the negative offset. Not good!

One solution is to add an initial offset to the original image so the resulting shadow images offset will not be negative.

    convert rose:  -repage +11+0\
            \( +clone   -background navy   -shadow 80x3-5+5 \) +swap \
            -background none   -mosaic   shadow_left.png
[IM Output]

Another method is offset both images by an appropriate amount after the shadow has been generated. This removes any negative offsets before you "-mosaic" them together. this requires the use of a '!' flag with "-repage" to add the given offset to both images.

    convert rose: \( +clone -background navy -shadow 80x3-5-5 \) +swap \
            -repage +11+11\! -background none  -mosaic  shadow_tl.png
[IM Output]

The amount of space need should be at least 2×'sigma'-'offset', or in this case 2×3--5 ⇒ 11 pixels, or you risk clipping the shadow. However space of about 'sigma'-'offset' usually produces an acceptable level of clipping.

It is a lot easier to just use a Layers Merge if it is available.

Shadow Outlines

You can also use "-shadow" to generate a fuzzy outlines of shapes, such as text, but you will need to offset the image to provide space on the top-left for the effect, of at least 2 times the blur 'sigma' value.

  convert -background none -fill white \
          -font Candice -pointsize 48  label:A -trim -repage 0x0+6+6  \
          \( +clone -background black  -shadow 100x3+0+0 \) +swap \
          -background none   -layers merge +repage  shadow_outline.png
[IM Output]

Here you can see one problem with using a blurred shape for outlining. The edge of the shape will always be at least 50% transparent, by the very nature of how blurring works.

To compensate you can either enlarge the shape of the image that will be shadowed, (for an example see Denser Soft Outline Font). Or you can adjust the matte values of the shadow image (using "-level") so that 50% transparent at the shape edges becomes fully transparent.

  convert -background none -fill white \
          -font Candice -pointsize 48  label:A -trim \
          \( +clone -background black  -shadow 100x3+0+0 \
             -channel A -level 50%,100% +channel \) +swap \
          +repage -gravity center -composite   shadow_outline_darker.png
[IM Output]

The above also shows another method of handling the shadow offset. Basically I just junked all "-shadow" generated offsets (using "+repage"), and center overlaid the original image on the larger shadow image.

You can use that method for normal shadowing too, by adding a appropriate composition "-geometry" offset the image, instead of getting "-shadow" to offset the generated shadow image.

  convert -background none -fill white -stroke black \
          -font Candice -pointsize 48  label:A -trim \
          \( +clone -background navy  -shadow 80x3 \) +swap \
          +repage -gravity center -geometry -3-3 -composite \
          shadow_geometry_offset.png
[IM Output]

The offset is a negative as you are offsetting the original image relative to the shadow.

This method will however clip the original source image, rather than the shadow image if the offset becomes larger that twice the blur 'sigma'. As such it can not be used for 'hard shadows' (using a 'x0' blur 'sigma'), unless you again add some extra space to the shadow image for the original to be added.

For some practical examples of shadowing see Thumbnail shadowing and Better 3-D Logo Generation.

Shadow in the Montage Command

As of IM v6.3.1 the "montage" "-shadow" setting, started to make use of the soft 'shaped' shadows this operator provides.

  montage -label Rose  rose: \
          -background none -geometry +5+5 -shadow  shadow_montage.png
[IM Output]

However as you can see no controls over the color, fuzziness and offset of that shadow is provided. Though "montage" never did provide such controls, beyond a simple on/off option.

Shadow Internals

Internally "-shadow" is extremely complex. Basically not only does it need to enlarge an image to accommodate a 'soft blurry shadow', but it also needs to blur the existing shape of the image, set its color appropriately, and finally adjust virtual page/canvas offsets; all to the users specifications.

For example given the following "-shadow" command...

    convert image_clone.png -shadow 60x4+5+5   image_shadow.png

The equivalent IM operation would be...

  convert image_clone.png -matte \
          -bordercolor none  -border 8  -repage -8-8\!  \
          -channel A -virtual-pixel transparent \
               -blur 8x4 -evaluate multiply .60 +channel
          -fill {background_color} -colorize 100% \
          -repage +5+5\!     image_shadow.png

Note that the value 8 in the above is two times the blur sigma, so as to provide enough space for the blurred shadow. However this means the final image will be 4 times sigma pixels larger. To compensate an equal amount of negative offset is also added.

Now as 2 time sigma negative offset will be added to the generated image, care should be taken to avoid the shadow being clipped, or incorrectly positioned relative to the original image. That can be done by either giving the original image an initial positive offset (such as 8-5 or +3+3 pixels), or using Layers Merge which understands negative offsets without clipping the final image.

Basically as previously mentioned caution is advised to correctly handle the offsets involved with shadow images.

The PNG, and MIFF formats are the only image formats I know that can handle a negative offset, as well as semi-transparent pixels. I recommended PNG be used if saving shadow images, for future use.

As I said "-shadow" is a very complex operation.

Of course while the above example is close to what "-shadow" does internally, it is not exactly the same.

The actual "-shadow" operator, does not change any of the global settings, such as border/background/fill colors, or the current virtual-pixel setting. Also it will short circuit the use of the "-blur" operator if the blur sigma is set to 0, to prevent the blur function from giving a warning for a zero sigma or radius.

FUTURE: overlaying multiple shadows

Overlaying two images with shadows, produces a unrealistic darkening of the
shadow where the shadow overlaps.  This darkening would be correct if each
object was lit by separate light sources, but more commonly the objects are
lit by the same light source.

For an example, see the line of photos across the top in..
   http://sempre-crescendo.nl/test/im

The solution is to overlay the one image over the other (shadow of one image
over the other), then mask out and re-create the background shadow of both
images together.  That is the background shadow should be generated
separately to the shadow falling on the behind object.

This complexity gets worse when you have three objects shadowing each other.
Also the offset and blurring from the shadow of each object should technically
be separate.  To generate that level of complexity, probably a 3-d ray-tracing
program should be used instead (sigh).


Specialized Blurs

There are a few other sorts of blurs that have been added to IM version 6, which have very special uses. These operate in specific directions, and not in all directions as most other 'convolve'-style operations do.

WARNING: All these blurs are experimental, and syntax has NOT been finalized!

Radial Blur

You can blur the image around in a circle using a "-radial-blur", as if it was spinning around and around. Though technically this is a rotational or angular blur, rather than a radial blur.

Note however that like a normal "-blur" operator, "-radial-blur" is affected by the "-channel" setting.

  convert -size 70x70 xc:none \
          -stroke red    -strokewidth 15 -draw 'line 35,5 35,65' \
          -stroke yellow -strokewidth  9 -draw 'line 35,5 35,65' \
          -channel RGBA  -radial-blur 30   radial_blur.png
[IM Output]

You can place the object off center (by adding some space to an image) for more interesting "-radial-blur" effects.

  convert -size 70x70 xc:none \
          -stroke red    -strokewidth 15 -draw 'line 5,50 65,50' \
          -stroke yellow -strokewidth  9 -draw 'line 5,50 65,50' \
          -channel RGBA  -radial-blur 90   radial_blur_90.png
[IM Output]

The blur argument is the angle the radial-blur covers. That is half that angle in each direction from the original image. So an angle of 180 is over a half circle, while 360 degrees will blur the image in a full circle.

  convert -size 70x70 xc:none \
          -stroke red    -strokewidth 15 -draw 'line 5,50 65,50' \
          -stroke yellow -strokewidth  9 -draw 'line 5,50 65,50' \
          -channel RGBA  -radial-blur 180   radial_blur_180.png
[IM Output]

  convert -size 70x70 xc:none \
          -stroke red    -strokewidth 15 -draw 'line 5,50 65,50' \
          -stroke yellow -strokewidth  9 -draw 'line 5,50 65,50' \
          -channel RGBA  -radial-blur 360   radial_blur_360.png
[IM Output]

You can even add a little Image Warping to make the effect more interesting...

  convert -size 70x70 xc:none \
          -stroke red    -strokewidth 15 -draw 'line 5,50 65,50' \
          -stroke yellow -strokewidth  9 -draw 'line 5,50 65,50' \
          -channel RGBA  -radial-blur 180 -swirl 180 radial_swirl.png
[IM Output]

The full circle radial blur, can be used to generate a rough circular gradients. However formulating the correct shape to generate the correct gradient can be extremely difficult, and probably not worth the effort.

  convert -size 80x80 xc:lightblue -fill red \
          -draw "path 'M 40,40   C 43,43 47,47 50,40 \
                  S 52,23 40,20   S 14,22 10,40   S 15,75 40,79 Z'" \
          radial_gradient_pre.gif
  convert radial_gradient_pre.gif  -radial-blur 360  radial_gradient.gif
[IM Output] [IM Output]

Motion Blur

You can add a linearly fading blur in one direction only (giving a radius and sigma, plus an the angle in which the blur should occur), by using a "-motion-blur".

This gives your image a look as if it (or the camera) was moving very very fast.

  convert -size 70x70 xc:none  -channel RGBA \
          -fill yellow  -stroke red  -strokewidth 3 \
          -draw 'circle 45,45 35,35'  -motion-blur 0x12+45  motion_blur.png
[IM Output]

Note that not only does the object get a trail, but the edges in the direction of motion also has the background blurred into it.

This leading edge blurring can be improved by re-drawing or overlaying the original image and re-applying a smaller "-motion-blur" multiple times.

  convert -size 70x70 xc:none -channel RGBA \
          -fill yellow  -stroke red -strokewidth 3 \
          -draw 'circle 45,45 35,35'  -motion-blur 0x8+45 \
          -draw 'circle 45,45 35,35'  -motion-blur 0x6+45 \
          -draw 'circle 45,45 35,35'  -motion-blur 0x2+45 \
          motion_blur_redraw.png
[IM Output]

Multiple motion blurs can be made to effect some spread of the trailing tail of the moving object. Sort of like dissipating smoke or flames.

  convert -size 70x70 xc:none -channel RGBA \
          -fill yellow  -stroke red -strokewidth 3 \
          -draw 'circle 45,45 35,35'  -motion-blur 0x12+25 \
          -draw 'circle 45,45 35,35'  -motion-blur 0x12+55 \
          -draw 'circle 45,45 35,35'  -motion-blur 0x12+40 \
          motion_blur_spread.png
[IM Output]

This technique can be used to generation a spreading shadow on the ground. Alternatively you could generate a motion blur, then radial blur it a little though that requires some image shifting to get the center right.
FUTURE example of a spreading shadow -- in compound fonts
You can also add some extra Image Warping to make things even more interesting...

  convert -size 70x100 xc:none -channel RGBA \
          -fill yellow  -stroke red -strokewidth 3 \
          -draw 'circle 35,80 45,70'  -motion-blur 0x20+90 \
          -background none  -rotate 50  -wave 5x25  -rotate -50 \
          -gravity center   -crop 70x100+0+0  +repage \
          -draw 'circle 35,80 45,70'  -blur 0x2 \
          motion_wave.png
[IM Output]


Note that while "-radial-blur" blurs in both directions, "-motion-blur" only blurs in one direction.

In both cases I recommend you pad your image with extra space around the edge (generally using "-border") as both of these specialized blurs have strong edge effects that is best to avoid.

If you find a more practical or interesting example or use of the above please email me a copy.


Feathering Shapes

When you are cutting out a shape from an image, you often want to feather or blur the edges of the shape a little to give it a smoother look, and to de-emphasise any parts outside the shape that may have accidentally been included, or jsut allow the image to fit into the background more.

For example here I have a GIF image which I overlay a light colored baground

  convert  shape.gif -background wheat -flatten  overlaid.png
[IM Output]

However as I am overlaying a GIF image with boolean transparency, and as a result has highly aliases, or staircase-like edges, the image looks very much out of place on the background. If you were dealing with real life images, the above result would look very artifical.

But by bluring the image transparency a little, I can make the overlay fit onto the background more smoothly.

  convert shape.gif -alpha set -virtual-pixel transparent \
          -channel A -blur 0x0.7  -level 0,50% +channel \
          -background wheat -flatten  edge_blured.png
[IM Output]

This by the way is the exact same technique used from generating Soft Edges on thumbnails.

For more examples of this look at the results of Fred Weinhaus's "feather" masking script.

As you can see this works very well for simple cases, when there is a high contrast between the overlaid image and the background. However there are serious problems when you want to use either a much larger feathering blur factor, or the two images are both very light colors.

Under Construction

Note that as blur extends both into and out of the are the alpha channel has to be adjusted so that the edge of the shape is zero (fully-transparent), but quickly becomes fully-opaque as to get further from the edge. An example of just such an alpha channel adjustment is provided by Color Lookup Tables with Transparency

This adjustment is critical, otherwise instead of de-emphasising the area outside the shape, you add a semi-transparent shadow or halo of the area outside the shape.

However blur has a particularly nasty problem in also smoothing the outline of the shape. For example...

  convert -size 100x60 xc: -draw 'polygon 5,5 50,30 5,55 95,30' \
          sharp_angles.gif
[IM Output]

If you blur this particular shape you get...

  convert sharp_angles.gif -blur 0x5  feather_blurred.gif
[IM Output]

Notice how the points of the mask was de-emphesised more than the the edges. Also how the internal angle seemed to be 'filled in', so as to show even more of the original background.

You can see this more clearly if we threshold the image.

  convert feather_blurred.gif  -threshold 50%  feather_blur_thres.gif
[IM Output]

This is the problem of using 'blur' as a method of fethering images. And is especially of concern when dealing with things like fingers, and ears as well as the areas between the legs. That is the appendages themselves and the spaces in between.

If the image has a cartoon like border outline, then this is not as big a problem for a '1 pixel' feather. But for real life images (with no definitive borders), it is a real problem.

A proper solution would be to find some sort of measure about how distant a point if from an edge of the shape, but such that two close edges do not add there effects together. A set of convolution operators called Morphology.


Convolution Kernels

Convolution Kernels...

General Convolution Operator...
  -convolve   -bias

  -convolve 1                   does not modify the image
  -bias {number}  -convolve 1   adds a fixed 'bias' to each pixels result.
  -bias 16384   -convolve .5    half color values, add 1/4 to each pixel
                                reduces black - grey25 and white to grey75

  More info at
    http://www.gamedev.net/reference/programming/features/imageproc/page2.asp
    http://www.dfanning.com/ip_tips/sharpen.html


  A basic 'kernel' for simple blur is
    0,1,0
    1,1,1
    0,1,0
  or..
    convert source.png -bias 0 -convolve 0,1,0,1,1,1,0,1,0 blur.png

  Sharpening using a laplacian convolution 'kernel'
     -1, -1, -1
     -1,  9, -1
     -1, -1, -1
  That is  multiply each pixel by 9, then subtract a copy of each of its 8
  neighbouring pixels.

  A sharpening-mask ???
    -1, -1, -1
    -1,  8, -1
    -1, -1, -1

  Emboss an image
    -1,-1, 1
    -1, 0, 1
     0, 1, 1

   However you may need to darken the result
   to prevent it being 'clipped' so a bias may also be needed...

     -bias 10000  -convolve -1,-1,0,-1,0,1,0,1,1


  Thanks to Krzysztof Gajda, aka 'cra3y' on the IM Forums, for the above info.


  NOTES:  The results of convolve is normalized  (should it?)
  EG:   -convolve 0,0,0,0,.5,0,0,0,0
  should produce a image multiplied by .5  but is then normalized!
  It is such a low level routine, I would not expect it to normalize the
  results.

Morphology....

  If you want to generate a kernel that is all ones.
  for example a 7x7 array of 1's you can use a extrememly large
  sigma and specify the appropriate radius, in a gaussian blur.

  As such
     -convolve 1,1,1,1,1,.....
  for a total of 49 ones is equivelent to
     -gaussian 3x65535

  This allows you to generate square kernel for binary mophological operators

  'Dialate'   for a 3x3 square kernel (radius=1) is thus
     -gaussian 1x65535 -threshold 0
  'Erode'  is thus
     -gaussian 1x65535 -threshold 99.999%

  'Open' is naturally a 'Dialate' followed by a 'Erode'
  and a 'Close' is a  'Erode' followed by a 'Dialate'

  A larger square kernel can be specified using larger radii


Create your own convolution 
   -fx   with relative pixels  EG: p[-1,-1]
         also see -virtual-pixel setting

Created: 19 April 2004
Updated: 6 October 2007
Author: Anthony Thyssen, <A.Thyssen@griffith.edu.au>
Examples Generated with: [version image]
URL: http://www.imagemagick.org/Usage/convolve/

a