Visual Odometry from Frame Motion
Watch the ground slide past frame by frame and add up the steps. Visual odometry turns pixel motion between consecutive frames into a running camera path.
Why Does This Exist?
GPS dies indoors and wheels slip, so a camera must dead-reckon from what it sees. Visual odometry exists for that incremental job: estimate rotation and translation between consecutive frames and chain them into a path. It is the front end inside visual SLAM; SLAM adds the map reuse and loop closure that odometry lacks.
This page covers frame-to-frame motion only. Pixel motion basics live in optical flow; the global correction that removes drift belongs to pose graph optimization and structure from motion.
Think of It Like This
Counting steps by watching floor tiles
Walk with eyes on the floor tiles and count how each tile slides past. Big fast slides mean long strides; slow slides mean shuffling. After a hundred steps your count is close but off, because each step estimate carried a small error.
Tiles are tracked corners and strides are and steps. The analogy stops at scale: tile size is known, while a single camera never learns meters without a baseline or a known object.
How It Actually Works
How one step is solved
Each step detects corners, tracks them into the next frame, and solves for the motion that best explains the 2D shifts. With calibrated stereo, triangulated points carry true scale and perspective-n-point recovers directly, where is the rotation and is the translation. With one camera, the epipolar constraint over matched normalized points and yields the essential matrix , with the skew-symmetric form of , and motion recovers up to an unknown scale factor. Keyframes anchor the chain: new frames track against the last keyframe, and a new keyframe spawns when parallax or feature loss passes a threshold. Chaining composes poses as , so per-step errors near 1 percent compound into percent-level drift per hundred meters.
Worked drift numbers
At 10 Hz with 0.5 m per step, 200 frames cover 100 m. A 1 percent scale bias adds 0.005 m each step, totaling m. Independent per-step noise of 0.07 m accumulates as a random walk with standard deviation m, about 1.0 m. The path ends roughly 2 m from truth with no loop to pin it: the textbook odometry drift curve.
Code
import math
steps = [0.505] * 200 # 0.5 m of truth plus 1 percent scale biastotal = 0.0for s in steps: total += s # 1D chaining stands in for SE(3) compositionprint(total)# -> 100.9999999999998print(round(total - 100.0, 2))# -> 1.0print(round(0.07 * math.sqrt(200), 2))# -> 0.99Watch Out For
Trusting monocular scale over distance
Monocular odometry recovers direction but not meters, so scale drifts silently with scene depth. The symptom is a path with the right shape at the wrong size. Fix scale from stereo, an IMU, or a known-height object, and never report meters from one camera alone.
Tracking through pure rotation
Distant scenes under rotation give tiny parallax, so translation estimates swing wildly while rotation looks clean. The symptom is a position that jumps while orientation stays smooth. Gate keyframes on translation parallax and freeze the position update when the baseline collapses.
The Quick Version
- Visual odometry chains frame-to-frame and into a running camera path.
- Stereo gives metric scale; one camera recovers motion only up to a scale factor.
- Keyframes bound cost by tracking new frames against sparse anchors.
- At 10 Hz and 0.5 m steps, 1 percent bias plus noise ends about 2 m off after 200 frames.
- Odometry drifts by design; only loop closure removes the accumulated error.