Motion parallax & focus of expansion

When the camera moves through a static scene, every point moves in the image, and how it moves tells both the depth of the point and where the camera is going. Near points move faster than far ones, and when moving forward, all points stream away from the point you are heading for. Move the camera, turn it, and see which part of the flow carries depth and which does not.

3D world drag to orbit, scroll to zoom camera path over the next 30 frames
Camera image with the flow x1−x0\mathbf{x}_1 - \mathbf{x}_0 ground posts mountains, 300 m away horizon click a point to select it
Flow length ∥x1−x0∥\|\mathbf{x}_1 - \mathbf{x}_0\| in pixels over the inverse depth 1/Z1/Z in 1/m f ∥(Tx,Ty)∥/Zf\,\|(T_x, T_y)\| / Z near points on the right

Flow from a moving camera

Between two frames, the camera center moves by T\mathbf{T} and the camera turns by a small rotation RδR_\delta, both given in the camera frame of the first image. A static point with camera coordinates Xc=Z K−1x0\mathbf{X}_c = Z\,K^{-1}\mathbf{x}_0 in the first frame has the coordinates

Xc′=Rδ⊤(Xc−T)\mathbf{X}'_c = R_\delta^\top (\mathbf{X}_c - \mathbf{T})

in the second, and its pixel moves from x0\mathbf{x}_0 to x1∼KXc′\mathbf{x}_1 \sim K\mathbf{X}'_c. The arrows show this displacement, the motion field of the scene. Optical flow estimated from the images only approximates it (see patch-based vs regularized flow).

Motion parallax

If the camera moves parallel to the image plane (Tz=0T_z = 0) without turning, every point keeps its depth and its pixel moves by

x1−x0=−fZ[TxTy]\mathbf{x}_1 - \mathbf{x}_0 = -\frac{f}{Z} \begin{bmatrix} T_x \\ T_y \end{bmatrix}

All points move in the same direction, opposite to the camera, but the length is inversely proportional to the depth: near objects sweep across the view, the mountains barely move. This is motion parallax, the depth cue you see from a train window. In the plot, all points lie on the line through the origin. Turned around, the flow gives the depth, Z=f ∥T∥/∥x1−x0∥Z = f\,\|\mathbf{T}\| / \|\mathbf{x}_1 - \mathbf{x}_0\|, as long as the motion of the camera is known.

This is also why a 2D translation is only a rough model for the motion of a whole image: it ignores parallax, and it only holds where the scene is at about the same depth.

Focus of expansion

With a forward component Tz≠0T_z \neq 0, the image of the direction of travel,

e=K TTz,\mathbf{e} = \frac{K\,\mathbf{T}}{T_z},

is the one point that does not move, and the translational flow of every other point lies on the line through it:

x1−e=ZZ−Tz (x0−e)\mathbf{x}_1 - \mathbf{e} = \frac{Z}{Z - T_z}\,(\mathbf{x}_0 - \mathbf{e})

Moving forward, points stream away from e\mathbf{e}, the focus of expansion, and do so faster the nearer they are and the farther they are from e\mathbf{e}. An approaching object grows radially in the same way. Moving backward, the flow converges in a focus of contraction. So the flow tells where the camera is heading: a pilot landing a plane aims at the point the flow radiates from. The focus of expansion is the epipole of the first image: the image of the second camera center.

Rotation carries no depth

Turning the camera without moving it maps every pixel through the same homography,

x1∼KRδ⊤K−1x0,\mathbf{x}_1 \sim K R_\delta^\top K^{-1} \mathbf{x}_0,

independent of ZZ: near and far points move alike, and a rotation alone reveals nothing about depth (which is why panoramas are taken by turning around the camera center, see homography). It also distorts the image, e.g. a pan shifts the image and bends it slightly into a trapezoid. For small motions, the flow is approximately the sum of the translational part, which depends on depth, and the rotational part, which does not. With rotation, the total flow no longer radiates from e\mathbf{e}, and depth computed from the flow is wrong unless the rotation is removed first.

Try this