Distortion Estimation from Homography Residuals
After estimating intrinsics via Zhang's method (which assumes distortion-free observations), the residuals between observed and predicted pixel positions encode the lens distortion. This chapter derives a linear method to estimate Brown-Conrady distortion coefficients from these residuals.
Problem Statement
Given:
- Camera intrinsics (from Zhang's method)
- homographies from the calibration board to the image
- Point correspondences: board points and observed pixels
Find: Distortion coefficients .
Assumptions:
- is a reasonable estimate (possibly biased by distortion)
- Distortion is moderate (the linear approximation holds)
- The homographies were computed from distorted pixel observations
Derivation
Ideal vs. Observed Coordinates
For each correspondence in view , the ideal (undistorted) pixel position predicted by the homography is:
Convert both observed and ideal pixels to normalized coordinates:
The residual in normalized coordinates encodes the distortion effect:
Linearized Distortion Model
The Brown-Conrady distortion applied to point with produces a displacement:
This is linear in the distortion coefficients .
Building the Linear System
For each correspondence, write the and components:
where are the ideal normalized coordinates and are the observed residuals.
Stacking all correspondences from all views gives an overdetermined system:
where is (or smaller if some coefficients are fixed), and .
Solving
The least-squares solution is:
In practice, this is solved via SVD of for numerical stability.
Options
#![allow(unused)] fn main() { pub struct DistortionFitOptions { pub fix_tangential: bool, // Fix p1 = p2 = 0 pub fix_k3: bool, // Fix k3 = 0 (default: true) pub iters: u32, // Undistortion iterations } }
fix_k3(defaulttrue): Removes from the system, reducing to a 4-parameter or 2-parameter model. Recommended unless the lens has strong higher-order radial distortion.fix_tangential(defaultfalse): Removes , estimating only radial distortion. Useful when tangential distortion is known to be negligible.
When parameters are fixed, the corresponding columns are removed from .
Accuracy
This linear estimate is typically within 10-50% of the true distortion values. The accuracy depends on:
- Quality of : If intrinsics are biased (from distorted observations), the estimated distortion absorbs some of the bias
- Number of points: More correspondences improve the overdetermined system
- Point distribution: Points across the full image area constrain distortion better than points clustered near the center (where distortion is small)
This accuracy is sufficient for initializing non-linear refinement.
API
#![allow(unused)] fn main() { let dist = estimate_distortion_from_homographies( &k_matrix, &views, opts )?; }
Returns BrownConrady5 with the estimated coefficients.
OpenCV equivalence: OpenCV estimates distortion jointly with intrinsics inside
cv::calibrateCamera. The separate distortion estimation step is specific to calibration-rs's initialization approach.