ImageMagick v6 Examples --
Distorting Images

Index
ImageMagick Examples Preface and Index
Simple Distorts
Rotate and Shearing
Circular Distorts
General Distortion Techniques
Generalized Distortion Operator
Distortion LUT Maps
Distortion Animations (fun examples)
Affine Matrixes, and DIY Distortions (separate page)

Distortions are operators that warp or re-arrange the contents of the image. In ways similar to fun-house mirrors you too can distort images in extreme ways. The image itself remains intact, but the location of the various parts of the image could be wildly displaced on the canvas.


Simple Distorts

Flipping, and Mirroring

[IM Output] These simple distortions of the image doesn't change the actual images. They don't even change the rectangular nature of the image, just re-arrange things.

For these examples lets use this cute looking koala image...

The simplest image distortion is to rearrange the pixels in the image so as to "-flip" it upside-down.

  convert koala.gif  -flip  flip.gif
[IM Output]

Or by using "-flop" you can generate a mirror image.

  convert koala.gif  -flop  flop.gif
[IM Output]

Transpose and Transverse, Diagonally

The "-transpose" and "-transverse" image operations produce diagonal mirrors of the image.

The "-transpose" mirrors the image along the image top-left to bottom-right diagonal.

  convert koala.gif  -transpose  transpose.gif
[IM Output]

While "-transverse" mirrors the image along the image bottom-left to top-right diagonal.

  convert koala.gif  -transverse  transverse.gif
[IM Output]

Rectangular Rotates

All the above operations, will essentially produce a mirror image of the original. The "-rotate" operator provides the non-mirrored versions of the image.


  convert koala.gif  -rotate   0  rotate_0.gif
  convert koala.gif  -rotate  90  rotate_90.gif
  convert koala.gif  -rotate 180  rotate_180.gif
  convert koala.gif  -rotate -90  rotate-90.gif
  convert koala.gif  -rotate 360  rotate_360.gif
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Note that "-rotate" is a simple distort only if you use a rotation angle of a multiple of 90 degrees. Any other angle will introduce other more complex pixel level distortions into the image.

You may notice that a positive angle of rotation is clock-wise, which seems to be mathematically incorrect. Internally however, it is mathematically correct and is caused by use a of negated Y-axis. That is the Y-axis goes from 0 at the top and positive downward. Because of this the coordinate system in reversed, and thus rotation is also reversed mathematically.

Digital photos can also be rotated to match the recorded Camera Orientation by using the "-auto-orient" operator. This was added in IM v6.2.7-8.

Rolling Images like a bad TV

You can "-roll" an image horizontally (like a TV that is out of sync). The amount of the roll is given in pixels.

  convert koala.gif  -roll +0+20  roll_horiz.gif
[IM Output]

Of course you can also roll the image sideways...

  convert koala.gif  -roll +30+0  roll_vert.gif
[IM Output]

Or by using a negative number of pixels, you can roll it in the opposite direction.

  convert koala.gif  -roll +0-20  roll-horiz.gif
[IM Output]

Simple Distorts Summary

The most important aspect of all these operators is that you can add them all together in many different ways such that the result will be exactly as if no operation was performed at all.

  convert koala.gif -roll +25+0 -rotate 90  -flop \
          -roll +0-25  -flip  -rotate 90    original.gif
[IM Output]


Rotating and Shearing

While all the above image distorting operators preserve the basic rectangular format of the image, the next set does not. The results of these operators do not fit in the original rectangle (or even the rotated rectangle). To ensure the result contains the whole of the original image, the size of the image is enlarged to accommodate.

Rotating Images -- Simple Image Rotation

As you saw above the "-rotate" operator can perform simple, image preserving distorts, when you rotate image in units of 90 degrees.

With other angles however, the rotated image will not fit nicely into a rectangular image. Consequently to ensure that no image data is lost, the size of the final image is enlarged just enough to accommodate the rotated image.

  convert koala.gif -rotate 30 rotate.jpg
[IM Output]

Note that the direction of rotate is clock-wise. This may seem illogical mathematically, until you realise that the image coordinate system is relative to the top-left of the image instead of the mathematical norm of the bottom-left. The result is the angle of rotation is also inverted. This is important to keep in mind when dealing with any form of image rotation, vs a diagrammatic or mathematical rotation.

The extra space added by ImageMagick is colored with the current "-background" color setting. Allowing you to specify the color to fill into the corners.

  convert koala.gif -background lightblue -rotate 30 rotate_color.png
[IM Output]

Of course if you want to fill with the transparent color, you will need to ensure the image can handle transparency (by using a "-matte" operator to add an alpha channel), and is saved to an image format that can handle transparency.

  convert koala.gif -matte -background none -rotate 30 rotate_trans.png
[IM Output]

If the extra space comes out black, then your output image output format does not allow the use of an alpha channel, (most likely the JPEG format), so the transparency defaults to black.

Before version 6.1.2, "-rotate" did not handle transparency correctly, producing stripes of black and transparent in the corners of the rotated image. The workaround for this problem was rather complex, involving rotating the alpha channel separately to the colors.

But what if you don't what that extra space, wanting to preserve the images original size? Well you can use a centered "-crop" to return the image to its original size.

If you don't know what the original size was, you can use an alpha composition trick (see the 'Src' Compose Method) to restore the image back to its original size.

    convert koala.gif -matte \( +clone -background none -rotate 30 \) \
            -gravity center  -compose Src -composite   rotate_resized.png
[IM Output]

The "-rotate" operator also understands two extra flags. If a '>' symbol is added to the rotate argument (before or after the number), then the image will only be rotated if the image is wider than it is taller. The result is that this flag will only rotate 'landscape' (wide) style images into 'portrait' (tall) style images.

The other flag '<' does the opposite, only rotate images that are taller than it is wide.

Digital photos can also be rotated to match the camera orientation (based on the "EXIF:Orientation" meta-data) by using the "-auto-orient" operator. However remember saving back to JPEG format may not be a good idea.

The Rotate Operator is actually implemented using various Simple Distorts and Image Shears, a technique known as 'Rotate by Shear' (RBS) and first publish in research papers by Alan Paeth.

Because non-simple rotates are implemented as a sequence of Shears there are some subsequent effects that result.

First areas added into the image corners are just directly filled in using the "-background" color. You can not control this using Virtual Pixel Setting.

Also you can not control the mixing of colors during the Image Rotation using the Interpolation Setting. Which means you can not preserve the original colors of the image.

Rotating a Thin Line - rotation color blurring

For example here I rotated a simple vertical line of pixels by 17 degrees, which I then scaled so as to show the effect of the individual pixels in the resulting image.

  convert -size 10x30 xc: -draw 'line 5,0 5,30' \
          -background white   -rotate 17  -scale 500%  rotate_magnify.gif

Note how the line seems to phase in and out in the rotated image, as it crosses pixel boundaries. Not only that, but as rotate is implements as multiple shears (see note above), the line only phased in sharply every second pixel column. That is the result is actually more blury than it needs to be.

[IM Output]

This 'rotation blur' is especially noticable when you rotate small text and labels, either attached to or part of a photo, by very small angles. Such lines contain lots of fine detail that 'dissapeares' in a regular and highly notice wave of blurring across the image.

The only direct solution to this problem is to use a Pixel Mapping technique, such as an Affine Distortion or Scale-Rotate-Translate (SRT). For examples of this see Interpolation of a Rotated Line.

However a much easer, though indirect method is to use the Super Sampling technique (see below). Basically we rotate an image that is at least twice (or more) the size of the final image size wanted. After rotating the resize will sharpen the resulting rotated image producing very sharp and clean lines, edges, and fonts.

An example of this solution is given both in the Super Sampling introducion below, and also in a more practical way, when using the Polaroid Transform, which is especially vulnerable to small angle rotation blur, of the added text caption.

For a more deeper understanding of the various image rotation algorithms and the issues involved see Leptonica Rotation.

Shearing Images -- Linear displacement

The "-shear" operator takes each row (or column) of pixels and slides them along so that each row (or column) is displaced by the same amount relative to the neighbouring row (or column). Its two arguments are given in terms of angles.

Just as with "-rotate" the operation increases the size of the resulting image so as not to loose any information.

However shear is more complex in that it is really a double operation.

  convert koala.gif  -shear 20      shear_rot.gif
  convert koala.gif  -shear 20x0    shear_x.gif
  convert koala.gif  -shear 0x50    shear_y.gif
  convert koala.gif  -shear 20x50   shear_xy.gif
  convert koala.gif  -shear 20x0  -shear 0x50   shear_xy2.gif
  convert koala.gif  -shear 0x50  -shear 20x0   shear_yx.gif
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

If you look at the results you will see that the double form of the "-shear" operation is to do the X shear first, followed by the Y shear (with an appropriate final image size correction). This is fundamentally different to a Y shear followed by the X shear.

If only one number is provided (without any 'x') then "-shear" will apply it in both the X and Y directions as a sort of poor mans rotate. For this reason the units of shear are in degrees.

The "-background" color setting is of course used as the color for the extra space added.

  convert koala.gif  -background none  -shear 30  shear_trans.png
[IM Output]

Before IM version 6.1.2 "-shear" did not handle transparency. The workaround for for this problem was rather complex, involving shearing the alpha channel separately to the colors.

Note that using a "-shear" in this way a proper method of rotating an image.

To actually use shear to rotate an image properly, you would need to use a need to perform three shearing operations in the form of "-shear {X}x{Y} -shear {X}x0 -crop ... ", however working out the proper values for the '{X}', '{Y}' and final crop requires some trigonometry. The builtin "Rotate Operator" (see above) is actually implemented in this way.

Note that shearing in the X direction will not affect an images height, while shearing the the Y direction will not effect the images width. The result is that the area covered by some object within the image will not change (only the surrounding container holding the image).

The Shear Operator is implemented as a direct 'warping' of the source image. As a consequence it does not use the Interpolation Setting or the the Virtual Pixel Setting.

As a result the areas added to the image is only filled by the current "-background" color, and no means are provided to preserve the original colors of the image.

Waving Images - Sine Wave Displacement

The "-wave" operator is like "-shear" in that it adds a 'linear displacement' to images. However this operator will only displace columns of pixels vertically according to a sine wave function.

There are two arguments to the "-wave" operator. The first is the maximum height or amplitude the pixels will be displace either up or down, while the second is the wavelength of the sine function in pixels.

  convert koala.gif  -wave 10x64 wave.jpg
[IM Output]

Note that because pixels can be displaced up to the given amplitude that much extra space will always be added to both the top and bottom of the image, even if that space is not actually needed.

For example by adjusting the arguments so that the wavelength is double the width of the image, you can make the image into a arc.

  convert koala.gif  -wave 20x150 arched.jpg
[IM Output]

In this sort of case the unused space can be removed using either a "-chop", "-shave", or possibly even a "-trim" operation.

Lets clean up the previous example by using a negative amplitude to flip the arc over, and use "-chop" to remove the unused space the "-wave" operator added.

  convert koala.gif  -wave -20x150 -gravity South -chop 0x20 arched_2.jpg
[IM Output]

Of course the "-background" color setting can be used to define the extra space added to the image.

  convert koala.gif -matte -background none -wave 10x75 wave_trans.png
[IM Output]

As you can see from the above examples "-wave" only applies in the vertical or 'Y' direction. If you want to add a wave in the X direction, you'll need to rotate the image before and after you apply the wave.

  convert koala.gif  -rotate -90 -wave -10x75 -rotate 90 wave_y.jpg
[IM Output]

The technique can be used to add a wave pattern or vibration to an image at any angle. Examples of this is given in the Vibrato Font and in the Smoking Font.

One other limitation with "-wave", is that the wave only starts at zero. That is the left most column is not displaced, while the next few rows are displaced downward (positive X direction), unless you give a negative amplitude for an initial vertical offset.

Basically the "-wave" operator does not (at this time) allow you to specify an offset for the start of the sine function. This can be rectified however by adding, then removing, an image offset using "-splice".

  convert koala.gif  -splice 19x0+0+0 -wave 10x75 \
                     -chop   19x0+0+0     wave_offset.jpg
[IM Output]

While "-wave" will not make use of the current Virtual Pixel Setting to define the color of the added areas, it will look at the current Interpolation Setting to map the colors from the source to the image generated. This means wave will tend to blur pixels slightly in vertical bands across the image...
EXAMPLE: wave a image of horizontal lines.

However you can use a special Super Sampling technique to improve the blurring of the results.

EXAMPLE: supersampled wave image


Circular Distortions

So far the image distortions have been rather mild, with very little stretching, expanding or compressing of the image data. That is the data remains pretty well unchanged.

These next few image operators are true image distortions, and can result in a image that is so distorted, the original image can not be determined. The colors being merged into a twisted blurry mess.

It also happens that they limit the distorting effects to a circular area with little to no distortion of th eoriginal image at the edge of the image rectangle. That means you can use these operators on a small area or Image Region and the result will still blend into the original image without it looking like it was: cut out, warped and pasted back into place.

Imploding Images

The "-implode" operator warps the image so as to pull all the pixels away from the edge toward the center. Its sort of like sticking a vacuum, or 'black hole' in the center of the image and sucking the pixels toward it.

Caution however is advised to only use very small values, to start with.

  convert koala.gif -implode .6 implode.gif
[IM Output]

Using increasingly large values will essentially suck all the pixels in a circle around the center, into oblivion.

  convert koala.gif -implode 5 implode_big.gif
[IM Output]

However be warned that using any "-implode" value larger than '1.0' is also effected by the Virtual Pixel Setting, as the algorithm starts to make color references beyond the boundaries of actual image itself. As the default "-virtual-pixel" setting is 'edge', the edge color or surrounding frame on an image can have a major effect on the result.

For example these two images are the same except one had white border added to it. this basically shows the area which is using colors looked up from beyond the bounds of the image proper. The area normally defined by the "-virtual-pixel" setting.

  convert rose: -gravity center -crop 46x46+0+0 +repage \
                                              -implode 3   implode_rose.gif
  convert rose: -gravity center -crop 44x44+0+0 +repage \
                -bordercolor white -border 1  -implode 3   implode_rose_2.gif
[IM Output] [IM Output]

Other "-virtual-pixel" settings can result in highly distorted copies of the image appearing withing the imploded region, here for example I implode simple box image with a 'tile' setting.

  convert -size 94x94 xc:red -bordercolor white -border 3 \
          -virtual-pixel tile     -implode 4   implode_tiled_box.gif
[IM Output]

More "-virtual-pixel" effects are explored on Implosion Effects of Virtual Pixels.

As the number of pixels being merged into a small area increases, the results start to get a distorted 'pixelated' look. To get a better more consistent result, you can increase the number of pixels implode works with, using a technique called Super-Sampling.

Basically by using a larger image (enlarging the source image if necessary), doing the distortion, then shrinking the result to its final size you will produce a much better result.

  convert -size 94x94 xc:red -bordercolor white -border 3 \
          -virtual-pixel tile  -resize 400%  -implode 4 -resize 25% \
          implode_tiled_ss.gif
[IM Output]

As you can see you get a much smoother and more realistic result that shows the internal detail of the distortion much better. We will look at this technique a lot more later.

By using a larger "-border" around the image being imploded, and later removing it again, you can also warp the edges of an image.

  convert koala.gif -bordercolor blue -border 20x20 \
          -implode .5   -shave 18x18  implode_border.jpg
[IM Output]

As of IM version 6.2.1 you can also use a transparent border, or image with transparency...

  convert koala.gif -bordercolor none -border 20x20 \
          -implode .5   -shave 18x18  implode_border_trans.png
[IM Output]

Exploding Images

By using a negative value with the "-implode" operator, you can explode the image. This is however more like magnifying the center of the image pushing all the mid-radius pixels out toward the edge, rather than a true explosion.

  convert koala.gif -implode -2 explode.jpg
[IM Output]

Using larger value will essentially enlarge the center most pixels of the image into a circle two-thirds the size of the smallest image dimension.

  convert koala.gif -implode -30 explode_big.jpg
[IM Output]

And here is a 'Super-Sampled', version.

  convert koala.gif -resize 400% -implode -30 \
          -resize 25% explode_big_ss.jpg
[IM Output]

The central color of the internal 'explosion' is set by the color of the center of the image (or region). This means that by changing the colors around that point, before exploding your image, you can control the 'flash' effect of the explosion. See Distortion Animations for an animated example of this color control.

Swirling Image Whirlpools

The "-swirl" operator acts like a cake mixer. It will warp the image around in a circle the number of degrees you give it as an argument.

  convert koala.gif -swirl 180 swirl.jpg
[IM Output]

By adding a border, and combining with "-implode" you can give the look of a whirlpool sucking the image up to oblivion.

  convert koala.gif -bordercolor white -border 20x20 \
          -swirl 180 -implode .3  -shave 20x20   whirlpool.jpg
[IM Output]

I have animated these swirling effects, which you can see below in Distortion Animations.

Limiting the Distort with Regions

All of the distortion operators work on a full image. However some of the distortion methods allow you to distort a smaller area or "-region".

For example here we have a line of stripes.

  convert -size 600x70 xc:darkred \
          -fill white -draw 'roundrectangle 5,5  595,65 5,5' \
          -fill black -draw 'rectangle 5,25 595,31' \
          -fill red -draw 'rectangle 5,39 595,45' \
          lines.gif
[IM Output]

Now by defining regions we can distort the line in various ways in specific places.

  convert lines.gif \
          -region 90x70+10+0    -swirl  400  \
          -region 90x70+100+0   -swirl  400 \
          -region 90x70+190+0   -swirl -400 \
          -region 120x70+280+0  -implode 1.5 \
          -region 100x70+380+0  -implode -7  \
          -region 101x90+480-10 -wave 10x50 \
          lines_regions.gif
[IM Output]

Note that the two Circular Distortion operators "-implode" and "-swirl", fit into the use of regions very well, as they have the property that the outside edge of the distorted image matches up to the rest of the image outside the defined region.

Also note that we could even use a Wave Distortion in the above, but that to do so, I had to enlarge its defined "-region" of operation. This is very tricky, and only works in the special case when the region covers the whole height of the image being processed.

How Regions Work

In reality the way regions work is they basically extract area of the image that the "-region" covers. This image is then run through the distortion operator, and then it is Composed back on top of the original image.

This actually works for any image operation (not just distorts).

For example here I define a region on the koala image, and rotate it, with a 'blue' background 'corner fill'...

  convert koala.gif  -region 30x30+10+10 -background blue -rotate 30 \
          koala_region_1.gif
[IM Output]

Even though this operation was not very useful in terms of results, you will notice that only the defined region was modified.

The other thing that you should notice, is that as the resulting image was enlarged by the rotation the enlarged image was still overlaid at the original coordinates, overflowing the areas from which the image was extracted.

The point this is that while regions can be used for interesting effects, or for limit the effect of operators, it will break down in its intended use if the size of the extracted image is changed. That is you need to be careful in what operations you apply to a extracted region.

Now what if instead of using a 'blue' corner fill, we instead use a transparent fill.

  convert koala.gif  -region 30x30+10+10 -matte \
          -background none -rotate 30   koala_region_2.gif
[IM Output]

This shows that when a region is overlaid back onto the original image, anything that is transparent will show the original image. That is the extracted region is only a copy, and does not erase the original area.

Finally you can do multiple operations on a region. For example...

  convert koala.gif  -region 30x30+10+10 -matte \
          -background blue -rotate 30 -background red -rotate 30 \
          koala_region_3.gif
[IM Output]

Note that the second 'red' rotation was applied to the previously 'blue' rotated reagion extracted image. That is the modified region was not restored to the original image until after both rotations had been applied.

In other words, the "-region" operator extracts an area of image to perform operations in, and will only restore that area (using Composite Over) when either the end of the command is reached, or another "-region" is requested.


General Distortion Techniques

Now that we have been introduce to the simple distortion operators that IM provides, lets take a step back and look at the nitty-gritty, and see how image distortions actually work, and how you can improve the way you use them.

Later we'll go forward to much more complex ways of distortion images, including methods that are not directly built into ImageMagick.

There are only a few basic ways an image processor can distort images.

The Simple Distortion operators for example are achieved by Pixel Swapping. That is individual pixels, or even whole rows and columns of pixels are just swapped around to Flip, Roll, Transpose, and even do Rectangular Rotates of images. No color changes are made, and the number of pixels remains the same.

The next method of distorting images is to Shifting or Shear the pixels either horizontally or vertically, such as what IM does with Image Shearing and the Wave Distortion above. The shears in turn providing a method to Rotate Images by any given angle, in a manner that should be quite fast.

However pixel shifting methods are limited to those basic distortions. It can not scale an image to a different size for example. You also have very little control over the handling of new areas of the resulting image that is not covered by the source image. In the above mentioned functions IM just sets the missing areas to the current background color.

To be able to distort images in a much more general way you need to use a more general distortion technique known as Reverse Pixel Mapping. For example this method is used by the more complex Circular Distortions such as Imploding and Swirling images.

Reverse Pixel Mapping

If we try to use a direct mapping each pixel from the source image to destination image, one pixel at a time, as is done for Simple Distorts, we get lots of problems. A specific pixel may map to a location that another pixel has already colored (overlaps), while a destination position may not even get any color from the source image (holes).

The reason is that pixels require an integer location in both the source and destination. But a general transformation generally produces a real, or floating point value. That is a direct mapping of pixels from an old location to a new position just does not work.

Reverse Pixel Mapping does the opposite. For each and every pixel in the destination image, the color needed for that pixel is looked up from the pixel array in the source image. As each and every pixel is process, we can be sure that every pixel in the destination gets one and only one color. So as long as we can figure out the 'source' location for each destination pixel, we can distort a source image to the destination image using any mathematical formula you can imagine.

[photo]

In Summary, a distortion mapping does the following.
For each pixel (I,J) in the destination or output image
   Map the I,J pixel position to a X,Y pixel position in the original image
   Look up the Color of the original image at position X,Y
       Using color interpolation, work out the appropriate color.
       Or the virtual-pixel setting, if it misses the actual source image.
   Set the destination images color for pixel I,J

Note that I used the variable names 'i,j' and 'x,y' in the above as these variables map into the variables that you would use in the "-fx" or DIY Operator.

The distinction between forward and reverse mapping is important as most mathematical transformations are defined as forward mappings, mapping a single source (X,Y) position to a destination (I,J) position. And indeed a 'forward mapping' works well for vector graphics, and drawing lines where you can just map the ends of the line and draw it. This is especially true for any linear transformation, such as rotations, where lines remain straight. It is in fact what is done for vector based languages such as such as postscript and SVG.

But for a general raster image, you must use a reverse mapping to distort the image, to ensure you 'fill in' all the pixels of the destination image. The problem is not all forward mapping transforms, work as a reversed transform. On the other hand some image distortions work very well when used as a reverse mapping, allowing you to produce interesting effects.

You can see the above in more detail in a DIY explanation in the sub-page DIY Distortion Mapping, as well later in the form of a more generalised technique of using Distortion LUT Maps.

What's in a name?

During my study I found that there is no real clear naming of this image processing method. The actual algorithmic process is known a 'Reverse Pixel Mapping', while the use of mathematical equations is known as a 'Geometric Transformation'. If the distortion is controlled by the movement of various control points, it is known a 'Image Warping' or 'Rubber Sheeting'.

Images can also be subdivided into smaller simpler units (generally triangles) using a process known as 'Image Registration', to map similar points from one image to another. From the distortion of these triangles, you can then perform 'Image Morphing' such as you see in movies and music videos.

In the 3d modeling, and in 3d computer games, the same techniques are also used to give some type of colored pattern to flat and curved surfaces in a method known as 'Texture Mapping'. This can involve sub-divided images into regions that approach a single pixel.

All the above are very closely related, and all basically involve the exact same thing, distorting images by looking up a pixel color basied on a specific desination coordinate. What term should be used... Take your pick.

For an alternative discussion of distortion transforms, see Leptonica, Affine Implementation and specifically its discussion of 'point-wise' method. The other method, 'sequential', is essentially how IM implements its Rotate and Shear distortion operators (see above).

Direct Interpolated Pixel Lookup

There are still a few problems with the above Reverse Pixel Mapping technique. First of all is that when mapping a pixel from an integer position on the destination you can end up with a non-integer position on the source. That is a location that falls between pixels on the source image. To determine what color should be returned a process called Interpolation is used to determine the final color for that real position by mixing the colors of the surrounding pixels.

Then you have the problem of what to do when the mapped position 'misses' the source image completely. What color should be returned is determined by the Virtual Pixel setting, which can let you pick a color such as, the color of the nearest edge of the source image, pretend the source image is infinitely tiled (or mirror tiled), or use some specific color such as 'white', black, or 'transparent' or the user defined background color.

There is also the possibility that there is no mathematically valid source position for the destination position being mapped. For example the pixel looks into the 'sky' of a perspective 'plane' (See Viewing Distant Horizons). This probably should have a completely different response to just a normal 'miss' of the source image.

The Interpolation setting will also handle the case that part of an image becomes 'stretched out' so that a single source pixel becomes smeared over a large area of the destination image. However the opposite is not handled very well by a simple interpolation method. And that requires other techniques we'll look at shortly.

Super Sampling, Improving Distortion Results

If part of the source image gets compressed into a much smaller area, the color of the destination image in that area should probably be a mix of a number source pixels, not just the nearest pixels to the lookup point. However only one single color lookup is performed by a simple reverse pixel mapping.

The result is a bit like using "-sample" instead of "-resize" in generating thumbnails. Thin lines become 'dotty' and edges start showing 'aliasing' or 'staircase' effects.

Currently the only solution to this to take a lot more color readings from the source image, so as to try to determine a more correct color for the destination image. The simplest technique is generally know as super-sampling, or over-sampling. See Wikipedia Entry on Super-Sampling.

Normally only one color lookup (sample) is taken from the source image for each destination pixel that is generated. But if the positions of neighbouring destination pixels when mapped into the source image are far apart (the source image is compressed into a smaller area), the individual pixels can start to look very different to each other, producing a 'pixelated' or almost random look.

By taking more samples from the source image for each destination pixel, the final color of the individual pixel will become a more accurate representation of distorted image at that point. The more color samples you make, the more accurate the final color will be, and the results produce a smoother more realistic look.

Remember this technique only really improves the look of the destination in areas where the source image becomes compressed by more than 50%. In areas where the distortion enlarges the source image, or keeps it about the same scale, a Interpolated Lookup of the source image look up will generally produce a good result.

In Imploding Images (above), I touched briefly on how you can use 'super-sampling' to improve the look of an image. I'll repeat those two examples here so you can see the difference.


  convert -size 94x94 xc:red -bordercolor white -border 3 \
          -virtual-pixel tile     -implode 4   implode_tiled_box.gif
  convert -size 94x94 xc:red -bordercolor white -border 3 \
          -virtual-pixel tile  -resize 400%  -implode 4 -resize 25% \
          implode_tiled_ss.gif
[IM Output]
Normal Implosion of a Box Image
[IM Output]
Super Sampled Implosion

This is the simplest way to super sample an image you plan on distorting. Increase the size of the image being distorted, distort it, then shrink the result.

A larger destination means the distortion does more lookups of the source image, and so creates more samples in a standard grid. A final resize then sharpens the whole result to produce a much higher quality distorted image. It is also a lot slower, but that is the trade-off.

Of course rather than enlarging the image, you could either generate a larger image, or apply it to a larger source image, before you do your final resize.

This is especially useful when rotating photos, and text, the source of which is usally much larger that the final result, and where the quality of the resulting image can be highly noticeable. For examples of this see the Polaroid Transform.

On final word of warning. Super-sampling is limited by the number of samples that was used for each pixel in the final image. That is the amount of scaling used in the final resize, determines the final 'quality' of the distorted image. Dividing the image size by 4 produces a much better result than only halving the distorted image, but it will also be 4 times slower.

In the extreme, super-sampling will not handle image distortions that involves infinities (such as in the center of an imploded image). In such cases a completely different technique is needed, one that is provided by Area Resampling (see below).

In summery, super-sampling can improve the look of images with only minor distortions, such as rotations, and shears. But as you will see below, it has limits to the types of distortions that it can improve.

Adaptive Sampling

The super-sampling technique can be expanded further. Rather than just using a fixed number of color lookups for each pixel, a check is made on either the distance between the lookups in the source image, or on the colors returned, to see if we should make more samples for that specific pixel.

That is the amount of super-sampling could be made responsive to needs of the distortion, without knowing anything about the specifics of the distortion itself. This is Adaptive Super-Sampling.

This technique is actually very common in Ray Tracers, where it is next to impossible to determine just how complex the resulting image is at specific points. In this case it is restricted to using 'color differences' to determine when more samples are needed.

IM does not currently support adaptive super-sampling at this time. Though it is now quite possible to add it as an alternative sampling method to use by the General Distortion Operator (see below).

Area Resampling, for better Distortions

The best alternative to super-sampling methods is Area Re-sampling.

Rather than distorting a larger image and averaging the results by resizing, Or just taking and averaging more samples from the image, we actually determine exactly how many pixels from the source image should be merged together (based on the 'scale' of the distortion at that point) to generate each specific output pixel. That is figure out the 'area' within the source image, each output pixel represents.

In fact this is exactly what the ImageMagick Resize Operator (a simpler form of image distortion) does to generate such good results. However for resize, you only need to calculate the scale and area needed to be sampled, once for the whole image.

When area re-sampling a distorted image, the area of pixel being generate covers will change with position. Some pixel may only need to merge a few source image colors, or even just one color, while another pixel elsewhere in the image may need to a very large number of pixels to generate the correct color.

Also the area that a destination pixel represents in the source image, may not be a simple square or circle, but may actually be a very weird awkward distorted shape, according to the distortion being used. Calculating and handling such awkward shapes can be very time consuming, or near impossible to achieve. As such it may be better to only approximation of the area of the source image needed.

For example here is a diagram showing how a round pixel in the final image needs to use the colors from a larger, elliptical area in the source image.
[IM Output]

Using an elliptical area of the source image to calculate colors for each destination pixel, is a method known as Elliptical Weighted Average (EWA) Re-sampling, and was outlined in the PDF research paper "Fundamentals of Texture Mapping and Image Warping" by Paul Heckbert. This was then used to define the new Generalized Distortion Operator (see next).

A simple ellipse may not be perfect for all distortions, but it works a lot better than simple pixel lookup, or a fixed scale super-sampling technique.

The results of this algorithm is especially good for extreme scale reductions such as produced by perspective distortions. For example here are all three re-sampling methods for an infinitely tiled perspective image. See Viewing Distant Horizons below for details.

  convert -size 90x90 pattern:checkerboard -normalize -fill none \
          -stroke gold -strokewidth 3 -draw 'rectangle 0,0 89,89' \
          checks.png

  convert checks.png -virtual-pixel tile -mattecolor DodgerBlue -filter point \
          -distort Perspective '0,0 20,60  90,0 70,63  0,90 5,83  90,90 85,88' \
          horizon_tile_point.png
  convert checks.png -resize 1000% \
          -virtual-pixel tile -mattecolor DodgerBlue -filter point \
          -distort Perspective \
                '0,0 200,600  900,0 700,630  0,900 50,830  900,900 850,880' \
          -resize 10%  horizon_tile_super.png
  convert checks.png  -virtual-pixel tile -mattecolor DodgerBlue \
          -distort Perspective '0,0 20,60  90,0 70,63  0,90 5,83  90,90 85,88' \
          horizon_tile.png
[IM Output]
Direct Reverse Pixel
Interpolated Lookup
[IM Output]
Super Sampling x10
[IM Output]
Elliptical Weighted Area
Resampled Image

The last image was generated using the default EWA settings of the Generalized Distortion Operator (see below). It took 4.3 seconds to generate. Which is rather reasonable.

The first image however is exactly the same, except that EWA resampling has been turned off by using a "-filter point" setting. This forces it to use Direct Interpolated Lookup for each pixel. As such this image was generated extremely fast in comparison (.49 seconds).

The middle image is like the first image but with the image being enlarged, and all the coordinate settings being multiplied by ten. That is more than 100 pixels were used to Super Sampling each destination pixel. It is quite fast to to generate (1.4 seconds), but does not produce any real improvement in quality. What improvement there is is actually restricted to a thin region in the middle ground of the image, and for this distortion, and image, that improvement is hardly noticeable.

The biggest difference between super-sampling and area-resampling, is that the former only does a general improvement in quality over the whole image. On the other hand area resampling concentrates more on the problem pixels closer to the horizon (where it spends most of its time), than on foreground pixels. For simpler distortions it is usually faster than super-sampling.

Now are you glad that I spent months adding Area Resampling to IM :-).


Generalized Distortion Operator

With the generation of these examples, the ensuing discussions in the IM Forums, and multiple requests from users for easier and faster ways to do perspective and other distortions, a new operator was added to IM v6.3.5-1 to allow us to more easily add new types of image distortions.

The General Distortion Mapping operator is called "-distort", and you can see what distortion methods it has available on your IM version using "-list" with a 'Distort' argument.

  convert -list distort

The "-distort" operator takes two arguments, one of the distortion methods as given by the above, and a second string argument consisting of comma or space separated floating point values.

The number floating point values given is however highly dependant on the distortion method being used, and their meanings also depend not only on the method chosen, but also can depend on the exact number of values given.

This is especially the case for the 'Scale_Rotate_Translate' (or 'SRT' for short) distortion, which really combines three separate 'Affine' distortions into a single distortion.

As discussed above in the Reversed Pixel Mapping, the resulting image (for magnification) is also effected by the Pixel Interpolation setting "-interpolate" to define how to lookup pixels from the source image, (especially in areas that become enlarged). For minification of the source image the Resize Filter settings controls the merging of pixel colors in the Area Resampling algorithm.

Finally the Virtual Pixel setting defines what the pixels surrounding the image should look like. while the color setting "-mattecolor" defining the color of pixels when the distortion mapping is undefined (for example the sky in a perspective distortion).

Phew. That is a lot of settings that you can use, but really you generally don't need all of them. Just define them as you need to.


By default "-distort" will usually distort the source image(s) into a image that is the same size as the original image. There are exceptions to this, such as the 'Arc' distortion (a polar mapping variant) where the input source image size really does not have much meaning in the distorted form of the image (see Arc Distortion below for details).

The other form of the operator, "+distort" (Added to IM v6.3.5-7), will resize the distorted image so it will contain the whole of the input image, much like what the Rotate and Shearing operators do.

However this particular 'mode' of operation also goes further an also sets the Virtual Canvas Offset (page) of the resulting image. This way if you later Flatten this image onto another image the position of your control points, and origin will still be in the correct position, even though the positions within the actual image itself many not be as you would expect.

Also (depending on the distortion method) a "+distort" will attempt to take into account any existing Virtual Canvas Offset that may be present in the source image, in the distortion process.

As such you may need to make judicious use of the "-repage" attribute setting operator to clear or adjust that offset when using the 'best-fit' "+distort" form of the General Distortion Operator, if these offsets are not wanted, or you don't want it to effect the outcome of the distortion operation. See also Removing Canvas/Page Geometry.

The "-distort" will ignore any existing offset present in the source image in terms of the distortion itself, but will copy that offset unchanged to the distorted image.

In Summery... Use "-distort" to have results mapped into an image the same size. And use "+distort" to size the output to best-fit the distorted image, BUT also use and generate Virtual Canvas Offsets (page attributes).

There is one final special option. As of IM v6.3.6-1 you can specify the setting
-set 'option:distort:viewport' WxH+X+Y
which will set the size and location of the resulting image in the distorted image space. This can be used to enlarge the destination image to a specific size, or shift it to a specific offset. This setting will override the normal output size handling of the "-distort" operator.

Well that is enough about the operator, lets look at some of the specific distortions that it provides. Here is where the fun really begins...


Scale-Rotate-Translate (SRT) Distortion

The simplest distortion, but with probably the most versatile, is the 'SRT or 'Scale-Rotate-Translate' distortion. (SRT is just a quick short-hand)

This distortion is actually three separate, distortions in a single distortion method. All arguments except the angle rotation, are optional, and this makes the argument meaning highly variable in meaning, depending on exactly how many comma separated arguments you give, up to the maximum of 7 floating point numbers.

-distort SRT " 
                   Angle 
 "   -> centered rotate
        Scale     Angle
  -> centered scale and rotate
X,Y               Angle 
  -> rotate about given coordinate
X,Y     Scale     Angle 
  -> scale and rotate about coordinate
X,Y ScaleX,ScaleY Angle 
  -> ditto
X,Y     Scale     Angle  NewX,NewY
  -> scale, rotate and translate coord
X,Y ScaleX,ScaleY Angle  NewX,NewY
  -> ditto

What this does is take an image in which you have selected a (optional) control point. If no control point is given, the center of the input source image is used. Around that point the distortion will, in sequence... Scale the image, Rotate it, then Translate or move the selected control point to a new position. Hence the name of this distortion.

For example lets take our koala image, and just simply rotate it, in a similar way to the Rotate operator...

  convert koala.gif  -background skyblue  -virtual-pixel background \
          -distort ScaleRotateTranslate -110 koala_distort_rotate.png
[IM Output]

Using the 'plus' form of "+distort", and a clean up of virtual offsets, we can make it exactly like the Rotate operator, but with better results.

  convert koala.gif  -background skyblue  -virtual-pixel background \
          +distort ScaleRotateTranslate -110 +repage koala_distort_rotate2.png
[IM Output]

Lets shrink it by 30% as well, but use a transparent background.

  convert koala.gif  -matte -virtual-pixel transparent \
          +distort ScaleRotateTranslate '.7,-110'  koala_distort_scale.png
[IM Output]

The next set of arguments will specify the 'center' around which the image is rotated and scaled. This point is called a 'control point' or 'handle' in the image which is a location used to control the distortion. As we are using a specific point for this distortion, lets not use the 'best-fit' mode to avoid the complications of 'virtual offsets'.

For example lets rotate and scale the koala around its 'nose', which is located at 28,24 in the source image. While we are at it lets distort the X and Y scales different.

  convert koala.gif  -background skyblue -virtual-pixel background \
          -distort ScaleRotateTranslate '28,24  .4,.8  -110' \
          koala_distort_center.png
[IM Output]

And as a final example, lets also move the 'nose' to near the bottom of the image, and set background to a matching white background.

  convert koala.gif  -virtual-pixel white \
          -distort ScaleRotateTranslate '28,24  .4,.8  -110  37.5,60' \
          koala_distort_trans.png
[IM Output]

Note that the final position is also a floating point value. In fact all the arguments can be floating point values and the distortion will do the right thing.

As you can see this distortion is very versatile, and while you can think of it as distorting the image using three different methods in sequence, in reality it is only distorting the image one single time to produce the shown result. This makes it faster than doing multiple individual operators, and generally produces a better final result.

The above also demonstrates the use of different Virtual Pixel settings to define the color used for the areas referenced outside the actual source image. To see the effect of Interpolation on rotations see Interpolation with Affine Rotates.

This distortion specifically designed to take an image of some known object and generate an animation based on the movements and rotation of that object.

For example here I create a stylized space ship, which I then animate in a very rough way. The ship sits on its base at 20,75 (for the initial 'hunker-down' scaling) while the normal 'handle' for movement and rotations is the ships center which is located at 20,60 in the original image. These points represent control points by which the object can then be animated in simple user friendly terms.

  convert -size 80x80 xc:skyblue -fill yellow -stroke black \
          -draw 'path "M 15,75 20,45 25,75 Z  M 10,55 30,55" ' \
          spaceship.gif
  convert spaceship.gif  -virtual-pixel background \
          \( -clone 0  -distort SRT '20,75  1.0,0.6  0' \) \
          \( -clone 0  -distort SRT '20,60     1     0  20.5,49.5' \) \
          \( -clone 0  -distort SRT '20,60    0.9   20  27,35' \) \
          \( -clone 0  -distort SRT '20,60    0.8   45  40,23' \) \
          \( -clone 0  -distort SRT '20,60    0.5   70  55,15' \) \
          \( -clone 0  -distort SRT '20,60    0.3   75  72,11' \) \
          \( -clone 0  -distort SRT '20,60    0.1   80  100,8' \) \
          -set delay 50  -loop 0  spaceship_launch.gif
[IM Output] ==> [IM Output]

Of course it is a very rough example of how you can use a 'SRT' distortion to animated a static image, but you should get the idea. You can add more frames, and perhaps some flames and smoke to improve it further (submissions welcome and best result will be added here with your name).

Under Construction

Experiment: use a interpolated filter for pixel resampling, rather than the default EWA filter (which is best for extreme scales).

  convert spaceship.gif  -virtual-pixel background \
          -filter point -interpolate mesh \
          \( -clone 0  -distort SRT '20,75  1.0,0.6  0' \) \
          \( -clone 0  -distort SRT '20,60     1     0  20.5,49.5' \) \
          \( -clone 0  -distort SRT '20,60    0.9   20  27,35' \) \
          \( -clone 0  -distort SRT '20,60    0.8   45  40,23' \) \
          \( -clone 0  -distort SRT '20,60    0.5   70  55,15' \) \
          \( -clone 0  -distort SRT '20,60    0.3   75  72,11' \) \
          \( -clone 0  -distort SRT '20,60    0.1   80  100,8' \) \
          -set delay 50  -loop 0  spaceship_launch2.gif
[IM Output] ==> [IM Output]

Note that while a interpolated 'point' lookup removed the blur in the initial small scale changes, it causes a pixelated look in the last couple of frames (with high minimization), which is where a EWA filter works much better. This is a known problem and will be fixed, when I next get back into a coding cycle.

Affine Distortion (a three point distort)

The previous 'SRT' distortion method, actually reproduces a general distortion known as a 'affine' or linear space transformation. However the above can not reproduce all the effects of a true affine distortion, as it is designed to avoid generating 'shear' distortions. (See Shearing Images above).

To make full use of an affine image transformation, the 'Affine' distortion method is defined in terms of the mapping of 3 control points. This is defined in terms of sets of coordinate pairs, the old pair then the new pair, of four values each. Three sets of 4 values makes a total of 12 values. For example...
-distort Affine 'X1,Y1 I1,J1, X2,Y2 I2,J2 X3,Y3 I3,J3'
With the above the coordinate X1,Y1 in the source image will be mapped to the position I1,J1 in the destination image. Simularly for the next two control points. Remember you can use either commas or spaces to seperate the values given.

All the distortions which are defined in terms of a set of control points define the pairs of coodinates in this way. That includes not only 'Affine', but also 'Perspective' and 'BiLinear' distortions.

Before IM version 6.3.6-0 when the "-distort" operator was first interoduced, the corrdinate ordering was defines as all the source coordinates, followed by all the destination coordinates. This however make it hard to determine which source and destination coordines corresponded to each other.

The change in ordering also allowed for the use of more than a minimal number of control points for least squares fiting of the distortion to the control points. That intern permitted the use of future 'image registration' techniques for automatic determination of control points.

Finally the new system will also allow for the future reading of control points directly from a file with one control point pair per line.

Another way you can think of this is the mapping of three corners of a triangle.
FUTURE: Image with a obvious triangle of control points.
Alternativally you can thing of the first coordinate mapping as a 'origin' with the other two coordinate mappings as vectors from that origin. For example here I draw some text, and overlay a red and blue 'vector' to define the three control points to distort the image with.

  convert -background lightblue -fill Gray -font Candice \
      -size 100x100 -gravity center label:Affine\! \
      -draw 'fill blue stroke blue path "M 2,60 32,60 M 27,58 27,62 32,60 Z"' \
      -draw 'fill red  stroke red  path "M 2,60  2,30 M  0,35  4,35  2,30 Z"' \
      label_axis.png
  convert label_axis.png  -virtual-pixel background \
          -distort Affine '2,60 2,60     32,60 32,60    2,30 17,35' \
          label_axis_distort_shear.png
  convert label_axis.png  -virtual-pixel background \
          -distort Affine '2,60 2,60     32,60,27,85    2,30 27,35' \
          label_axis_distort_rotate.png
  convert label_axis.png  -virtual-pixel background \
          -distort Affine '2,60 30,50    32,60 60,80    2,30 30,5' \
          label_axis_distort_affine.png
[IM Output] ==> [IM Output] [IM Output] [IM Output]

In the first example only the third coordinate (for the red vector) was modified causing the image to be sheared. Later examples make more radical changes to the image, including scaling, and rotations.

Of course the Annotate Text operator can also skew actual text in this same way more directly (also see Annotate Argument Usage), but an Affine distortion can do this for any image, not just text.

Affine Matrix Distortion

Under Construction

Using a raw affine matrix for the distortion
FUTURE
For now see the old Affine Matrix Examples that uses the "-affine" and "-transform" operational pair for distorting images.

FUTURE: Look at +distort 'BestFit' and offset overlaying.

Affine Tiling

All three affine-like distortion methods we have looked at so far, also provides interesting ways to generate various tiling patterns, based on a distorted image.

For this example I created a special checkerboard image, with a extra border to show the images normal bounds, when tiled.

  convert -size 90x90 pattern:checkerboard -normalize -fill none \
          -stroke gold -strokewidth 3 -draw 'rectangle 0,0 89,89' \
          checks.png

  convert checks.png    -matte    -virtual-pixel tile \
          -distort  ScaleRotateTranslate  '20,20  .5  30' \
          checks_srt_tile.png
  convert checks.png    -matte    -virtual-pixel tile \
          -distort  Affine  '0,0 10,10   0,89 10,50   89,0 50,0' \
          checks_affine_tile.png
  convert checks.png    -matte    -virtual-pixel tile \
          -distort  AffineProjection  '0.9,0.3,-0.2,0.7,20,15' \
          checks_amatrix_tile.png
[IM Output] ==> [IM Output] [IM Output] [IM Output]

Using a distortion mapping in this way is actually how 'texture mapping' works in 3D graphic libraries and games. The only difference is that the distortions are 3 dimensional coordinate mapping of surfaces, back to a two dimensional image.

FUTURE: specifying alternative output image sizes or 'viewports'.

Perspective Distortion (a four point distort)

This is probably the most common requested type of distortion at the time of this operators creation has been for a fast perspective distortion operation. This is an implementation of a linear trapezoidal or keystone distortion, and works by asking IM to move as set of four image coordinates from one position to another position.

For example, here I have a image building. From this image I manually discovered the location of 4 points (red). I also defined the final location to which I those points transformed to in the final image (blue), so as to 'straighten' or 'rectify' the face of the building.

  convert building.jpg \
          -draw 'fill none stroke red polygon 7,40 4,124, 85,122, 85,2' \
          building_before.jpg
  convert building.jpg \
          -draw 'fill none stroke blue polygon 4,30 4,123, 100,123, 100,30' \
          building_after.jpg
[IM Output] ==> [IM Output] [IM Output]

The result is 2 sets of 4 pairs of image coordinates, a total of 16 numbers. these are then re-ordered into 4 sets of mapping pairs, to produce the arguments needed by the 'perspective' distortion method (source coordinates is given first).

To do the actual image distortion, you only need to feed those coordinates into the 'perspective' method of "-distort".

  convert building.jpg -matte -virtual-pixel transparent \
         -distort Perspective \
              '7,40 4,30   4,124 4,123   85,122 100,123   85,2 100,30' \
          building_pers.png
[IM Output] ==> [IM Output]

Notice the blank area on the top right, where the distortion 'missed' the pixel data in the source image. What IM does in this situation is controlled by the "-virtual-pixel" setting (see Virtual Pixel).

What is less noticeable is that a small amount of the left-most edge of the original image is also 'lost' as the 'transform' would place outside the new image.

As a matter of interest lets also reverse the distortion, by swaping the coordinates of each mapping pair. This lets us see just how much of the image is degraded by the distortion.

  convert building_pers.png  -matte -virtual-pixel transparent \
         -distort Perspective \
              '4,30 7,40   4,123 4,124   100,123 85,122   100,30 85,2' \
          building_pers_rev.png
[IM Output] ==> [IM Output] ==> [IM Output]

Not bad. A lot of 'fuzziness' is present, but that can't be helped. Notice that the 'fuzziness' is worse on the right side of the image where it was compressed the most. All distorts suffer from this compression problem, as such you should alway try to distort from an original image, rather than distorting an already distorted image.

Internally the given coordinates (16 numbers) is converted into a mathematical expression which maps a coordinate in the destination image (which is the same size as the source image) to the source image. This in turn lets us look up the colors to place on the destination image. See Reverse Pixel Mapping above.

Here is another example, of using this transform, using the special checkerboard test image we created above, which we distort then reverse the distortion.

  convert checks.png        -matte    -virtual-pixel transparent \
          -distort Perspective '0,0,0,0  0,90,0,90  90,0,90,25  90,90,90,65' \
          checks_pers.png
  convert checks_pers.png   -matte    -virtual-pixel transparent \
          -distort Perspective '0,0,0,0  0,90,0,90  90,25,90,0  90,65,90,90' \
          checks_pers_rev.png
[IM Output] ==> [IM Output] ==> [IM Output]

You can see the slight fuzziness caused by the distortion, but the image is basically restored.

FUTURE: Alternative.  Coordinates represents a triangle and center point.
You can fix the triangle and move the center point, or fix that center and
move the other three coordinates, to generate the perspective view.

Good Example needed.
If you like to see more detail in what IM actually does and the mathematics involved see DIY Perspective Distortion. You can also see a Postscript implementation that was presented in a PDF paper Perspective Rectification, by Gernot Hoffmann. Also have a look at Leptonica Affine and Perspective Transforms.

Viewing Distant Horizons

You can produce some very unusual effects using Perspective Distortions if you adjust the coordinates to produce a 'vanishing point' within the boundaries of the image.


  convert checks.png -mattecolor DodgerBlue \
          -virtual-pixel background -background Green \
          -distort Perspective '0,0 20,60  90,0 70,63  0,90 5,83  90,90 85,88' \
          checks_horizon.png
[IM Output]

Well we used 'green' for the surrounding virtual pixels of this image, which we enabled using Virtual Pixel Background Settings. But what is more interesting is the appearence of the 'blue' color that was defined using the "-mattecolor" setting.

This 'blue' color represents an area where the pixels generated by the distortion is invalid, and in such areas the "-distort" operator will just output the "-mattecolor" setting.

For a Perspective Distortion, any pixel ending up in the 'sky' of the resulting image will be classed as invalid. Also it defines the 'sky' as being the side of the 'horizon' on which the source image will not appear. It will only appear when images are highly foreshortened by the distortion.

If you don't want a 'sky' in your final image result then the best idea is to set both "-background" and "-mattecolor" to use the same color.

The Perspective Distortion gets more interesting when one of the special infinite tiling Virtual Pixel settings are used. For example here we used a 'tile' setting to generate a infiniteally tiled plane.

  convert checks.png  -virtual-pixel tile -mattecolor DodgerBlue \
          -distort Perspective '0,0 20,60  90,0 70,63  0,90 5,83  90,90 85,88' \
          horizon_tile.png
[IM Output]

A word of warning about this image. Asking for an infinitely tiled image is very very slow to generate. The larger the image the slower it gets. You can monitor the progress of the "-distort" (or any other slow image processing task) using the "-monitor" Operational Control Setting.

Basically for a single pixel that is close to the horizon, ImageMagick will need to average a huge number of pixels from the original image to figure out the appropriate color. This can take a very long time. ImageMagick does try to limit the amount of time it uses to handle these near-horizon pixels, but it can still take a long time.

For more deatils of this method see Area Resampling above.

Another infinitely tiled perspective image can be generated by using a Random Virtual Pixel Setting...

  convert checks.png  -virtual-pixel random -mattecolor DodgerBlue \
          -distort Perspective '0,0 20,60  90,0 70,63  0,90 5,83  90,90 85,88' \
          horizon_random.png
[IM Output]

What is happening is that all virtual pixels surrounding the image are just random picks of any pixel within the image itself. The result is a ground consisting of random noise that gets smoother and more blurred as you look toward the horizon of the image. It gives a natural feeling of depth, without any specific repeating pattern.

Here I repeated the above but with a pure black and white source image. However I am not interested in the actual distorted image, only the Virtual Pixel 'random' pattern that was generated, so I changed the what part of the 'distorted image space' I am looking at using a special 'distort:viewport' setting. This setting overrides the normal size and location of the area of distorted space being viewed.


  convert -size 90x90 pattern:gray50 -matte \
       -virtual-pixel random -mattecolor none \
       -set option:distort:viewport 120x120+100-15 \
       -distort Perspective '0,0 20,60  90,0 70,63  0,90 5,83  90,90 85,88' \
       +repage -size 120x50 gradient:dodgerblue-tomato \
       -compose DstOver -composite    sunset_horizon.png
[IM Output]

To complete the image I removed the viewport offset (using "+repage" ), and Underlaid a gradient of sunset colors into the transparent 'sky' (set using "-mattecolor") .

A very interesting image that could be used as a backdrop for some other image processing work. You can adjust the distortion parameters to adjust the height and slope of the horizon.

Here is a more traditional test of a tiled perspective distortion.

  convert pattern:checkerboard -scale 120x120 -normalize \
          -virtual-pixel tile  -distort Perspective \
             '0,0 10,61   119,0 60,60   0,119 5,114   119,119 125,110' \
          checkered_plain.gif
[IM Output]

In my studies I found the above test to be misleading, as it give no real indication of the quality of the area resampling technique for near unity scales of an image. That is problems such as described in Resize Artifacts.


Arc Distortion (curving images into circular arcs)

The 'Arc' distortion (as of IM v6.3.5-5) is a simple variation of a much more complex, polar distortion (still to be added).

By default it will curve the given image into a perfectly circular arc over angle given, and without other arguments it will try to preserve the scaling of horizontal center-line of the image, and the aspect ratio of the image as much as possible.

To do this it takes up to four arguments.
arc_angle rotate top_radius bottom_radius
However only the arc_angle is required, the other arguments are optional, and can be added as needed, in the sequence given.

For example 'Arc' an image over an angle of 60 degrees...

  convert rose:  -virtual-pixel white -distort arc 60  arc_rose.jpg
[IM Output]

Note that unlike the other image distortion operators, an 'Arc' distort will always set the size of the resulting image so that the complete source image is present. This includes any anti-aliasing edge pixels. As such the resulting image will rarely match the size of the input image.

Adding a second argument allows you to rotate the image around the circle. For example make the right edge horizontal by rotating it 60 degrees.

  convert rose:  -virtual-pixel white -distort arc '60 60'  arc_rose_rot.jpg
[IM Output]

As no specific radius argument has be mentioned, the 'Arc' distortion method takes great pains to try to ensure the image is scaled as minimally as possible. To do this the horizontal center line of the image is set to the ideal radius for the width of the source image.

This means that if you arc the image over a larger angle, the radius of the centerline used will also shrink by the same factor. As such the radius of the center-line will be smaller and tighter.

  convert rose:  -virtual-pixel white -distort arc 120  arc_rose_3.jpg
[IM Output]

Note how the image will now fit into a smaller circle, but that the bottom edge of the image is an even smaller circle still!

If you set an even larger angle over which to arc the image, the bottom edge will hit the center of the distortion, and beyond, which results in it disappearing into oblivion.

  convert rose: -virtual-pixel white -distort arc 60   arc_rose_1.jpg
  convert rose: -virtual-pixel white -distort arc 90   arc_rose_2.jpg
  convert rose: -virtual-pixel white -distort arc 120  arc_rose_3.jpg
  convert rose: -virtual-pixel white -distort arc 180  arc_rose_4.jpg
  convert rose: -virtual-pixel white -distort arc 240  arc_rose_5.jpg
  convert rose: -virtual-pixel white -distort arc 300  arc_rose_6.jpg
  convert rose: -virtual-pixel white -distort arc 360  arc_rose_7.jpg
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

Longer images 'Arc' distort a lot better over very large angles. For example you can wrap long images (like text messages) into rings. And just so you can truly see what is happening here I set a different Virtual Pixel background color, so you can see the boundary of the original image.

  convert -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel background  -background SkyBlue \
          -distort arc 60     arc_circle_1.jpg
  convert -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel background  -background SkyBlue \
          -distort arc 120    arc_circle_2.jpg
  convert -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel background  -background SkyBlue \
          -distort arc 180    arc_circle_3.jpg
  convert -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel background  -background SkyBlue \
          -distort arc 270    arc_circle_4.jpg
  convert -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel background  -background SkyBlue \
          -distort arc 360    arc_circle_5.jpg
[IM Output] [IM Output] [IM Output] [IM Output] [IM Output]

And hey presto we have 'arc'ed the label image into a full circle.

If you look closely at the join of the full circle image you may see a small line of pixels, where the join is not quite complete. This is caused by the effect of the surrounding white Virtual Pixel background.

The simplest solution to prevent the background color 'leaking' into the join like this is to add a very very slight overlap in the joined image.

  convert -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel background -background SkyBlue \
          -distort arc 362   arc_circle.jpg
[IM Output]

Overlapping the sides of the image like this however will 'chop' a few pixels from the image where they join. It will also may cause a very sharp color change along that same 'join' line. Well look at other ways to fix by adjusting the Virtual Pixel setting later.

If before 'arc'ing an image you rotate the input image upside-down, you can place the original 'top' of the image on the inside edge of the circle. Of course you may like to 'rotate' the result back to normal again afterward, but that capability is already built into the 'Arc' distortion method.

  convert -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel background -background SkyBlue \
          -rotate 180   -distort arc '270 180'  arc_flip.jpg
[IM Output]

The third argument will override the 'ideal' radius for the top of the image. This has the effect of 'fitting' the distorted image so it exactly fits a circle of the radius you give.

  convert -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel background -background SkyBlue \
          -distort arc '362 0 50'  arc_radius.jpg
[IM Output]

Note how the whole image was enlarged to match the new radius. This preserves the original images aspect ratio (height to width relation) as much as possible.

However if you provide the fourth "bottom edge radius" argument, you can get complete control of the radial 'height' of the ring generated, and distort the radial scaling of the image, separate to the 'arc width' or angle.

  convert -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel background -background SkyBlue \
          -distort arc '362 0 45 30'   arc_inner.jpg
[IM Output]

You can even force it to completely fill the inside of the circle.

  convert -font Candice -pointsize 20 label:' Around the World ' \
          -virtual-pixel background -background SkyBlue \
          -distort arc '362 0 45 -1'   arc_fill.jpg
[IM Output]

Not however that the join will always reappear near the center of an image like this, no matter how big an overlay you use. To fix this you need to chnage the Virtual Pixel setting to 'tile' (see below).

You can also try to generate interesting effects, for example arcing a long checkerboard pattern into the ring produces...

  convert -size 210x30 pattern:checkerboard -matte \
          -virtual-pixel background -background none \
          -distort arc 360   arc_checks.png
[IM Output]

By using the default 'Edge' Virtual Pixel setting you can produce a more interesting effect. This also solves the problem of joining up a 360 degree circle, without resorting to a slight overlap.

  convert -size 210x30 pattern:checkerboard  -virtual-pixel edge \
          -distort arc 360   arc_checks_edge.png
[IM Output]

If you look carefully at the last two images, you may notice that the the line from the center directly downward is very sharp when compared to the other radial lines in the image, such as the one going from the center upward. This sharp/fuzzy behaviour is especially apparent near the extreme outside edge.

This sharp change is caused by the color continuing beyond the arc limits, without any chance for color interpolation. It is the wrap around point and it is not handled very will by the 'Arc' distortion.

However if you use a Virtual Pixel setting of 'tile', then the neighbouring color at the wrapping edge also happens at the right point for the source image pixel lookup. This results in a proper interpolated color lookup at the join and a perfect 360 circle.

Of course tile also has 'radial' effects too, forming a interesting circular checkerboard pattern.