ImageMagick v6 Examples --
Blurring and Sharpening Images

Index
ImageMagick Examples Preface and Index
Blurring Images
Sharpening Images (Under Construction)
Generating Shadows
Specialised Blurs
Feathering Shapes using Blur (under construction)
Related Operators (under construction)

Blurring, and its oppisite, sharpening of images is a very important aspect of image processing. In this section we will look at both.


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-blur" 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 Blur Operator.)

Blur/Gaussian Arguments

The arguments for "-blur" and "-gaussian-blur" 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 pixels that are within that many pixels of the one being blurred (a square radius). As such using a very small radius such as '1' effectively limited the blurring to within the immediate neighbours of each pixel.

Note that while sigma is a floating point, radius is not. If a floating point value is given (or internally calculated) it is rounded up to the nearest integer, to determine the 'neighbourhood' of the blur.

How much each neighbour contributes to the final result is still controlled by the sigma. A very small sigma (less than '1' ) limits their contribution to a small amount, while a larger sigma contributes more equal amounts from all the neighbours. The largest sigma of '65355' will produce a simple averaging of all the pixels in the square neighbourhood.

Also notice that for smallish radius but a large sigma you see artifacts appear in the blurred result. This is especially visible in the output for "-blur 5x8". This is caused by the small square neighbourhood 'cutting off' the area blurred, producing sudden stops in the smooth Gaussian curve of the blur, and thus producing Ringing Artefacts along sharp edges. So...

Never use a radius smaller than the sigma for blurs

The ideal solution is to simply set radius to '0x' as shown by 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 smallest radius IM would use is 3, and is typically 3 * sigma for a Q16 version of IM (a smaller radius is used for IM Q8, as it has less precision). The only time I would use a non-zero radius was for a very small sigma or for specialized specialized blurs. 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.

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. 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]

Note the color "#F000" is a fully-transparent red. It that is the background areas of the image is actually a invisible red in color, instead of the more typical fully-transpaent black. This is important for later tests.

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-blur" operators were applied as pure grey-scale operation, and as such did not adjust color weighting 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 Blur Operators

There has been some confusion as to which operator, "-blur" or the "-gaussian-blur" 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-blur" operator on the other hand is more mathematically correct as it blurs in all directions simultaneously. The speed cost between the two can be enormous, by a factor of 10 or more, depending on the amount of bluring involved.

In a more technical context, "-blur" is a 2 pass, 1 dimensional orthogonal convolution filter, while "-gaussian-blur" is a 2 dimensional cylindrical convolution filter. See Convolution for more details. The results of the two method 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-blur" because its faster. Some pixels will be different on the interior due to rounding, and the edge pixels may be different because of loss of Virtual Pixel edge effects, again in the intermediate stage.

In summary, the two operators are slightly different, but only minimally. As "-blur" is much faster, use it. I do in just about all the examples involving blurring.

Large Blur using Resize

Using large sigma values for image bluring is very slow. But onw technique can be used to speed up this process. This however is only a rough method and could use some mathematicaly rigor to improve results.

Essentually the reason large blurs are slow is because you need a large window or 'kernel' to merge lots of pixels together, for each and every pixel in the image. However resize (making image smaller) does the same thing but generates fewer pixels in the process.

The technique is basically shrink the image, then enlarge it again to generate the heavilly blured result. The Gaussian Filter is especially useful for this as you can directly specify a Gaussian Sigma define.

For example here I blue the small rose image by a sigma value of 5 using the two methods.

  convert  rose: -blur 0x5   rose_blur_5.png
  convert rose: -filter Gaussian -resize 50% \
          -define filter:sigma=2.5 -resize 200%  rose_resize_5.png
[IM Output] ==> [IM Output] [IM Output]

Note the sigma setting (used only on the enlargement step) is only half that actually desired as you are also doubling the image size. You can make overall resulting blur larger by adjusting both the downsize ratio and the given sigma value. The downsizing step is the one that produces the speedup but you should have at least soem bluring in upsize step as a quality control.

This is just an example of the technique. It is really meant to be used for very very large sigma values on very very large images. For example in blurs using a sigma of 10 or more on modern digital photos.

This technique is also used to generate multi-level blur of a single image in a Sparse Color Shepards, Alternative.



Sharpening Images

Under Construction

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.

Unsharp Images

Under Construction

Both the "-sharpen", and "-unsharp" operators, work using the exact same technique of subtracting a blur from the original image.

For the internal details of how both "-sharpen", and "-unsharp" actually work see Unsharpen Convolution.


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

From comments on  Sharpening with ImageMagick from Alex Beels

  Matching GIMP unsharp
    Take gimp radius and add 1 => IM sigma
    Threshold divide by 255    => IM Threshold

  So  GIMP  radius=2  amount=1.5  threshold=5  results in
    -unsharp 0×3+1.5+0.0196

  Another suggested that   im_sigma = sqrt(gimp_radius)

Raw notes from Fred Weinhaus

Blur Image for test.

A_original.jpg

convert A_original.jpg -blur 0x3 A_original_blur3.jpg

sharpen is just a gaussian type blurred image subtracted from the image to
make an edge image (high pass filter), then equally blends that back with the
original, so one has a high pass enhanced image.

convert A_original_blur3.jpg -sharpen 0x3 A_original_blur3_sharp3.jpg

unsharp is more complex. It is similar. It takes the difference (edge result)
as above, i.e. like sharpen BUT only blends some fraction or multiple of that
with the original image, AND only if the difference is above a threshold. Thus
unsharp 0x3+1+0 is basically the same as sharpen 0x3

convert A_original_blur3.jpg -unsharp 0x3+1+0
A_original_blur3_unsharp3_1_0.jpg

compare -metric rmse A_original_blur3_sharp3.jpg
A_original_blur3_unsharp3_1_0.jpg null:
164.661 (0.00251256)

The difference may be due to whether one uses a separable (gaussian) blur
filter or not in one or the other but not both. Or it could be just some
slight differences elsewhere in the IM implementation.

If one blends less with the original, one gets less sharpening.

convert A_original_blur3.jpg -unsharp 0x3+0.5+0
A_original_blur3_unsharp3_0p5_0.jpg

If one blends more with the original, one gets more sharpening.

convert A_original_blur3.jpg -unsharp 0x3+2+0
A_original_blur3_unsharp3_2_0.jpg

If one increases the threshold, then one gets less sharpening again.

convert A_original_blur3.jpg -unsharp 0x3+2+0.2
A_original_blur3_unsharp3_2_0p2.jpg

Several of my (Fred's) scripts, binomialedge, gaussianedge, sharpedge use this
blending concept (between the high pass filtered result and the original
image) and a description is there with the scripts. The thresholding in my
scripts is done differently and for a different purpose.

Sharpen using de-convolution

There is a technique of using de-convolution (division in a Fast-Fourier
generated frequency form of images),  This works best when the exact 'blur'
that was applied to the original image is known, or calculated in some way.

At the moment only raw 'DIY' methods are as yet available in IM
and a number of such methods are demonstrated (trialed) in the sub-section
Fourier Multiply/Divide.


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]

While it is easiest to just use a Layers Merge, it will tend to shift the overall offset of the resulting image. The shift however is not caused by the layering method, but due to "+repage" removing any negative or positive offset that may be present in the resulting 'layer' image. See Shadows and the Offset Problem for alternative techniques.

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).

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]

If there is enough space for the shadow to be included without clipping, in the original image, you can use this command. It uses a special 'DstOver' composition method so as to avoid the need to swap the order of the two images.

  convert -background none -stroke black -fill white \
          -font Candice -pointsize 48 label:'A ' \
          \( +clone -background navy -shadow 80x3+3+3 \) \
          -background none -compose DstOver -flatten  shadow_a_size.png
[IM Output]

You can probably see a small amount of clipping in this as the original image did not have quite enough extra space for the requested shadow.

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. Note 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.

Another alternative is to expand the original image so as to make enough room for the final shadow. This is the BEST way of handling shadows, while preserving the images original location on the virtual canvas.

For example here I pad out the original image with some extra space for the shadow, and then underlay the shadow image directly. I included a border in the displayed image result so that you can see that the final image remains centered in the 'padded' image.

  convert rose: -bordercolor None -border 11x11 \
          \( +clone -background navy -shadow 80x3+5+5 \) \
          -background none -compose DstOver -flatten \
          -compose Over  shadow_space.png
[IM Output]

The amount of padding needed should be at least 'sigma'+abs('offset') or better still 2×'sigma'+abs('offset'), to ensure the shadow is not clipped. Padding can be asymmetrical to reduce space, but typically a symmetrical padding (like the above) is used for convenience.

Note that while the "-compose Over" setting is not actually needed in the above, it is recommended. Otherwise later operations (even in other "convert" commands) could be effected, with unexpected results. That is a non-standard compose setting can effect other operations, including: image layering, adding borders, or frames, or simply other compositions.

Shadows and Composite

Many people on the forums generate a shaodw image and then try to use the lower-level "-composite" to merge the images. For example directly overlay the original image onto a generated (larger) shadow image.

  convert rose: \( +clone  -background navy  -shadow 60x3 \) \
          +swap -composite  +repage shadow_composite.png
[IM Output]

The first point to remember is that the Composition Operators are very low level and do not read any layer or vitural canvas offset either original image, or the Shadow Operator may have. In fact we still need to remove or adjust the posibly negative (bad) offset shadown added using the Repage Setting.

This means that the offset you see on the above example is being generated simply because of the way shadow enlarged the input image to give the shaodw some space. The shadow is where it is solely due to the expansion of the shadow image by 2 times sigma. Further, if you use a 'hard shadaow' (zero sigma) you would also end up with no offset to the shadow at all, and thus the shadow will be hidden by the original image, other than a posible dark halo edge effect.

You have essentually give up the built-in offset calculation that the Shadow Operator provides.

Of course you can calculate and set the appropriate Composite Geometry/Gravity settings instead, and the easiest way is to use a "-gravity Center" setting, as the enlarged shadow image is expanded equally on all sides.

  convert rose: \( +clone  -background navy  -shadow 60x3 \) +repage \
          +swap -gravity center -geometry -3-5 -composite shadow_geometry.png
[IM Output]

Note that the centered geometry offset is negative as the image order was swapped.

Shadow Outlines

You can also use "-shadow" to generate a fuzzy outlines of shapes, such as text. By using Layers Merge IM will automatically add the extra space needed for the semi-transparent blur.

  convert -background none -fill white \
              -font Candice -pointsize 48 label:A -trim \
          \( +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).

Better still you can adjust the transparency of the shadow image, using a Level Adjustment so that a 50% transparency along the edges of the shape becomes fully opaque.

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

Another method of handling the shadow positioning and offset, is to basically junk all the "-shadow" generated offsets (using "+repage"), and center overlaid the original image on the larger shadow image.

By adding a "-geometry" composition offset you can then offset the shadow as a separate action.

  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]

However notice how the offset is a negative to what you would normally use for positioning the shadow. This is because you are really offsetting the text shape and not the shadow, so it is in the opposite direction.

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 include some padding space to the shadow image for the original image to be overlaid. With a soft fuzzy shadow however that is rarely a problem.

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 no controls for setting the color, fuzziness and offset of that shadow is provided, as "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 a 2 times 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 use the previous techniques to correctly handle posible negative 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.

The solution is to overlay the one image over the other, applying the shadow
effects to the opaque parts of each layer image in turn. That is the
background shadow should be generated separately into each layer.  Remember
the shadow cast by the top most layer should become fuzzier than the shadow
contribution of the bottom most layer.

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 ways, and not in all directions as most other 'convolve'-style operations do.

They also may not work as well as other methods of generating specialized blurs, such as distorting images before and after an more normal blur. For example see Polar Cycle Tricks, and Elliptical (mapped) Blurring.

WARNING: All these blurs are experimental, and syntax may change!

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 generate 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. 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 using Blur

Under Construction

WARNING: This section is now out of date, and users whating to correctly feather image should look at Feathering Shapes using Distance. What is shown here is known as 'Blur Feathering' which as is shown in the later part is a 'False Feathering Technique'. Even so it is still a useful method but only with 'convex' image 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-emphasize any parts outside the shape that may have accidentally been included, or to allow the image to fit into the background without making it of obvious it is a copy-n-paste.

Basically insteand of having a 'hard' edge to some shape, soften it to 'fake' anti-aliasing, or lens blurring, so that the paste is more seemless.

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 50,100% +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.


Note that as blur extends both into and out of the shaped area, 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 CLUT with Transparency Handling

This adjustment is critical, otherwise instead of de-emphasizing the area outside the shape, you add a semi-transparent shadow or halo of the area outside the shape. Basically some semi-tranparent 'undefined color' that was previously hidden by the image transparency.

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-emphesized more than the the edges. Also how the internal angle seemed to be 'filled in', whic with transparency can result in full-transparent pixels becomming semi-transparent. That is pixels with a undefined color may actually become visible!

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 effect on the shape of 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. This distance measuring operation, has now been added to IM, and is known as Distance Morphology. For details of using this for feathering see Feathering Shapes using Distance.


Related Operators

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

  -median
    Set each channel color of the pixel to the median value of all all pixels
    within a given radius. (median = center most value of all values found,
    half on one side, half on the other).  This is a way of "de-speckling" an
    image  (such a dust in a scan).  But could distort edges, cause some color
    channel aburation, and remove thin lines.

    This filter is the best technique to use for removing Salt & Pepper
    noise, especially on gray scale images.

    It is suggested that a trim for a scan use a median filtered image for
    attempting to find the appropriate bounding box.

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

    See forum discussion
      http://www.imagemagick.org/discourse-server/viewtopic.php?f=1&t=10266

  -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

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/blur/