Motion tracking
Pin text, pictures or effects to something that moves in a video, with Blender's tracker.
Kinetograph tracks points through a video with Blender's tracker (libmv). You run it once, before rendering. It writes a small JSON file of positions, and your composition reads it with useTrack(). Rendering never tracks, so every render comes out the same.
Track a point
Find the point in a still of the first frame. You can make one with ffmpeg -i clip.mp4 -frames:v 1 first.png. Then run:
npx kinetograph track public/video/clip.mp4 --point 980,800This writes public/video/clip.mp4.track.json. Repeat --point for more points. Use name=x,y to name one:
npx kinetograph track public/video/clip.mp4 --point anvil=980,800 --point sign=1690,640Points are in the video's own pixels. x goes right, y goes down, and 0,0 is the top-left corner.
Use it in a composition
import { useTrack } from '@kinetographdev/core';
const Label = () => {
const { x, y, rotation, scale } = useTrack('video/clip.mp4.track.json', 'sign');
return (
<div style={{ position: 'absolute', left: x, top: y, transform: `translate(-50%, -50%) rotate(${rotation}deg) scale(${scale})` }}>
Look here
</div>
);
};Draw <Label /> over your <OffthreadVideo>. useTrack returns:
| Field | What it is |
|---|---|
x, y | The tracked point, in video pixels. |
rotation | Degrees the pattern has turned clockwise since the first frame. |
scale | How much bigger the pattern is than in the first frame. |
corners | The pattern's four corners, for a corner pin. |
frame, tracked | The clip frame the value comes from, and whether it is the current frame or a held one. |
The clip starts at frame 0 of the Sequence. If the composition and the clip have different frame rates, frames are matched by time. Before the first tracked frame, the first position is used. After the last frame, or after a track is lost, the last position holds.
If you draw the video smaller, larger or moved, apply the same scale and offset to the positions.
Options
All defaults are Blender's defaults for a new track.
| Option | Default | What it does |
|---|---|---|
--model | loc | What the pattern may do: loc (move), locrot, locscale, locrotscale, affine or perspective. Pick one with rotation or scale if you want rotation and scale to change. |
--pattern, --search | 21, 71 | The size in pixels of the pattern square, and of the area searched for it in the next frame. Fast motion needs a bigger search area. |
--match | keyframe | keyframe compares every frame with the first. previous compares with the frame before, which follows a changing look but can drift. |
--min-correlation | 0.75 | A worse match stops the track. Lower it for grainy footage. |
--margin | 0 | Pixels the pattern keeps from the frame edge. |
--from, --to | the whole clip | The frames to track. |
--backwards | off | Place the points at --to and track towards the start. |
-o | <video>.track.json | Where to write the file. |
Find points automatically
--detect finds corners with plenty of texture, at least 120 pixels apart, on the first frame tracked. Then it tracks them all, as Blender's Detect Features does.
npx kinetograph track public/video/clip.mp4 --detectThe points are named p1, p2 and so on, after any --point you also give. The defaults find only the strongest few corners. To find more, lower the threshold or the distance.
| Option | Default | What it does |
|---|---|---|
--detect-threshold | 0.5 | How strong a corner must be. 0.05 finds many more. |
--detect-distance | 120 | The least number of pixels between points. |
--detect-margin | 16 | Pixels from the frame edge where nothing is detected. |
--detect-inside, --detect-outside | Keep only points inside (or outside) a polygon, written x,y,x,y,... in video pixels. Repeat for more polygons. |
Pin a picture to a surface
A plane track follows a flat surface, such as a screen, a sign or a wall. You make one from four or more tracked points on that surface, as Blender's Create Plane Track does:
npx kinetograph track public/video/clip.mp4 --point 820,540 --point 1250,430 --point 820,360 --point 200,600 \
--plane screen=p1,p2,p3,p4 --plane-corners screen=700,300,1300,320,1280,700,720,680--plane-corners sets the plane's corners on the first frame tracked. The order is top-left, top-right, bottom-right, bottom-left, as x,y pairs in video pixels. Without it, the plane starts as the box around the points' patterns. --plane all uses every tracked point.
Pick points that are on the surface and spread out. Do not pick three on one line.
In the composition, usePlaneTrack() gives the corners for the current frame, ready for the cornerPin effect:
import { Image, cornerPin, usePlaneTrack } from '@kinetographdev/core';
const Screen = () => {
const { pin } = usePlaneTrack('video/clip.mp4.track.json', 'screen');
return <Image src={staticFile('images/poster.png')} width={1280} height={720} effects={[cornerPin(pin)]} />;
};The picture's four corners go to the plane's four corners, whatever its size. Draw <Screen /> in a full-frame layer over the video, with the video at its own size.
Steady a shot
There is no stabiliser, but a track can make one. Apply the opposite of the tracked point's motion to the video: translate(-x, -y), rotate(-rotation) and scale(1 / scale), then move the result back to where the point started. Get that start with trackAt(file, 0, 'anchor').
Track with --model locrotscale to undo rotation and zoom too. Wrap the video in a scale(1.1) layer so the frame edges stay out of view. That hides a shake, but a large camera move still shows the edges.
When a track is lost
A track stops where Blender's would. That is when the best match is below the minimum correlation, falls outside the search area, or reaches the frame edge. The command prints the frame, the file lists it in lost, and the position holds from there.
To track further, try a bigger pattern, a bigger search area, a lower --min-correlation, or a point with more texture.
Match with Blender
Kinetograph drives libmv the way Blender's "Track Markers" does, with Blender's defaults. On the same clip with the same settings, the same frames are tracked and lost. scripts/track-parity/ in the repository runs that comparison.