Fischler–Bolles RANSAC | VitaVision
Back to atlas

Fischler–Bolles RANSAC

5 min readIntermediateView in graph
Based on
Random sample consensus: a paradigm for model fitting with applications to image analysis and automated cartography
Fischler, Bolles · Communications of the ACM 1981
DOI ↗

Goal

Fit a parametric model to a set PP of NN data points where an unknown fraction of the observations are gross errors (outliers). Inputs: the data set PP; a minimal sample size ss determined by the model's degrees of freedom; an inlier-distance threshold ε\varepsilon; a desired success probability pp; a prior inlier-fraction estimate ww; and a consensus-set acceptance threshold tt. Outputs: model parameters θ\theta^* estimated from the largest consistent subset II^* of PP, where consistency is defined by dist(x,θ)ε\mathrm{dist}(\mathbf{x}, \theta^*) \leq \varepsilon. The defining property is the random-sample-consensus strategy: draw a minimal random subset, instantiate a model, count global inliers, and retain the best hypothesis — inverting the classical approach of fitting all data and pruning residuals iteratively.

Algorithm

Let PP denote the data set and N=PN = |P| the number of points. Let ss denote the minimal sample size — the number of points required to instantiate the model uniquely. Let ε\varepsilon denote the inlier-distance threshold: a datum x\mathbf{x} is an inlier to model θ\theta iff dist(x,θ)ε\mathrm{dist}(\mathbf{x}, \theta) \leq \varepsilon. Let pp denote the desired probability that at least one drawn minimal sample consists entirely of inliers. Let ww denote the estimated inlier fraction — the probability that a uniformly chosen datum is an inlier. Let tt denote the minimum consensus-set size required to accept a hypothesis. Let θ\theta denote model parameters and II a consensus set — the subset of PP consistent with θ\theta. Let kk denote the number of trials to execute.

Definition
Iteration count

The number of trials needed so that the probability of drawing at least one all-inlier minimal sample is at least pp:

k=log(1p)log(1ws).k = \frac{\log(1 - p)}{\log(1 - w^s)}.

Derived in §II.B from the geometric-series identity. Expected value and standard deviation of the trial count are

E[k]=ws,SD(k)=1wsws.E[k] = w^{-s}, \qquad \mathrm{SD}(k) = \frac{\sqrt{1 - w^s}}{w^s}.

For p=0.99p = 0.99, w=0.5w = 0.5, s=4s = 4: k72k \approx 72 and E[k]=16E[k] = 16.

Procedure

Algorithm
RANSAC
Input: Data set PP with NN points; minimal sample size ss; inlier threshold ε\varepsilon; desired success probability pp; inlier-fraction estimate ww; acceptance threshold tt.
Output: Model parameters θ\theta^* and inlier set II^*.
  1. Compute k=log(1p)/log(1ws)k = \log(1 - p) / \log(1 - w^s) and round up to the nearest integer.
  2. Initialise II^* \leftarrow \emptyset and θ\theta^* \leftarrow undefined.
  3. For each trial j=1,,kj = 1, \ldots, k:
    1. Draw a uniform random subset SjPS_j \subseteq P with Sj=s|S_j| = s.
    2. Instantiate model θj\theta_j from SjS_j.
    3. Form the consensus set Ij={xPdist(x,θj)ε}I_j = \{\, \mathbf{x} \in P \mid \mathrm{dist}(\mathbf{x}, \theta_j) \leq \varepsilon \,\}.
    4. If Ij>I|I_j| > |I^*| set IIjI^* \leftarrow I_j and θθj\theta^* \leftarrow \theta_j; if It|I^*| \geq t terminate early.
  4. Re-fit θ\theta^* on II^* by least squares (optional; improves accuracy when I>s|I^*| > s).
  5. Return θ\theta^* and II^*.

Implementation

Generic RANSAC loop in Rust:

use rand::seq::SliceRandom;

pub trait RansacModel: Sized {
    type Point;
    const SAMPLE_SIZE: usize;
    fn fit_minimal(sample: &[&Self::Point]) -> Option<Self>;
    fn residual(&self, point: &Self::Point) -> f64;
}

pub fn ransac<M: RansacModel>(
    points: &[M::Point],
    eps: f64,
    p_success: f64,
    w: f64,
) -> Option<(M, Vec<usize>)> {
    let s = M::SAMPLE_SIZE;
    // k = log(1 − p) / log(1 − w^s)
    let k = ((1.0 - p_success).ln() / (1.0 - w.powi(s as i32)).ln()).ceil() as usize;

    let mut rng = rand::thread_rng();
    let indices: Vec<usize> = (0..points.len()).collect();
    let mut best: Option<(M, Vec<usize>)> = None;

    for _ in 0..k {
        let picks: Vec<usize> = indices.choose_multiple(&mut rng, s).copied().collect();
        let sample: Vec<&M::Point> = picks.iter().map(|&i| &points[i]).collect();
        let Some(theta) = M::fit_minimal(&sample) else { continue };

        let inliers: Vec<usize> = points
            .iter()
            .enumerate()
            .filter(|(_, p)| theta.residual(p) <= eps)
            .map(|(i, _)| i)
            .collect();

        if best.as_ref().map_or(true, |(_, b)| inliers.len() > b.len()) {
            best = Some((theta, inliers));
        }
    }
    best
}

Remarks

  • Complexity: O(kNcmodel)O(k \cdot N \cdot c_{\mathrm{model}}), where kk is the iteration count, NN is the number of data points, and cmodelc_{\mathrm{model}} is the cost of one model instantiation plus NN residual evaluations.
  • Iteration count is exponentially sensitive to ww: E[k]=wsE[k] = w^{-s}, so halving ww with s=4s = 4 raises E[k]E[k] from 16 to 256 (§II.B). For w=0.2w = 0.2 and s=4s = 4, E[k]=625E[k] = 625 — impractical without guided sampling.
  • Fat-tailed convergence: SD(k)E[k]\mathrm{SD}(k) \approx E[k] for small wsw^s (§II.B), so k=E[k]k = E[k] yields only ~63% success probability. Production budgets 335×E[k]5\times E[k] trials.
  • Founding application — the Location Determination Problem (§IV.B–E): camera pose from aerial-image landmark correspondences, w{0.8,0.6}w \in \{0.8, 0.6\}, achieved accuracy X: 0.1 ft, Y: 6.4 ft, Z: 2.1 ft, Heading: 0.01°, Pitch: 0.10°, Roll: 0.12° on a 4000 ft real-image benchmark.
  • See ransac for the four design axes — sampling, verification, local optimisation, threshold treatment — that organise the modern RANSAC family.

References

  1. M. A. Fischler, R. C. Bolles. Random Sample Consensus: A Paradigm for Model Fitting with Applications to Image Analysis and Automated Cartography. Communications of the ACM, 24(6)
    –395, 1981. dl.acm.org

Prerequisites

Extended by