snibgo's ImageMagick pages

Animation with SRT

-distort SRT provides simple but high-quality animation.

For video and animations, we often want to digitally pan and zoom. Successive frames might show different views of the same static image, or different views of a sequence of video frames perhaps to stabilise a hand-held video, or to give the impression of a hand-held camera even though the camera was on a tripod. Importantly, the pan and zoom must be smooth, and not limited to integer pixel coordinates.

Generally, the input image should be large enough that we can pan and zoom while remaining within the image boundaries.

GIF is a poor format for animating photographs. I use it here only for convenience of display on the Web.

The method

The -distort SRT operation takes between two and seven arguments. See the official Command-line Options documentation.

This page will use the six-argument form of SRT. The arguments are:

X,Y A coordinate within the input image.
Scale Scale.
1: no change. >1: magnifies (zooms in)
Angle Angle of rotation.
NewX,NewY Corresponding coordinate within the output image.

The arguments can be floating-point, and IM correctly uses them. The arguments can also be %[fx:...] expressions.

With those six arguments, SRT effectively does the following operations:

Internally, I suppose IM does this in a single operation. But the effect is as if these four separate operations were performed.

"-distort SRT" applies the transformation, putting the required result in the top-left of the canvas. We could crop it from there. However, it is faster to use "-define distort:viewport" before the SRT. The results are identical. If the input is much larger than the output, a viewport is much faster than a crop. (I suppose IM works by looping through every output pixel, calculating the source location. Setting a viewport reduces the required looping.) Annoyingly, -define distort:viewport cannot accept fx expressions.

For example: suppose we have an image that includes a foot, with the big toe at coordinate 3134,4241. We want the output to be 600x400, with the big toe at 200,266.67. We want to rotate the image by 32.5° clockwise., and scale by 0.75.

set SRC=%PICTLIB%20130713\AGA_1372.JPG

%IMG7%magick ^
  %SRC% ^
  -define distort:viewport=600x400+0+0 ^
  -distort SRT 3134,4241,0.75,32.5,200,266.67 ^
  as_ex1.png
as_ex1.pngjpg

For convenience, I put these eight values into variables. These values will be the ones used in the first frame (frame zero) of the animation.

OUT_WI
OUT_HT
Required output width and height.
IN_X
IN_Y
Coords in the input image.
OUT_X
OUT_Y
Corresponding coords in the output image.
SCALE Initial scale.
ANGLE Initial angle of rotation.
set OUT_WI=600
set OUT_HT=400

set IN_X=3134
set IN_Y=4241

set OUT_X=200
set OUT_Y=266.67

set SCALE=0.75
set ANGLE=32.5

Animating the output width and height can't be done within the convert command, and we don't usually want this, so I don't show that here. We can easily animate the other six values.

I use six variables, each being the amount of change per frame.

D_IN_X
D_IN_Y
Pan across the input image, before applying scale and rotate.
Positive pans right/down (moves image left/up).
D_OUT_X
D_OUT_Y
Pan across the output, after applying scale and rotate.
Positive pans right/down (moves image left/up).
D_SCALE Multiplier for scale.
D_ANGLE Additional angle of rotation, degrees clockwise.

For no movement:

set D_IN_X=0
set D_IN_Y=0

set D_OUT_X=0
set D_OUT_Y=0

set D_SCALE=1
set D_ANGLE=0

The formulae to calculate the SRT parameters are:

X = IN_X + D_IN_X * FNUM
Y = IN_Y + D_IN_Y * FNUM
NewX = OUT_X + D_OUT_X * FNUM
NewY = OUT_Y + D_OUT_Y * FNUM
Scale = SCALE * D_SCALEFNUM
Angle = ANGLE + D_ANGLE * FNUM

... where FNUM is the frame number, starting from zero.

If we have a small animation, we can process it entirely within a single convert command by duplicating the image and using t as the frame number.

Translate the input before scale/rotate.

set D_IN_X=3
set D_IN_Y=0

%IMG7%magick ^
  -loop 0 -delay 20 ^
  %SRC% ^
  -duplicate 4 ^
  -define distort:viewport=%OUT_WI%x%OUT_HT%+0+0 ^
  -distort SRT ^
%%[fx:%IN_X%+%D_IN_X%*t],^
%%[fx:%IN_Y%+%D_IN_Y%*t],^
%%[fx:%SCALE%*pow(%D_SCALE%,t)],^
%%[fx:%ANGLE%+%D_ANGLE%*t],^
%%[fx:%OUT_X%-%D_OUT_X%*t],^
%%[fx:%OUT_Y%-%D_OUT_Y%*t] ^
  as_g1.gif

set D_IN_X=0
set D_IN_Y=0
as_g1.gif

Translate the output after scale/rotate.

set D_OUT_X=3
set D_OUT_Y=1.5

%IMG7%magick ^
  -loop 0 -delay 20 ^
  %SRC% ^
  -duplicate 4 ^
  -define distort:viewport=%OUT_WI%x%OUT_HT%+0+0 ^
  -distort SRT ^
%%[fx:%IN_X%+%D_IN_X%*t],^
%%[fx:%IN_Y%+%D_IN_Y%*t],^
%%[fx:%SCALE%*pow(%D_SCALE%,t)],^
%%[fx:%ANGLE%+%D_ANGLE%*t],^
%%[fx:%OUT_X%-%D_OUT_X%*t],^
%%[fx:%OUT_Y%-%D_OUT_Y%*t] ^
  as_g2.gif

set D_OUT_X=0
set D_OUT_Y=0
as_g2.gif

Start zoomed out, and continue zooming out.

set SCALE=0.9
set D_SCALE=0.99

%IMG7%magick ^
  -loop 0 -delay 20 ^
  %SRC% ^
  -duplicate 4 ^
  -define distort:viewport=%OUT_WI%x%OUT_HT%+0+0 ^
  -distort SRT ^
%%[fx:%IN_X%+%D_IN_X%*t],^
%%[fx:%IN_Y%+%D_IN_Y%*t],^
%%[fx:%SCALE%*pow(%D_SCALE%,t)],^
%%[fx:%ANGLE%+%D_ANGLE%*t],^
%%[fx:%OUT_X%-%D_OUT_X%*t],^
%%[fx:%OUT_Y%-%D_OUT_Y%*t] ^
  as_g3.gif

set D_SCALE=1
set SCALE=1
as_g3.gif

Larger animations may not fit into memory. The frames can be processed in a loop, one frame per convert. They can be assembled with gifsicle or ffmpeg.

My convention for frame file names is to use six digits with leading zeros. (Five digits is too few for 60 minutes of video.)

Zoom out and rotate.

set SCALE=0.9
set D_SCALE=0.99
set D_ANGLE=1

set LAST_FR=4

del as_fra_*.png >nul

for /L %%I in (0,1,%LAST_FR%) do (

  set LZ=000000%%I
  set LZ=!LZ:~-6!

  echo !LZ!

  %IMG7%magick ^
    %SRC% ^
    -define distort:viewport=%OUT_WI%x%OUT_HT%+0+0 ^
    -distort SRT ^
%%[fx:%IN_X%+%D_IN_X%*t],^
%%[fx:%IN_Y%+%D_IN_Y%*t],^
%%[fx:%SCALE%*pow^(%D_SCALE%,%%I^)],^
%%[fx:%ANGLE%+%D_ANGLE%*%%I],^
%%[fx:%OUT_X%-%D_OUT_X%*%%I],^
%%[fx:%OUT_Y%-%D_OUT_Y%*%%I] ^
    as_fra_!LZ!.gif
)

%IMG7%ffmpeg -y -i as_fra_%%06d.gif as_fra.mpg

gifsicle -O2 --delay 20 --loopcount=forever as_fra_*.gif >as_fra.gif

del as_fra_*.gif

set D_ANGLE=0
set D_SCALE=1
set SCALE=1

as_fra.gif:

as_fra.gif

Conclusion

The commands shown above implement simple animation of static images, creating pan, zoom and rotate effects. More sophisticated expressions can be used, for example to give the effect a smooth start or finish.


All images on this page were created by the commands shown, using:

%IMG7%magick -version
Version: ImageMagick 7.1.0-42 Q16-HDRI x64 396d87c:20220709 https://imagemagick.org
Copyright: (C) 1999 ImageMagick Studio LLC
License: https://imagemagick.org/script/license.php
Features: Cipher DPC HDRI OpenCL 
Delegates (built-in): bzlib cairo freetype gslib heic jng jp2 jpeg jxl lcms lqr lzma openexr pangocairo png ps raqm raw rsvg tiff webp xml zip zlib
Compiler: Visual Studio 2022 (193231332)
gifsicle --version
LCDF Gifsicle 1.87
Copyright (C) 1997-2014 Eddie Kohler
This is free software; see the source for copying conditions.
There is NO warranty, not even for merchantability or fitness for a
particular purpose.

To improve internet download speeds, some images may have been automatically converted (by ImageMagick, of course) from PNG or TIFF or MIFF to JPG.

Source file for this web page is animsrt.h1. To re-create this web page, run "procH1 animsrt".


This page, including the images, is my copyright. Anyone is permitted to use or adapt any of the code, scripts or images for any purpose, including commercial use.

Anyone is permitted to re-publish this page, but only for non-commercial use.

Anyone is permitted to link to this page, including for commercial use.


Page version v1.0 29-September-2015.

Page created 25-Aug-2022 21:10:23.

Copyright © 2022 Alan Gibson.