MyRoboPathOpen Robotics Lab
Perception & Localization18 min readUpdated 2026-04-10Advanced

Visual SLAM & Visual Odometry: Feature Tracking, Bundle Adjustment & VIO

The Mathematical Architecture of Camera-Based Spatial Intelligence: From Epipolar Geometry to Factor Graph Bundle Adjustment

MyRoboPath Spatial AI & Vision Team
Computer Vision & State Estimation Research Group
Visual SLAM & Visual Odometry: Feature Tracking, Bundle Adjustment & VIO
Tracking Latency
15 – 33 ms
Real-time feature matching at 30 to 60 FPS
Scale Drift (Monocular)
1 – 5%
Metric scale divergence per 100 meters without IMU/Stereo
Bundle Adjustment Window
7 – 20 frames
Local keyframe sliding window for real-time QP optimization
VIO Position Accuracy
< 0.5% drift
Tightly-coupled error per unit distance traveled

Core Engineering Takeaways

  • •Visual Odometry (VO) estimates incremental frame-to-frame trajectory without maintaining a global map, accumulating drift over time, whereas Visual SLAM performs global loop closure and bundle adjustment to correct historical errors.
  • •Monocular cameras suffer from unobservable metric scale ambiguity ($s$); stereo baselines, RGB-D sensors, or tightly coupled IMU accelerometers are required to recover metric scale.
  • •The Essential Matrix $\mathbf{E} = [\mathbf{t}]_\times \mathbf{R}$ encapsulates the geometric relationship between calibrated camera frames, decomposed via SVD into relative rotation and up-to-scale translation.
  • •IMU preintegration computes continuous motion delta factors on the $SO(3)$ Lie manifold between keyframes, avoiding costly numerical re-integration during factor graph optimization.
  • •Loop closure uses Bag-of-Visual-Words (DBoW2) or NetVLAD embeddings to recognize previously visited spaces, triggering Pose-Graph Optimization that eliminates accumulated dead-reckoning drift across kilometers of travel.
Prerequisites
  • Linear algebra (3D rotation matrices, quaternions, SVD, eigenvalues)
  • Camera projection models (pinhole camera intrinsics, focal length, principal point)
  • Probability and state estimation (Kalman filters, maximum likelihood, least squares)

1. Architecture Taxonomy: VO vs Full Visual SLAM vs VIO

Spatial intelligence in autonomous systems begins with answering two fundamental questions: *"Where am I?"* and *"What does the surrounding environment look like?"*

The Taxonomy of Vision-Based Localization:

  1. 1
    Visual Odometry (VO):
  • Focuses strictly on local trajectory continuity.
  • Computes the relative transformation Tk,k−1∈SE(3)\mathbf{T}_{k, k-1} \in SE(3) between consecutive camera frames.
  • Computes no persistent global map; drifts unbounded over extended paths (E∝tE \propto \sqrt{t} or E∝dE \propto d).
  1. 2
    Full Visual SLAM (Simultaneous Localization and Mapping):
  • Maintains both a local sliding-window estimate and a global sparse/dense landmark map.
  • Detects when the camera revisits a prior location (Loop Closure).
  • Executes global Bundle Adjustment (BA) to simultaneously adjust all camera poses and landmark coordinates, pulling the entire drift envelope back to zero.
  1. 3
    Visual-Inertial Odometry / SLAM (VIO / VI-SLAM):
  • Fuses high-rate (200–1000 Hz) IMU linear acceleration and angular velocity with lower-rate (30–60 Hz) camera images.
  • Resolves metric scale for monocular cameras, enables tracking during sudden camera rotations and motion blur, and observes gravity vectors to lock pitch and roll.
The Monocular Scale Dilemma

A single pinhole camera cannot determine if it is looking at a toy car 10 centimeters away or a real semi-truck 50 meters away. Without stereo disparity, depth sensors, or an accelerometer measuring metric gravitational acceleration, monocular visual SLAM trajectories are strictly up-to-scale (sim(3) geometry).

2. Front-End Tracking: Feature-Based (ORB) vs Direct Photometric (DSO)

The SLAM "front-end" abstracts raw camera pixels into mathematical representations suitable for state estimation.

1. Feature-Based Methods (e.g., ORB-SLAM3)

  • Extracts distinctive corner/blob features like FAST or Harris corners.
  • Computes rotation-invariant binary descriptors (ORB - Oriented FAST and Rotated BRIEF).
  • Matches features across frames using Hamming distance matching.
  • Advantages: Robust against illumination changes and wide baseline viewpoints. Excellent for loop closure recognition.
  • Disadvantages: Fails in textureless environments (white walls, foggy warehouses) and discards 98% of image pixel information.

2. Direct Methods (e.g., DSO - Direct Sparse Odometry, SVO)

  • Skips feature detection and descriptors entirely.
  • Minimizes photometric error directly over pixels with high intensity gradients:
Ephoto=∑p∈Ω(Ik(π(T⋅P))−I0(p))2E_{photo} = \sum_{\mathbf{p} \in \Omega} \left( I_k(\pi(\mathbf{T} \cdot \mathbf{P})) - I_0(\mathbf{p}) \right)^2
  • Advantages: Functions well in environments with few distinct corners (smooth walls, subtle surface textures) and constructs semi-dense point clouds.
  • Disadvantages: Highly sensitive to non-Lambertian surfaces, auto-exposure changes, and rolling shutter distortion.
Table 1: Feature-Based vs Direct Visual Front-Ends
CriteriaFeature-Based (ORB-SLAM)Direct (DSO)Hybrid (SVO)
Feature ExtractionFAST corners + BRIEFHigh gradient pixel selectionFAST corners on sparse grid
Cost FunctionReprojection error (geometric)Photometric error (pixel intensity)Photometric patch alignment
Illumination RobustnessExtremely HighModerate (requires photometric calibration)Moderate
Map DensitySparse 3D point cloudSemi-dense gradient mapSparse 3D structure
Computational LoadModerate (GPU/NEON accelerated)High (intense CPU numerical Jacobian)Low (ultra-lightweight for drones)

3. Epipolar Geometry: Essential Matrix & 3D Triangulation

When two calibrated pinhole cameras observe the same 3D point P\mathbf{P}, the point, the two optical centers C1\mathbf{C}_1 and C2\mathbf{C}_2, and the projection vectors lie in a single plane called the Epipolar Plane.

Epipolar Constraint & Essential Matrix

For normalized image coordinates x1\mathbf{x}_1 and x2\mathbf{x}_2 (where x=K−1[u,v,1]T\mathbf{x} = \mathbf{K}^{-1} [u, v, 1]^T):

x2TEx1=0\mathbf{x}_2^T \mathbf{E} \mathbf{x}_1 = 0

Where E\mathbf{E} is the Essential Matrix, formed by the cross-product skew-symmetric matrix of relative translation [t]×[\mathbf{t}]_\times and rotation matrix R\mathbf{R}:

E=[t]×R=[0−tzty tz0−tx −tytx0]R\mathbf{E} = [\mathbf{t}]_\times \mathbf{R} = \begin{bmatrix} 0 & -t_z & t_y \ t_z & 0 & -t_x \ -t_y & t_x & 0 \end{bmatrix} \mathbf{R}

Decomposing E\mathbf{E} via Singular Value Decomposition (SVD) yields four possible (R,t)(\mathbf{R}, \mathbf{t}) solutions. The unique valid physical configuration is identified by the chirality test (verifying that triangulated 3D points lie in front of both camera lenses with positive depth Z>0Z > 0).

3D Landmark Triangulation via Direct Linear Transformation (DLT)

AP=0,where A=[u1P1,3T−P1,1T v1P1,3T−P1,2T u2P2,3T−P2,1T v2P2,3T−P2,2T]\mathbf{A} \mathbf{P} = 0, \quad \text{where } \mathbf{A} = \begin{bmatrix} u_1 \mathbf{P}_{1,3}^T - \mathbf{P}_{1,1}^T \ v_1 \mathbf{P}_{1,3}^T - \mathbf{P}_{1,2}^T \ u_2 \mathbf{P}_{2,3}^T - \mathbf{P}_{2,1}^T \ v_2 \mathbf{P}_{2,3}^T - \mathbf{P}_{2,2}^T \end{bmatrix}
In Simple Words: Triangulation converts 2D pixel coordinates across two calibrated frames into a unique 3D world coordinate vector P by finding the right nullspace of projection matrix equations using SVD.
Variables Breakdown:
P\mathbf{P}
3D world coordinates [X, Y, Z, 1]^T of the landmarkUnit: meters
(u1,v1)(u_1, v_1)
Observed pixel coordinate in Frame 1Unit: pixels
(u2,v2)(u_2, v_2)
Observed pixel coordinate in Frame 2Unit: pixels
Pi,jT\mathbf{P}_{i,j}^T
The j-th row of the 3x4 projection matrix of camera i
Worked Example:

Given two camera poses separated by baseline 0.2 m, rays intersecting with parallax angle > 2 degrees yield sub-centimeter 3D depth estimates.

4. Back-End Optimization: Bundle Adjustment, Ceres Solver & g2o

While the front-end provides initial feature matches and noisy pose estimates, the SLAM back-end refines these estimates to achieve maximum statistical accuracy.

Bundle Adjustment (BA)

Bundle Adjustment simultaneously adjusts 3D landmark positions Xj\mathbf{X}_j and camera poses Ti∈SE(3)\mathbf{T}_i \in SE(3) to minimize the sum of squared reprojection errors:

min⁡{Ti},{Xj}∑i∑jρ(∥zij−π(Ti,Xj)∥Σij−12)\min_{\{\mathbf{T}_i\}, \{\mathbf{X}_j\}} \sum_{i} \sum_{j} \rho\left( \| \mathbf{z}_{ij} - \pi(\mathbf{T}_i, \mathbf{X}_j) \|^2_{\mathbf{\Sigma}_{ij}^{-1}} \right)

Where:

  • zij\mathbf{z}_{ij} is the measured 2D pixel coordinate of landmark jj in frame ii.
  • π(Ti,Xj)\pi(\mathbf{T}_i, \mathbf{X}_j) is the camera projection model mapping 3D space to 2D image plane.
  • ρ(⋅)\rho(\cdot) is a robust M-estimator (such as Huber or Cauchy loss) that downweights outlier measurements caused by false feature matches.
  • Solved iteratively using Levenberg-Marquardt (LM) via sparse Schur complement decomposition, implemented in libraries like g2o or Ceres Solver.
Sliding-Window Local BA

Running global Bundle Adjustment over thousands of camera frames in real-time is computationally impossible. Real-time visual SLAM runs Local BA on a sliding window of the last 10–20 keyframes at 10–20 Hz, offloading Full Global BA to a dedicated low-priority background thread.

5. Visual-Inertial Odometry: IMU Preintegration on SO(3) Manifolds

Fusing camera images with an Inertial Measurement Unit (IMU) bridges the gap between low-frequency visual updates and high-frequency robot dynamics.

Why IMU Preintegration?

Standard numerical integration of IMU measurements (linear acceleration a\mathbf{a} and angular rate ω\boldsymbol{\omega}) depends on the camera pose at the start of the integration step:

ΔRij=∫titjR(t)⋅[ω(t)−bg(t)]×dt\Delta \mathbf{R}_{ij} = \int_{t_i}^{t_j} \mathbf{R}(t) \cdot [\boldsymbol{\omega}(t) - \mathbf{b}_g(t)]_\times dt

Whenever Bundle Adjustment modifies the initial pose Ri\mathbf{R}_i, traditional systems had to re-integrate thousands of high-frequency IMU readings—crippling CPU throughput.

On-Manifold Preintegration (Forster et al.) decouples the delta integration from the starting pose by integrating in the local frame of keyframe ii:

ΔRij=∏k=ij−1exp⁡((ω~k−bg,i)Δt)\Delta \mathbf{R}_{ij} = \prod_{k=i}^{j-1} \exp\left( (\tilde{\boldsymbol{\omega}}_k - \mathbf{b}_{g,i}) \Delta t \right)

When estimated sensor biases bg,ba\mathbf{b}_g, \mathbf{b}_a change slightly during optimization, the preintegrated measurement is updated instantly via first-order Taylor expansion without re-running numerical integration!

IMU Preintegrated Position Delta on SO(3)

Δpij=∑k=ij−1[ΔvikΔt+12ΔRik(a~k−ba,i)Δt2]\Delta \mathbf{p}_{ij} = \sum_{k=i}^{j-1} \left[ \Delta \mathbf{v}_{ik} \Delta t + \frac{1}{2} \Delta \mathbf{R}_{ik} (\tilde{\mathbf{a}}_k - \mathbf{b}_{a,i}) \Delta t^2 \right]
In Simple Words: The relative position displacement between two keyframes is integrated purely in the local body coordinate frame of the initial keyframe, invariant to global world frame shifts.
Variables Breakdown:
Δpij\Delta \mathbf{p}_{ij}
Preintegrated translation vector between frame i and frame jUnit: meters
a~k\tilde{\mathbf{a}}_k
Raw accelerometer reading from IMUUnit: m/s²
ba,i\mathbf{b}_{a,i}
Estimated accelerometer bias vector at frame iUnit: m/s²
Δt\Delta t
Sampling interval of the IMU (e.g., 0.005 s for 200 Hz)Unit: seconds
Worked Example:

Between two camera frames spaced 100 ms apart, 20 IMU samples at 200 Hz are preintegrated into a single factor in the GTSAM or Ceres graph.

6. Loop Closure & Global Drift Correction: DBoW2 & Sim(3) Alignment

Even with high-precision local Bundle Adjustment and IMU fusion, long-distance robotic exploration inevitably accumulates drift.

Loop Closure provides the antidote:

The Loop Closure Pipeline:

  1. 1
    Place Recognition via Visual Vocabularies:
  • Every keyframe converts its extracted feature descriptors into a visual Bag-of-Words vector using DBoW2 or DBoW3 hierarchical k-means trees.
  • When a new keyframe is processed, DBoW computes inverted-index cosine similarity scores against all historical keyframes, instantly flagging candidates.
  1. 2
    Geometric Verification:
  • Feature correspondences are established between the current keyframe and the candidate loop keyframe.
  • RANSAC estimates a 7-DoF similarity transformation S∈Sim(3)\mathbf{S} \in Sim(3) (3 rotation, 3 translation, 1 metric scale factor for monocular systems).
  • If at least 30–50 inliers agree with the transformation, the loop is accepted.
  1. 3
    Global Pose-Graph Optimization (PGO):
  • The loop constraint is inserted into the factor graph as a high-confidence edge.
  • Non-linear optimization propagates the drift correction backwards across the entire trajectory graph, instantly snapping historical paths and landmarks into global geometric alignment.
loop_closure_pgo_ceres.cpp
cpp
#include <ceres/ceres.h>
#include <ceres/rotation.h>

// Residual between estimated relative pose and detected Loop Closure pose
struct Pose3dErrorTerm {
  Pose3dErrorTerm(const Eigen::Vector3d& p_measured,
                  const Eigen::Quaterniond& q_measured,
                  const Eigen::Matrix<double, 6, 6>& sqrt_information)
      : p_measured_(p_measured), q_measured_(q_measured),
        sqrt_information_(sqrt_information) {}

  template <typename T>
  bool operator()(const T* const p_a, const T* const q_a,
                  const T* const p_b, const T* const q_b,
                  T* residuals_ptr) const {
    // Map raw pointers to Eigen types
    Eigen::Map<const Eigen::Matrix<T, 3, 1>> p_a_vec(p_a);
    Eigen::Map<const Eigen::Quaternion<T>> q_a_quat(q_a);
    Eigen::Map<const Eigen::Matrix<T, 3, 1>> p_b_vec(p_b);
    Eigen::Map<const Eigen::Quaternion<T>> q_b_quat(q_b);

    // Compute relative pose difference
    Eigen::Matrix<T, 3, 1> p_diff = q_a_quat.conjugate() * (p_b_vec - p_a_vec);
    Eigen::Quaternion<T> q_diff = q_measured_.cast<T>().conjugate() * 
                                  (q_a_quat.conjugate() * q_b_quat);

    // Populate 6-DoF residual vector (3 translation, 3 rotation)
    Eigen::Map<Eigen::Matrix<T, 6, 1>> residuals(residuals_ptr);
    residuals.template block<3, 1>(0, 0) = p_diff - p_measured_.cast<T>();
    residuals.template block<3, 1>(3, 0) = T(2.0) * q_diff.vec();

    // Scale by information matrix (inverse covariance)
    residuals = sqrt_information_.cast<T>() * residuals;
    return true;
  }

  const Eigen::Vector3d p_measured_;
  const Eigen::Quaterniond q_measured_;
  const Eigen::Matrix<double, 6, 6> sqrt_information_;
};

Note: C++ snippet illustrating a pose-graph constraint added to Ceres Solver when a loop closure is detected.

Frequently Asked Questions

Common Questions & Troubleshooting

Q:Why does monocular Visual SLAM fail to calculate real-world distances in meters?

Monocular cameras project 3D light rays onto a 2D sensor array. A 10 cm object at 1 meter projects the exact same image coordinates as a 100 cm object at 10 meters. Without an external metric reference (such as a known stereo camera baseline distance, depth sensor, or calibrated IMU measuring gravitational acceleration g = 9.81 m/s²), the scale factor is unconstrained.

Q:How does ORB-SLAM3 achieve tracking through dark rooms or rapid jerky movements?

ORB-SLAM3 integrates high-rate IMU preintegration with an Atlas multi-map system. When visual tracking is lost due to motion blur or darkness, the system relies on the high-bandwidth IMU to propagate pose estimates. If tracking fails completely, it spawns a new sub-map and later merges it back into the master map when visual features re-appear.

Q:What is the key difference between 2D LiDAR SLAM (Cartographer) and Visual SLAM?

2D LiDAR SLAM directly measures metric distances across a 360-degree horizontal plane, providing immense geometric reliability in planar indoor corridors. Visual SLAM captures rich color and 3D volumetric appearance data, allowing 6-DoF tracking and semantic object recognition, but is more sensitive to variable lighting and low-texture surfaces.

Q:What is Huber loss and why is it preferred over ordinary least squares in Bundle Adjustment?

Ordinary least squares squares the error (e²), which means a single false feature match (an outlier with 100px reprojection error) creates a massive gradient (10,000) that pulls the entire optimization off course. Huber loss acts quadratically for small errors (inliers) and transitions to linear penalty for large errors (outliers), preventing catastrophic corruption of the map.