ImageMagick v6 Examples --
Multi-Image Layers

Index
ImageMagick Examples Preface and Index
Layers Introduction
Appending Images (-append)
Composition of Multiple Pairs of Images
Layering Multiple Images
Evaluate Sequence Multi-Image Merging
Mean (average)Max/Min ValueMedian Pixel,   AddMultiply

Layering Image Examples
Overlaying multiple images onto each other to generate a larger 'composite' is generally known as using image 'layering'. These examples involve the combining of multiple 'layers' of images to produce the final larger more complex image.


Layering Images Introduction

As we have previously noted, ImageMagick does not deal with just one image, but a sequence or list of images. This allows you to use IM in two very special image processing techniques.

You can for example think of each image in the list as a single frame in time, so that the whole list can be regarded as being a Animation. This will be explored in other IM Example Pages. See Animation Basics.

Alternatively, you can think of each image in the sequence as Layers of a set of see-through overhead transparencies. That is, each image represents a small part of the final image. For example: the first (lowest) layer can represent a background image. Above that you can have a fuzzy see though shadow. Then the next layer image contains the object that casts that shadow. On top of this a layer with some text that is written over that object.

That is you can have a sequence of images or 'layers' that each adds on more piece to a final much more complex image. Each image layer can be moved, edited, or modified completely separately from any other layer, and even saved into a multi-image file (such as TIFF:, MIFF: or XCF:) or as separate images, for future processing. And that is the point of image layering.

Only when all the image layers have been created do you Flatten, Mosaic, or Merge all the Layered Images into a single final image.


Appending Images

Appending is probably the simplest, of the multi-image operations provided to handle multiple images.

Basically it joins the current sequence of images in memory into a column, or a row, without gaps. No form of justification such as centering is (currently) provided, so images are aligned either along their left, or top edges, as appropriate. The "-append" option appends vertically, while the plus form "+append" appends horizontally.

For example here we append a set of letter images together, side-by-side, to form a fancy word, in a similar way that fonts letters are joined together.

  convert font_A.gif font_P.gif font_P.gif font_E.gif font_N.gif \
          font_D.gif font_E.gif font_D.gif +append  append_row.gif
[IM Output]

The above is similar (in a very basic way) to how fonts are handled. Unlike real fonts you are not limited to just two colors, but can generate some very fancy colorful alphabets from individual character images. Many of these 'image fonts' are available on the WWW for download. A very small set can be found in Anthony's Icon Library, in Fonts for Text and Counters, which is also where I found the above Blue Bubble Font.

Note also how the "+append" operator was done last, on the command line, after all the images that you want to append have been added to the current image sequence.

This is great for appending a label to an image, for example...

  convert rose:  -background LawnGreen label:Rose \
          -background white  -append append_label.jpg
[IM Output]

Note that the "-background" color was used to fill in any space that was not filled in. Of course if the all the images are the same width, no space will be left for this fill.

From IM v6.4.7-1 the "-gravity" setting can be used to specify how the images should be added together. As such in a vertical append, a setting of 'Center' will center the image relative to the final resulting image (so will a setting of either 'North' or 'South' though they will have the same effect.


  convert rose:  -background LawnGreen label:Rose \
          -background white -gravity center -append \
          append_center.jpg
[IM Output]

Naturally any 'East' gravity setting will align the images on the right side.

  convert rose:  -background LawnGreen label:Rose \
          -background white -gravity east -append \
          append_east.jpg
[IM Output]

Similar vertical alignment can be achieved when using "+append"

Before IM v6.4.7 it was much more difficult to align appended images, and generally involved using a "-flop" for right alignment. Or using "-extent" or "-border" to adjust the image width for centered aligned appends.

For example, this will work with an older 6.3.2 version of IM...

  convert rose:  -background SkyBlue label:Rose \
          -background White -gravity center -extent 200x \
          -append -trim +repage   append_center_old.jpg
[IM Output]

You can also use multiple append operations, in the same command without conflict or confusion as to the outcome of the operations (which was not the case before IM v6).

  convert font_{0,0,6,1,2}.gif +append  dragon_long.gif \
          -background none   -append   append_multi.gif
[IM Output]

We appended each row of images together, then appende a larger image below that. This is very simple, and straight-forward.

By using parenthesis, you can append just the numbers after the larger image. For example, here append all the numbers together, before appending them vertically to the dragon image we read in before the numbers.

  convert dragon_long.gif  '(' font_{0,0,6,2,9}.gif +append ')' \
          -background none   -append   append_parenthesis.gif
[IM Output]

The parenthesis in the above must be either quoted, or escaped with a backslashed ('\') when used with a UNIX shell, otherwise they will be interpreted by the shell as something completely different.

As only two images were involved we could have just added a "+swap" or "-reverse" instead of using parenthesis.

You can take this further to make a whole array of images, and build them either by rows, or by columns.

  convert \( font_1.gif font_2.gif font_3.gif +append \) \
          \( font_4.gif font_5.gif font_6.gif +append \) \
          \( font_7.gif font_8.gif font_9.gif +append \) \
          \( -size 32x32 xc:none  font_0.gif +append \) \
          -background none -append   append_array.gif
[IM Output]

Technically the first set of parenthesis is not needed, as no images have been read in yet, but it makes the whole thing look uniform and shows the intent of the command, in making an array of images.

See also Montage Concatenation Mode, for an alternative way of creating arrays of equal sized images.

The "-append" operator will only append the actual images, and does not make use the virtual canvas (image page) size of offset. However the virtual canvas information seems to be left in a funny state with the canvas sizes being added together and the offset set to some undefined value.

This may be regarded as a bug, and means either the input images or result should have the virtual canvas reset using "+repage", before saving, or using the image in operations where this information can become important.

This situation will probably be fixed in some future expansion of the operation. Caution is thus advised, especially if re-appending Tile Cropped images.


Composition of Multiple Paits of Images

Compostion is the low-level operation that is used to merge two individual images together. Almost all layering techniques eventaully devolve down to merging images together two at a time, until only one image is left.

So lets start bby looking at ways of doing low-level composition of image pairs.

Using the Composite Command

The traditional method of combining two images together using ImageMagick is though the "composite" command. This command can only combine only two images at a time, saving the results of each operation into a file. This of course does not stop you from using it to layer multiple images, one image at a time...

  convert -size 100x100 xc:skyblue composite.gif
  composite -geometry  +5+10 balloon.gif composite.gif composite.gif
  composite -geometry +35+30 medical.gif composite.gif composite.gif
  composite -geometry +62+50 present.gif composite.gif composite.gif
  composite -geometry +10+55 shading.gif composite.gif composite.gif
[IM Output]

As all input images are read in by ImageMagick BEFORE the output image is opened, you can output to one of the input images. This allows you to work on the same image over and over, as shown above, without problems.

Do not do this with a lossy image format like "JPEG" as the format errors are accumulative, and the base image will quickly degrade.

You can also resize the overlaid image as well as position it using the "-geometry" setting.

  convert -size 100x100 xc:skyblue comp_resize.gif
  composite -geometry 40x40+5+10  balloon.gif comp_resize.gif comp_resize.gif
  composite -geometry      +35+30 medical.gif comp_resize.gif comp_resize.gif
  composite -geometry 24x24+62+50 present.gif comp_resize.gif comp_resize.gif
  composite -geometry 16x16+10+55 shading.gif comp_resize.gif comp_resize.gif
[IM Output]

The "composite" command also has a few other advantages in that you can use to control the way the image is drawn onto the background with the "-compose" option and its relative position is effected by the "-gravity" setting.

You can also "-tile" the overlay so that it will just cover the background image, without needing to specify tile limits. This is something only available when using "composite".

The big disadvantage with this method is that you are using multiple commands, and IM has to write-out the working image, either to a pipeline, or to disk, for the next command to read-in again.

To find more examples of using the "composite" command, to overlay images on top of other images, see "Annotating by Overlaying Images" and "Image Positioning using Gravity".

Composite Operator of Convert

The "-composite" operator is available within the "convert" command. For more details see Convert -composite Operator. This allows you to do the same as the above, but all in one command.

  convert -size 100x100 xc:skyblue \
          balloon.gif  -geometry  +5+10  -composite \
          medical.gif  -geometry +35+30  -composite \
          present.gif  -geometry +62+50  -composite \
          shading.gif  -geometry +10+55  -composite \
          compose.gif
[IM Output]

This first creates a Canvas Image which is "skyblue" in color, and then layers each of the later images onto that canvas at the given locations.

Now the "-geometry" is is a very special operator that not only sets an overlay position for the next "-composite" operation, it also "-resize" the last image (and only the last image) in the current image sequence.


  convert -size 100x100 xc:skyblue \
          balloon.gif  -geometry 40x40+5+10   -composite \
          medical.gif  -geometry      +35+30  -composite \
          present.gif  -geometry 24x24+62+50  -composite \
          shading.gif  -geometry 16x16+10+55  -composite \
          compose_resize.gif
[IM Output]

There are of course features in "composite", not available in any form of "convert" image overlaying. See the composite command summary.

Image positions are effected by "-gravity" for their relative placement, allowing you to position images relative to the center, or bottom or right edges of the image. However is not the case for the next set of image overlay options, which only allows absolute placement.

Draw Multiple Images

Also using "convert" you can also use Draw Primitives to overlay images onto its working canvas.

  convert -size 100x100 xc:skyblue \
          -draw "image over  5,10 0,0 'balloon.gif'" \
          -draw "image over 35,30 0,0 'medical.gif'" \
          -draw "image over 62,50 0,0 'present.gif'" \
          -draw "image over 10,55 0,0 'shading.gif'" \
          drawn.gif
[IM Output]

You can of course also specify a resize for the overlaid image too..

  convert -size 100x100 xc:skyblue \
          -draw "image over  5,10 40,40 'balloon.gif'" \
          -draw "image over 35,30  0,0  'medical.gif'" \
          -draw "image over 62,50 24,24 'present.gif'" \
          -draw "image over 10,55 16,16 'shading.gif'" \
          drawn_resize.gif
[IM Output]

The 'drawn' images can also be Rotated, Scaled, and Affine Distorted during the overlay process. Though that can be tricky to get working the way you want.

Drawn images are "-gravity" effected, just like text. But this is NOT true in the previous IM version 5.5.7.   See examples of this in "Image Positioning using Gravity".


Layering Multiple Images

True layering of images requires methods to combine multiple images together, without needing to individually compose each pair of images separtally. This is where the various -layers operator methods come into ther own.

Ordering of layered images can be important, so it is a good idea to understand teh special Image Sequence or List Operators.

Note that 'layered images' is practically identical to the handling 'animated frames'. As such it is recommended you also look at both Animation Basics and Animation Modifications for techniques involving processing individual 'layers' or 'frames'. Actually animations often use the same -layers operator for processing images.

Flatten - onto a Background Image

The "-layers flatten" image list operator, (or its shortcut "-flatten") will basically "Compose" each of the given images on to a background to form one single image. However the image positions are specified using their current Virtual Canvas, or Page offset.

For example, here I create a nice canvas, and specify each of the images I want to overlay onto that canvas.

  convert -size 100x100 xc:skyblue \
          -fill dodgerblue -draw 'circle 50,50 15,25' \
          -page +5+10  balloon.gif   -page +35+30 medical.gif  \
          -page +62+50 present.gif   -page +10+55 shading.gif  \
          -layers flatten  flatten_canvas.gif
[IM Output]

As of IM v6.3.6-2 the "-flatten" operator is only an alias for a "-layers 'flatten'" method.

Thus the "-flatten" option can be regarded as a short cut for the "-layers" method of the same name.

You don't need to create an initial canvas as we did above, you can instead let "-flatten" create one for you. The canvas color will be the current "-background" color, while its size is defined by the first images Virtual Canvas size.

  convert -page 100x100+5+10  balloon.gif   -page +35+30 medical.gif  \
          -page +62+50        present.gif   -page +10+55 shading.gif  \
          -background dodgerblue  -layers flatten  flatten_page.gif
[IM Output]

While the "-gravity" setting will effect image placement defined using "-geometry" settings, it will not effect image positioning using virtual canvas offsets set via the "-page" setting. This is part of the definition of such offsets. See Geometry vs Page Offsets for more details.

If placement with "-gravity" is need look at either the above multi-image composition methods, or the special Layers Composition method that can handle both positioning methods simultaneously.

If any image does not appear in the defined virtual canvas area, it will either be clipped or ignored, as appropriate. For example here we used a smaller canvas size, causing the later images not to appear completely on that canvas.

  convert -page 75x75+5+10  balloon.gif   -page +35+30 medical.gif  \
          -page +62+50 present.gif   -page +10+55 shading.gif  \
          -background dodgerblue  -flatten  flatten_bounds.gif
[IM Output]

The normal use of Flatten is to merge multiple 'layers' of images together.

That is you can be generating various parts of a larger image, usually using Parenthesis to limit image operators to the single 'layer' image being generated, and then flatten the final result together.

For example one typical use is to create a Shadow Image layer, onto which the original image is flattened. For example...

  convert balloon.gif \( +clone  -background navy  -shadow 80x3+5+5 \) +swap \
          -background none   -flatten   flatten_shadow.png
[IM Output]

Note that as I want the shadow under the original image, I needed to swap the two images place them in the right order.

Using Flatten for adding generated Shadow Images is not recommended, as generated shadow images can have negative image offsets.

The recommended solution, as given in the section on Shadow Images, is to use the more advanced Layer Merging technique, we will look at later.

Because the Virtual Canvas consists of just a size, the resulting image will be that size, but have no virtual canvas offset, as such you do not need to worry about any offsets present in the final image.

This use of the virtual canvas to define the canvas on which to overlay the image means you can use it to add a surrounding border to an image. For example here I set the an image's size and virtual offset to 'pad out' an image to a specific size.

  convert medical.gif -set page 64x64+20+20 \
          -background SkyBlue   -flatten   flatten_padding.gif
[IM Output]

Of course there are better ways to Pad Out an Image so that IM automatically centers the image in the larger area.

Strangely the exact same handling can be used to 'clip' or Crop an image to a virtual canvas that is smaller than the original image. In this case however you want to use a negative offset to position the 'crop' location, as you are offseting the image and not positioning the crop 'window'.

  convert  logo:  -repage 100x100-190-60  -flatten  flatten_crop.gif
[IM Output]

Of course a Viewport Crop would also do this better, without the extra processing of canvas generation and overlaying that "-flatten" also does. It also will not 'expand' the image itself to cover the whole viewport if the image was only partially contained in that viewing window.

The most common use of the "-flatten" operator is to Remove Transparency from an image. That is to get rid of any transparency that an image may have, but overlaying it on the background color.

Mosaic - Canvas Expanding

The "-layers mosaic" operator (or its "-mosaic" shortcut) is more like a expanding canvas version of the Flatten Operator. Rather than only creating an initial canvas based on just the canvas size of the initial image, the Mosaic Operator creates a canvas that is large enough to hold all the images (in the positive direction only).

For example here I don't even set an appropriate Virtual Canvas, however the "-mosaic" operator will work out how big such a canvas needs to be to hold all the image layers.

  convert -page +5+10  balloon.gif   -page +35+30 medical.gif  \
          -page +62+50 present.gif   -page +10+55 shading.gif  \
          -background dodgerblue  -layers mosaic  mosaic.gif
[IM Output]

As on IM v6.3.6-2 the "-mosaic" operator is only an alias for a "-layers 'mosaic'".

Thus the "-mosaic" option can be regarded as a short cut for the "-layers" method of the same name.

Note that both "-mosaic" and "-flatten" still creates a canvas that started from the 'origin' or 0,0 pixel. This is part of the definition of an images 'virtual canvas' or 'page' and because of this you can be sure that the final image for both operators will have a 0 virtual offset, and the whole canvas will be fully defined in terms of actual pixel data.

Also note that "-mosaic" will only expand the canvas in the positive directions (the bottom or right edges), as the top and left edge are fixed to the virtual origin. That of course means "-mosaic" will still clip images with negative offsets...

  convert -page -5-10  balloon.gif   -page +35+30 medical.gif  \
          -page +62+50 present.gif   -page +10+55 shading.gif  \
          -background dodgerblue  -mosaic  mosaic_clip.gif
[IM Output]

Merging - to Create a New Layer Image

The "-layers merge" operator is almost identical to the previous operators and was added with IM v6.3.6-2. It only creates a canvas image just large enough to hold all the given images at their respective offsets.

Like Mosaic will also expand the canvas, but not only in the positive direction, but also in the negative direction. Basically it means that you don't have to worry about clipping, offset, or other aspects when merging layer images together. All images will be merged relative to each others location.

The output does not include or ensure the origin is part of the expanded canavs. As such the output of a Layers Merge can contain a 'layers offset' which may be positive or negative.

In otherwords.. Layers Merge merges layer images to produce a new layer image.

As such if you don't want that offset when finished you will probably want to include a "+repage" operator before the final save.

For example here is the same set of layer image we have used previously...

  convert -page +5+10  balloon.gif   -page +35+30 medical.gif  \
          -page +62+50 present.gif   -page +10+55 shading.gif  \
          -background dodgerblue  -layers merge  +repage layers_merge.gif
[IM Output]

As you can see the image is only just big enough to hold all the images which were placed relative to each other, while I discarded the resulting images offset relative to the virtual canvas origin. This preservation of relative position without clipping or extra unneeded space is what make this variant so powerful.

Lets try this again by giving one image a negative offset...

  convert -page -5-10  balloon.gif   -page +35+30 medical.gif  \
          -page +62+50 present.gif   -page +10+55 shading.gif  \
          -background dodgerblue  -layers merge  +repage layers_merge_2.gif
[IM Output]

As you can see the "balloon" was not clipped, just moved further away from the others so as to preserve its relative distance to them.

Of course the "+repage" operator in the above examples, removes the absolute virtual canvas offset in the final image, preserving only the relative image placements between the images. The offset was removed as web browsers often have trouble with image offsets and especially negative image offsets, unless part of a GIF animation.

But if I did not remove that offset, all the images will remain in their correct location on the virtual canvas within the generated single layer image, allowing you to continue to process and add more images to the merged image. Typically you would use a "-background" color of 'None', to make the unused areas of the merged image transparent.

When applied to a single image, Layer Merging will replace any transparency in the image with the solid color background, but preserve the images original size, as well as any any offsets in that image, The virtual canvas size of the image however may be adjusted to 'best fit' that images size and offset.

The operators original purpose was allow users to more easily merge multiple distorted images into a unified whole, regardless of the individual images offset. For example when aligning photos to form a larger 'panorama'. You could simply start with a central undistorted base image (without an offset), and use this operator to overlay the other images around that starting point (using either negative or positive offsets) that have been aligned and distorted to match that central image.

For other examples of using this operator by distorting images to align common control points, see 3D Isometric Photo Cube, and 3D Perspective Box.

Other examples of using this operator is to generate a simple series of Overlapping Photos.

Coalesce - a Progressive Layering

The "-layers coalesce" image operator (or its "-coalesce" shortcut) is really designed for converting GIF animations into a sequence of images. For examples, see Coalescing Animations for details.

However, it is very closely associated with "-flatten" and has very useful effects for multi-layered images in this regard.

For example using Coalesce on a single image, will do exact the same job as using Flatten with a "-background" color of 'None' or 'Transparency'. That is it will 'fill out' the canvas of the image with transparent pixels.

  convert  -page 100x100+5+10 balloon.gif -layers coalesce  coalesce_canvas.gif
[IM Output]

When dealing with a image consisting on multiple layers, Coalesce can be used to generate a 'Progressive Layering' of the image. But to do this we need to take a few precautions, to disable any 'GIF animation' handling by the operator.


   convert -page 100x100+5+10 balloon.gif   -page +35+30 medical.gif  \
           -page +62+50       present.gif   -page +10+55 shading.gif  \
           -set dispose None  -coalesce  miff:- |\
     montage - -frame 4 -tile x1 -geometry +2+2 \
             -background none -bordercolor none  coalesce_none.gif
[IM Output]

In the above, we "-set" all the "-dispose" settings to 'None'. This effectively tells "-coalesce" to just overlay each frame on top the results of the previous overlays.

The result is the first image is just a 'fill out' of the images canvas, with a transparency background. The next image is the previous image with that layer overlaid. And so on. A 'progressive' flatten of the image sequence.

The last image in the sequence will thus be the same as if you did a normal "-flatten" with a transparent background.

You can get a completely different sort of effect if you had used a "-dispose" setting of 'Background'. In this case "-coalesce" will just 'fill out' the canvas of each image, as if they were completely separate images!

  convert -page 100x100+5+10 balloon.gif   -page +35+30 medical.gif  \
          -page +62+50       present.gif   -page +10+55 shading.gif  \
          -set dispose Background  -coalesce  miff:- |\
    montage - -frame 4 -tile x1 -geometry +2+2 \
            -background none -bordercolor none  coalesce_bgnd.gif
[IM Output]

Please note however that unlike Flatten, Mosaic, or Merge the "-coalesce" operator does not make use of the current "-compose" alpha composition setting. It only uses an 'Over' compose method, as this is what is required for GIF animation handling.

Using different "-compose" methods with the more standard image layering operators is the subject of the next set of examples.

Compose Methods and Layering

The three Layering methods 'flatten', 'mosaic' will make use of the "-compose" setting to determine the composition method used to overlay each image in sequence. As such you could think of these functions as a multi-image "-composite" operator with the ability to set an initial "-background" canvas color.

However using anything but the default Alpha Composition of 'Over' requires some thought before applying or you will get unexpected results. You may also may need to thing about the effect of the "-background" color that is used by these operators to generate a starting canvas, onto with each image (including the first) in composed.

For example lets place each successive image under the previous images using a 'DstOver'...

  convert -page 100x100+5+10 balloon.gif   -page +35+30 medical.gif  \
          -page +62+50       present.gif   -page +10+55 shading.gif  \
          -background none  -compose DstOver  -flatten  flatten_dstover.gif
[IM Output]

Here the background was set to be transparent, otherwise you will only see the background canvas in the result as all the other images will have been placed 'under' this initial canvas! This does provide a way of 'blanking' an image with a particular color, as shown in Canvases Sized to an Existing Image.

Here is a more practical example. Rather than layering the images with the background canvas first, which awkward and un-natural in some image processing situations, you can just generate the images top-down or foreground to background order.

  convert rose: -repage +10+10 \
          \( +clone -background black -shadow 60x3+5+5 \) \
          \( granite: -crop 100x80+0+0 +repage \) \
          -background none  -compose DstOver -layers merge layer_dstover.gif
[IM Output]

Each of the first three lines generates one layer image, with the final line merging all the layers under the previous layers, effectively reversing the order.

As you can see the image processing for the above was simpler and cleaner than you normally would see with shadow generation, just by underlaying each image in sequence (with a transparent starting canvas)

Of course I could have just as easily Reverse the image list instead.

  convert rose: -repage +10+10 \
          \( +clone -background black -shadow 60x3+5+5 \) \
          \( granite: -crop 100x80+0+0 +repage \) \
          -reverse -layers merge layer_reverse.gif
[IM Output]

However remember that this only re-orders the existing images, and does not effect the 'starting background canvas' that the layering methods create. The compose methods can also be used to produce some interesting effects. For example, if you draw three circles, then by overlaying them using the 'Xor' compose method, you get a unusual and complex looking symbol, for minimal effort.

  convert -size 60x60 \
          \( xc:none -fill blue   -draw 'circle 21,39 24,57' \) \
          \( xc:none -fill red    -draw 'circle 39,39 36,57' \) \
          \( xc:none -fill green  -draw 'circle 30,21 30,3'  \) \
          -background none  -compose Xor   -flatten  flatten_xor.png
[IM Output]


Evaluate-Sequence - Direct Mutli-Image Merging Methods

The "-evaluate-sequence" methods, are designed to merge multiple images of the same size together in very specific ways.

In some ways it is a blend of the Evaluate and Function Operators combined with multi-image Composition techniques we have seen above. Many of the methods provided can even be performed using normal multi-image layering composition techniques, but not all.

The operator uses the same methods as "-evaluate" so you can get a list of them using "-list Evaluate". Though some of these (such as 'Mean' and 'Medium') are really only useful when used with this operator.

Mean (Average) of multiple images

Essentially both the older "-average" and the newer "-evaluate-sequence mean" will create a average of all the images provided.

For example, here is an average of the rose image using all its Flipped and Flopped versions.

  convert rose: -flip rose: \( -clone 0--1 -flop \) \
          -evaluate-sequence mean  average.png
[IM Output]

Averaging hundreds of images of the same fixed scene, can be used to remove most transient effects, such moving people, making them less important. However areas that get lots of transient effects may have a 'ghostly blur' left behind that may be very hard to remove.

As video sequences are notoriously noisy when you look at the individual frames, you can average a number of consecutive, but unchanging, frames together to produce much better cleaner and sharper result.

Matt Leigh, of the University of Arizona, reports that he has used this technique to improve the resolution of microscope images. He takes multiple images of the same 'target' then averages them all together to increase the signal/noise ratio of the results. He suggests others may also find it useful for this purpose.

An alternative for averaging two images together is to use a "composite -blend 50%" image operation, which will work with two different sized images. See the example of Blend Two Images Together for more detail.

The IM Discussion Forum had a discussion on Averaging a sequence 10 frames at a time, so as to average thousands of images, without filling up the computers memory (making it very slow). Related to this, and containing relevent maths is the discussion Don't load all images at once.

Max/Min Value of multiple images

The 'Max' and 'Min' methods will get the maximum (lighter) values and minimum (darker) values from a sequence of images.

Again they are basically equivalent to using a Lighten and Darken Composition Methods, but with multiple images. With the right selection of background canvas color, you could use Flatten Operator with the equivelent compose method.

WARNING: This is not a selection of pixels (by intensity), but a selection of values. That means the output image could result in the individule red, green and blue values from different images, resulting in a new color not found in any of the input images. See the Lighten Compose Method for more details of this.

Median Pixel by Intensity

The "-evaluate-sequence Median" will look for the pixel which has an intensity of the middle pixel from all the images that are given.

That is for each position it collect and sort the pixels from each of the images by intensity. Then it will pick the pixel that falls in the middle of the sequence.

It can also be used as a alternative to simply averaging the pixels of a collection of images.

This could be used for example by combining an image with two upper and lower 'limiting' images. As the pixel will be the middle intensity you will either get the pixel from the original image, or a pixel from the 'limiting' images. In other words you can use this to 'clip' the intensity of the original image. Strange but true.

For an even number of images, the pixel on the brighter side of the middle will be selected. As such with only two images, this operator will be equivalent to a pixel-wise "lighten by intensity".

The key point is that each pixel will come completely from one image, and sorted by intensity. You will never get a mix of values, producing a color mixed from different images. The exact color of each pixel will come completely from one image.

Add Multiple Images

The 'Add' method is will of course simply add all the images together.

  convert ... -evaluate-sequence add ...

Which is a faster (more direct) version of using Flatten to Plus Compose all the images together...

  convert ... -background black -compose plus -layers flatten ...

Be warned that adding images in this way can very easilly overflow the Quantum Range of the image, and as such geta 'clipped' result, unless you use a HDRI version of IM. With HDRI you could easilly convert a 'added result' into a image Mean or Average of the result, bt dividing (using Evaulate Divide Method) by the number of images originally added together.

Subtract Multiple Images

The 'Subtract' method subtracts each image from the first. Or at least that is what it should do. Internally it has arguments swapped and it is subtracting the previous results from the next image. Arrggggg!

However by using a quirk of the Linear Burn Compose Method you can subtract the second and later images from the first. Basically by Negating all but the first image, and setting a 'white' (negated zero) as a the starting background color you can then use Flatten to subtract all the images from the first.

  convert  ...  \
         -negate \( -clone 0 -negate \) -swap 0 +delete \
         -compose LinearBurn -background white -flatten \
         ...

Multiple/Divide Multiple Images

'Multiply' and 'Divide' are accepted as methods by "-evaluate-sequence" but they generate unexpected and odd results, as they are using the actual color value of the images rather than the normalised color value, just as "-evaluate" does. As a result the scale of the multiply and divide is too large.

This could be classed as a bug.

In the meantime, you are better using the equivelent 'flatten' method for Multiply, which does work as expected.

  convert ... -background white -compose multiply -layers flatten ...


layering Image Examples

Laying multiple images using the various layer operators above is a very versatile technique. It lets you work on a large number of images individually, and then when finished you combine them all into a single unified whole.

So far we have shown various ways of merging (composing or layering) multiple images in many different ways. Here I provide some examples on just how to make use of those techniques.

Layering Thumbnail Images

You can also use this technique for merging multiple thumbnails together in various complex ways.

Here I add a Soft Edge to the images as you read and position them, you can generate a rather nice composition of images, on a Tiled Canvas.

  convert -page +5+5    holocaust_tn.gif \
          -page +80+50  spiral_stairs_tn.gif \
          -page +40+105 chinese_chess_tn.gif \
          +page \
          -alpha Set -virtual-pixel transparent \
          -channel A -blur 0x10  -level 50,100% +channel \
          \( -size 200x200 tile:tile_fabric.gif -alpha Set \) -insert 0 \
          -background None -flatten  overlap_canvas.jpg
[IM Output]

Programmed Positioning of Layered Images

You can simplify your image processing, by separating them into two steps. One step can be used to generate, distort, position and add fluff to images, with a final step to merge them all together. For example, lets generate create Polaroid Thumbnails from the larger original images in Photo Store, processing them individually.

The script below does this very nicely, processing each thumbnail image, but then center pads (Extent) and Trimmed each image so that the images 'center' is in a known location on the virtual canvas. It does not actually matter where that location is, as long as it is the same location for all images on the virtual canvas.

The image is then translated (using a relative "-repage" operator, see Canvas Offsets), so that each image generated will be a 60 pixels to the right of the previous image. That is each image center is spaced a fixed distance apart, regardless of how much the images actual size changed due to the rotation. The actual position does not matter, only their relative positions to each other is important.

The other major trick with the script however is that rather than save each 'layer image' into a temporary file, you can just write the image into a pipeline using the MIFF: file format. A method known as a MIFF Image Streaming.

This works because the "MIFF:" file format allows you to simply concatenate multiple images together into a single data stream, while preserving all the images meta-data, such as its virtual canvas offset.

And here is the resulting script...

  center=0   # Start position of the center of the first image.
             # This can be ANYTHING, as only relative changes are important.

  for image in ../img_photos/[a-m]*_orig.jpg
  do

    # Add 70 to the previous images relative offset to add to each image
    #
    center=`convert xc: -format "%[fx: $center +70 ]" info:`

    # read image, add fluff, and using centered padding/trim locate the
    # center of the image at the next location (relative to the last).
    #
    convert -size 500x500 "$image" -thumbnail 240x240 \
            -set caption '%t' -bordercolor Lavender -background black \
            -pointsize 12  -density 96x96  +polaroid  -resize 30% \
            -gravity center -background None -extent 100x100 -trim \
            -repage +${center}+0\!    MIFF:-

  done |
    # read pipeline of positioned images, and merge together
    convert -background skyblue   MIFF:-  -layers merge +repage \
            -bordercolor skyblue -border 3x3   overlapped_polaroids.jpg

[IM Output]

This technique provides a good starting point for many other scripts. Images can be generated, or modified and the final size and position can be calculated in any way you like.

Another example is the script "hsl_named_colors" which takes the list of named colors found in ImageMagick and sorts them into a chart of those colors in HSL colorspace. You can see its output in Color Specification.

Other possibilities include... Basically you have complete freedom in the positioning of images on the virtual canvas, and can then simply leave IM to sort out the final size of the canvas needed to whole all the images.

Other examples, and results are welcome, Mail Me

Pins in a Map

A typical example of layering images is putting pins in a map.

[IM Output] To the left is a 'push pin' image. The end of the pin is at position +18+41.

I also have a image of a Map of Venice, and want to put a pin at various points on the map. For example 'Accademia' is locate at pixel position, +160+283.

To align the push-pin with that position you need to subtract the location of the end of the pin from map position. This poduces a offset of +142+242.

Here is the result, using layered images

  convert map_venice.jpg    -page +142+242 push_pin.png \
          -flatten  map_push_pin.jpg
[IM Output]

This example was from a IM Forum Discussion, Layering Images with Convert.

Lets automate this further.

We have a file listing the locations and colors for each of the pins we want to place in the map.
[Data File]

Lets read this text file, to create 'pins' in a loop.


  pin_x=18  pin_y=41

  cat map_venice_pins.txt |\
    while read x y color location; do

      [ "X$x" = "X#" ] && continue   # skip comments data

      x=$(( x - pin_x ))    # convert x,y to pin image offsets
      y=$(( y - pin_y ))

      # convert 'color' to settings for color modulate (hue only)
      # assumes a pure 'red' color for the original push pin
      mod_args=$(
         convert xc:$color -colorspace HSL txt: |
           tr -sc '0-9\012' ' ' |\
             awk 'NR==1 { depth=$3 }
                  NR==2 { hue=$3;
                          print  "100,100,"  100+200*hue/depth
                        }'; )

      # re-color and position the push pin
      convert push_pin.png -repage +${x}+${y} -modulate $mod_args miff:-

    done |\
      # read pipeline of positioned images, and merge together
      convert  map_venice.jpg  MIFF:-  -flatten  map_venice_pins.jpg

[IM Output]

Note it assumes the original pin color is red and uses the Modulate Operator to re-color it to other colors. Note that for a red pin, Hue = 0 and the modulute argument for no hue change is 100.

FUTURE: perspective distort map, adjust pin size for 'depth' on the map calculate change in pin position due to distortion, and 'pin' it to the distorted map.

Positioning Distorted Perspective Images

Aligning distorted images can be tricky, and here I will look at aligning such images to match up at a very specific location. Here I have two images that highlight a specific point on each image.
[IM Output] [IM Output]

The second image is 65% semi-transparent, and the marked control point pixel positioned at coordinates 59,26 (blue) and 35,14 (red) respectivally.

if you are simply overlaying the two images, you can just subtract the offsets and 'compose' the image on each other, producing a offset of +24+12. Note that this offset could be negative!

  convert align_blue.png align_red.png -geometry +24+12 \
          -composite align_composite.png
[IM Output]

But if you are distorting the image, you will want to ensure the two pixels remain aligned. The best way to do that would be to use the points you want to align as Distort Control Points. This will ensure they are aligned properly.

  convert align_blue.png \
          \( align_red.png -alpha set -virtual-pixel transparent \
             +distort SRT '35.5,14.5  1 75  59.5,26.5' \
          \) -flatten  align_rotate.png
[IM Output]

Note that as distort generates a 'layer image' you can not simply use Composite to overlay the images, instead we need to use a Flatten operator, so that it will position them using page offsets, rather than a composite geometry offset.

Note how I also added a value of 0.5 to the 'pixel' coordinates. This is because pixels have area, while mathematical points do not, as such if you want to align the center of a pixel, you need to add 0.5 to the location of the 'point' within the pixel. See Image Coordinates vs Pixel Coordinates for more information.

The other problem with the above was that the overlayed image was 'clipped' by the blue background canvas image, just as the Composite Operator does. That is to say the 'blue' image provided the 'clipping viewport' for the result during the composition. To prevent this we use Layer Merge instead which creates 'viewport' canvas that is large enough contain hold all the images being composted together.

  convert align_blue.png \
          \( align_red.png -alpha set -virtual-pixel transparent \
             +distort SRT '35.5,14.5  1 75  59.5,26.5' \
          \) -background none -layers merge +repage  align_rotate_merge.png
[IM Output]

As the result of the 'merge' will have a 'negative' offset (so as to preserve layer positions of the images), I need to junk that offset using "+repage". If I was going to do further processing I would keep that offset, so the image positions remains known.

Now the same techniques as shown above would also apply if you were doing a more complex distortion such as Perspective

  convert align_blue.png \
          \( align_red.png -alpha set -virtual-pixel transparent \
             +distort Perspective '35.5,14.5  59.5,26.5
                       0,0 32,4    0,%h 14,36    %w,%h 72,53  ' \
          \) -background none -layers merge +repage  align_perspective.png
[IM Output]

The problem with this technique is that you position the perspective distortion using an internal control point. That can make it hard to control the actual perspective shape.

A alternative method is to control all four corners, but then 'shift' or 'translate' the resulting shaped image so the control points align. But where does our internal control point move to during the distortion? It is this that it the real heart of the problem.

For example, here I distort the image using all four corners to produce a specific shape, but I do not try to align the control points...

  convert align_blue.png \
          \( align_red.png -alpha set -virtual-pixel transparent \
             +distort Perspective '0,0  10,12  0,%h 14,40
                               %w,0 68,6  %w,%h 63,48 ' \
          \) -background none -layers merge +repage  align_persp_shape.png
[IM Output]

As you can see while the red image was distorted, the position of the red control point is no where near the blue control point we want to align. You can not just simply measure these two points as the red point is unlikely to be at a exact pixel position, but will have a sub-pixel offset involved. We will need to first calculate exactly where the red point is.

To do that we can re-run the above distortion with verbose enabled to get the perspective forward mapping coefficents. These can then be used to calculate as descripted in Perspective Projection Distortion.

  convert align_red.png  -verbose \
             +distort Perspective '0,0  10,12  0,%h 14,40
                               %w,0 68,6  %w,%h 63,48 ' null:
[IM Text]

Note that as we are only interested in the forward mapping coefficients (the first part), we don't need the destination image, or worry about virtual pixels, backgrounds or anything else.

Here I extract the 8 perspective coefficents (from the 3rd and 4th line of the previous output, and use them to map the red control point to its new distorted postion, and subtract it from the blue control point so I know how much translation is needed to allow the control point of distorted red shape with the blue background image.

  bluex=59; bluey=26
  redx=35; redy=14

  convert align_red.png  -verbose \
             +distort Perspective '0,0  10,12  0,%h 14,40
                               %w,0 68,6  %w,%h 63,48 ' null: 2>&1 |\
    tr -d "',"  < align_persp_verbose.txt |\
      awk 'BEGIN   { redx='"$redx"'+0.5;   redy='"$redy"+0.5';
                     bluex='"$bluex"'+0.5; bluey='"$bluey"'+0.5; }
           NR == 3 { sx=$1; ry=$2;  tx=$3; rx=$4; }
           NR == 4 { sy=$1; ty=$2;  px=$3; py=$4; }
           END { div =  redx*px + redy*py + 1.0;
                 dx = ( redx*sx + redy*ry + tx ) / div;
                 dy = ( redx*rx + redy*sy + ty ) / div;
                 printf "red point now at %f,%f\n", dx, dy;
                 printf "translate shape by %+f %+f\n", bluex-dx, bluey-dy; }'
[IM Text]

The above used the "tr" text filter to remove extra quotes and commas from the output. It then uses the "awk" program to extract the coefficents, and to the floating point mathematics required.

Note that I again added 0.5 to the 'pixel coordinates' of the control points to ensure that the center of the pixel is what is used for the calculations. See Image Coordinates vs Pixel Coordinates.

Now that we have how much we need to translate the perspective shape by, we have two ways you add that translation to the distortion. Either by modifying the coefficents of the perspective projection appropriatally, or we could just add the translation amounts to each of the destination coordinates of the original.

Here is the result of the later...

  convert align_blue.png \
          \( align_red.png -alpha set -virtual-pixel transparent \
             +distort Perspective '0,0   31.408223,15.334305
                                   0,%h  35.408223,43.334305
                                   %w,0  89.408223, 9.334305
                                   %w,%h 84.408223,51.334305 ' \
          \) -background none -layers merge +repage  align_persp_move.png
[IM Output]

To the right I have cropped and scaled the result around the control points to show they are perfectly aligned!

  convert align_persp_shape.png -crop 19x19+50+17 +repage \
          -scale 500%   align_persp_shape_mag.png
[IM Output]

As you can see we have a perfect alignment of the two pixels, without any sub-pixel overflow to any one side. Even the smallest miss-alignment would show as an asymmetrical coloring on either side of the central pixel.

This scaling even shows some asymetrical changes between left and roght sides of the red cross due to the perspective distortion. That is how accurite this test is.


A similar example but for positioning rotated text is in Text Postioning using Distort.


Under Construction

   -layers trim-bounds can be used to ensure all images get a positive
   offset on a minimal canvas size, while retaining there relative positions,
   and without actually merging the images together.

   This lets you then perform further processing such as inserting the next
   image in the center of all the images and the layers.

   However if images have a transparency, it is probably a good idea to trim
   that transparency first, making the ideal usage...

     -alpha set -bordercolor none -border 1x1 -trim -layers trim-bounds

   This minimizes the image layers including any and all transparent areas of
   actual image data, while ensuring everything is contained on a valid
   virtual (positive) canvas of minimal size.


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