Brown-Conrady Distortion

Real lenses introduce geometric distortion: straight lines in the world project as curves in the image. The Brown-Conrady model captures the two dominant distortion effects — radial and tangential — as polynomial functions of the distance from the optical axis.

Distortion Model

Given undistorted normalized coordinates , the distorted coordinates are:

Radial distortion (barrel/pincushion):

Tangential distortion (decentering):

Combined:

The model has five parameters: radial coefficients and tangential coefficients .

OpenCV equivalence: This is identical to OpenCV's distortPoints with the 5-parameter model (k1, k2, p1, p2, k3). Note OpenCV's parameter ordering differs from the mathematical ordering.

Physical Interpretation

  • : barrel distortion (lines bow outward from center)
  • : pincushion distortion (lines bow inward)
  • : higher-order radial corrections
  • : tangential distortion from imperfect lens-sensor alignment (lens elements not perfectly centered)

Typical values for industrial cameras: , , .

When to Fix

The sixth-order radial term is only significant for wide-angle lenses where reaches large values. For typical industrial cameras with moderate field of view:

  • is poorly constrained by the data and often absorbs noise
  • Estimating can cause overfitting, leading to worse extrapolation outside the calibration region
  • The library defaults to fix_k3: true in most problem configurations

Recommendation: Only estimate with high-quality data covering the full image area, or for lenses with field of view > 90°.

Undistortion (Inverse)

Given distorted coordinates , recovering undistorted coordinates requires inverting the distortion model. Since the forward model is a polynomial without a closed-form inverse, calibration-rs uses iterative fixed-point refinement:

This rearranges the distortion equation to isolate and iterates to convergence. The default is 8 iterations, which provides accuracy well below sensor noise for typical distortion magnitudes.

Convergence

The fixed-point iteration converges when the Jacobian of the distortion residual has spectral radius less than 1, which holds for physically realistic distortion values (small , relative to ). For extreme distortion, more iterations may be needed via the iters parameter.

OpenCV equivalence: cv::undistortPoints performs the same iterative inversion.

The DistortionModel Trait

#![allow(unused)]
fn main() {
pub trait DistortionModel<S: RealField> {
    fn distort(&self, n_undist: &Point2<S>) -> Point2<S>;
    fn undistort(&self, n_dist: &Point2<S>) -> Point2<S>;
}
}

The BrownConrady5<S> struct:

#![allow(unused)]
fn main() {
pub struct BrownConrady5<S: RealField> {
    pub k1: S, pub k2: S, pub k3: S,
    pub p1: S, pub p2: S,
    pub iters: u32,   // undistortion iterations (default: 8)
}
}

NoDistortion is the identity implementation for distortion-free cameras.

Distortion in the Projection Pipeline

Distortion operates in normalized image coordinates (after pinhole projection, before intrinsics):

This is the standard convention: distortion is defined on the plane, not in pixel space. The advantage is that distortion parameters are independent of image resolution and focal length.