Motion

Fast True-Motion Motion-Compensation Functions for AVISynth

This filter is in development and not yet ready for real use. Discussion can be found at:

http://forum.doom9.org/showthread.php?t=101859

This is a quick recap of the functions and options; it's not intended as a substitute for reading the discussion, which contains interesting feature requests and suggestions not repeated here. If you have been following the thread, you may just want to skip to the function reference. Please note that all filters are intended for use on progressive YV12 only, and require mod 8 width and height.

Basic Usage

You have probably come here for motion compensated frame rate change. Usage is very simple -- grab the latest versions of the plug-in and the MotionCompensatedFPS script, put them in your plug-in autoloading directory, and write something like this:

MotionCompensatedFPS(100)

In other words, it's used just like ConvertFPS.

That's it!

Intermediate Usage

#AVISource...
Compensate()

This will replace each frame with an approximation to it, calculated using chunks of the previous frame. [So frame 31 will be replaced with frames stitched together from sections of frame 30.]

If you instead want to use an approximation based on the next frame, use this:

#AVISource...
Compensate(source = next)

[So frame 31 will be replaced with a new frame stitched together from sections of frame 32.]

To see the motion vectors, use:

#source
DrawMotion(FindMotion())

#source
DrawMotion(FindMotion(from = next))

Example

For motion compensated denoising:

#AVISource...
Interleave(\
Compensate(),\
last,\
Compensate(source = next))
#temporal smoother, radius 1
SelectEvery(3, 1)

See the documentation for Compensate the notes on compensating across radii greater than one.

Function Reference

BlendFPS
CombineFPS
Compensate
DrawMotion
FindMotion
MotionFPS

General Note

Because I find mode numbers hard to remember and hard to read in scripts, I have defined named constants for use in all the filters below. So while other filters often have the form Filter(mode = 3), the filters in this package tend to use the form Filter(mode = move).

In some cases modes are selected by functions rather than constants -- so you may see Filter(mode = warp(firstargument, secondargument)). This usage has its advantages when writing scripts, but in case it is confusing for casual users I have define presets which should be sufficient in nearly all cases.

Frame Construction Methods

Some of the functions construct new frames from existing ones using motion compensation. All such functions share arguments method and chromamethod. (method is used on luma and chroma planes unless chromamethod is specified, in which case this is used for chroma planes.) This section describes the use of such arguments.

Presets

In order from fastest to slowest:

move -- construct new frame by moving blocks
warpfast -- construct new frame by stretching blocks
warp -- construct new frame by stretching blocks; more accurate than warpfast

For example:

#AVISource...
MotionFPS(100.0, warpfast) #warp all planes quickly

#AVISource...
MotionFPS(100.0, warp, move) #warp luma but move chroma

Warping is slower than moving blocks (although still fast), but is much less likely to produce blocking. It can cause a 'ripple' affected, but this is typically much less distracting than blocking.

Advanced Usage

Reading this section is only useful for writing advanced scripts.

move and warp are in fact functions:

move(interpolation = halfpixel) and
warp(warpinterpolation = bilinear, moveinterpolation = halfpixel).

The interpolation arguments are used to round motion vectors before frames are constructed. They can take the values pixel, halfpixel or hpel, and bilinear (in order from fastest to slowest).

move simply moves blocks from the source frame to construct a new frame; as move(halfpixel) is just as fast as move(pixel), halfpixel is set as the default. [move(bilinear) is currently only implemented in C and is therefore slow.]

warp stretches blocks using bilinear mesh-warping (bilinear in terms of motion vectors). warpinterpolation must be pixel or bilinear. [halfpixel would be almost as slow as bilinear.] When the four corners of a block move by the same amount, it can be moved instead of warped, and in this case moveinterpolation is used.

warpfast is currently set to warp(pixel, halfpixel).

FindMotion(clip, ...)

Optional arguments to FindMotion (not in order):

from = previous/next
int reset (default 0)
int initialise (default 1)

FindMotion estimates block motion for use by other functions in this plug-in. With the default setting of from = previous, it finds where (in the previous frame) each block in the current frame has come from [forward prediction]. If you set from = next, it finds where (in the following frame) each block in the current frame will go [backwards prediction].

With the default setting of reset = 0, motion estimation always uses estimated motion vectors for the previous frame, which forces linear access. If e.g. reset = 50 then motion vectors are calculated from scratch every 50 frames, allowing seeking. Lower values of reset will allow faster seeking.

Increasing initialise increases the accuracy of vectors calculated from scratch, at the cost of increased calculation time (I am currently using initialise =4).

Arguments to FindMotion not recommended for use:

subpixel = true/false (default true)
useassembly = true/false (default true)
iterate (default 1)

Compensate(clip tocompensate[, method, chromamethod, source = previous/next, clip motion])

Compensate constructs a near-copy of the each frame of tocompensate using material from the previous or next frame (as specified by source, default previous). This can be used to e.g. interleave clips for motion compensated denoising.

The construction method used can be one of move (default), warp or warpfast -- also see above. The method is used on luma and chroma planes unless chromamethod is specified, in which case this is used for chroma planes. For example:

#AVISource...
Compensate(warp) #warp all planes

#AVISource...
Compensate(warp, chromamethod = move) #warp luma but move chroma

If specified, motion should be a clip produced by FindMotion. (The source argument of Compensate should match the from argument of FindMotion, as in the scripts above.) If motion is omitted, it will be computed automatically.

The source frame is taken from tocompensate. If motion is specified, it is usual to set this to be the clip which was passed to FindMotion, as follows:

#source = ...
motionclip = FindMotion(source)
compensated = Compensate(source, motion = motionclip)

But it is also possible to compensate another clip. In particular, we can compensate an already compensated clip, like this:

#source = ...
motionclip = FindMotion(source)
singlycompensated = source.Compensate(motion = motionclip)
output = singlycompensated.Compensate(motion = motionclip)

Now frame 32 of the output is made up of portions of frame 31 of the singly compensated clip. But frame 31 of the singly compensated clip is itself made up of portions of frame 30 of the source. So we have indirectly used (only) frame 30 of the source to mimic frame 32 of it. This allows us to apply motion compensated temporal denoise with radii larger than 1.

DrawMotion(clip, clip motion)

DrawMotion illustrates the block motion using motion vectors previously found by FindMotion. motion should be a clip produced by FindMotion.

MotionFPS(clip, float FPS[, method, chromamethod, source = previous/next, clip motion])

MotionFPS changes the frame rate like ConvertFPS or ChangeFPS. It is not meant as a usable replacement for ConvertFPS; it is a building block for frame rate conversion scripts and a tool to help find situations which are difficult for motion compensated frame rate change to deal with.

MotionFPS constructs intermediate frames using material from either the previous or next frame (as specified by source, default previous). The construction method used can be one of move (default), warp or warpfast -- also see above. The method is used on luma and chroma planes, unless chromamethod is specified, in which case this is used for chroma planes. For example:

#AVISource...
MotionFPS(100.0, warp) #warp all planes

#AVISource...
MotionFPS(100.0, warp, move) #warp luma but move chroma

If specified, motion should be a clip produced by FindMotion. (The source argument of MotionFPS should match the from argument of FindMotion, as in the scripts above.) If motion is omitted, it will be computed automatically.

Further examples:

#AVISource...
MotionFPS(100)

#AVISource...
MotionFPS(100, warp, from = next)

CombineFPS(clip, float FPS, clip fromprevious, clip fromnext)

CombineFPS takes two frame rate converted clips (as produced by MotionFPS), one (fromprevious) produced using source = previous and one (fromnext) produced using source = next, and combines them with a weighted average. Weights are chosen to give greater emphasis to frames which are closer to the original source.

Using this function is (for obvious reasons) more than twice as slow as simple frame rate conversion, and so it is not recommended for general use.

Example usage:

#source= AVISource...
source
fromprevious = MotionFPS(100)
fromnext = MotionFPS(100, source = next)
source.CombineFPS(100, fromprevious, fromnext)

BlendFPS(clip, float FPS[, float aperture = 1])

Converts the frame rate to FPS using blend-conversion. Intended as a YV12 alternative to ConvertFPS. Unlike the other functions in this filter, it also supports other colourspaces. FPS may take any value, but blend-conversion is not recommended for changing the frame rate by a large factor. Increasing aperture will blend more frames; decreasing it will blend fewer.