Goal
Stitch two overlapping images and given a set of point correspondences across them. Compute, for every pixel in , a projective transformation that maps the local neighbourhood of into . The field varies smoothly with and reduces to a single global homography when the data are consistent with the projective model; elsewhere it deviates locally to absorb model inadequacy (parallax, non-rotational camera motion, non-planar scene). Globally projective, locally adjustable.
Algorithm
Let denote in homogeneous coordinates. A homography acts as , with the -th row of and the row-stacked vector.
For each correspondence , the constraint linearises to three rows in , of which two are independent:
Stacking for all yields the DLT design matrix .
The single homography that minimises the algebraic residual on all correspondences.
obtained as the right singular vector of with smallest singular value.
A Gaussian locality kernel on the source-image distance from a query point to each correspondence's source position , clipped from below by for stability.
with bandwidth and floor . As the field collapses to the global homography; as extrapolation regions become numerically singular.
The location-dependent homography at query , fit by weighting each correspondence's DLT contribution by .
with — each weight repeats once for each of the two rows of . The solution is the right singular vector of with smallest singular value.
Procedure
- Detect and match keypoints between and . Run RANSAC with a DLT minimal solver to discard outlier correspondences.
- Apply Hartley pre-conditioning: translate each point set to centroid zero and isotropically scale so the mean distance from the origin is . Build the conditioned design matrix once.
- Partition into a uniform grid of cells. Take each cell's centre as the query .
- For every cell, compute the weight vector from and .
- For every cell, take the right singular vector of with smallest singular value as , reshape to , and de-normalise via .
- Warp every pixel inside a cell using that cell's . Composite the warped source onto the target.
Implementation
Per-cell Moving DLT in Rust. The function takes the once-conditioned design matrix and returns the local homography at one cell centre — the kernel that steps 4–5 of the procedure invoke times.
use nalgebra::{DMatrix, Matrix3};
fn moving_dlt(
a: &DMatrix<f64>, // 2N×9 conditioned DLT design matrix
src_pts: &[[f64; 2]], // source-image positions of the N matches
cell_centre: [f64; 2], // query x_*
sigma: f64,
gamma: f64,
) -> Matrix3<f64> {
let n = src_pts.len();
let s2 = sigma * sigma;
// Eq. 11: per-match Gaussian weights with floor γ.
let w: Vec<f64> = src_pts.iter().map(|p| {
let dx = p[0] - cell_centre[0];
let dy = p[1] - cell_centre[1];
(-(dx * dx + dy * dy) / s2).exp().max(gamma)
}).collect();
// Eq. 10: scale row 2i and row 2i+1 of A by w_i so that ‖W_* A h‖² = ∑ w_i² ‖a_i h‖².
let mut wa = a.clone();
for i in 0..n {
let wi = w[i];
for j in 0..9 {
wa[(2 * i, j)] *= wi;
wa[(2 * i + 1, j)] *= wi;
}
}
// Eq. 9: smallest right singular vector of W_* A.
let svd = wa.svd(false, true);
let v_t = svd.v_t.expect("SVD V^T");
let h = v_t.row(8).transpose(); // last row of V^T → smallest singular direction
Matrix3::new(
h[0], h[1], h[2],
h[3], h[4], h[5],
h[6], h[7], h[8],
)
}
Each branch of the function corresponds to one equation: the weight loop is Eq. (11), the row scaling is Eq. (10), and the SVD line is Eq. (9). Hartley pre-conditioning (and de-normalisation ) live one level up, since they are applied once outside the per-cell loop.
Remarks
- Complexity: each per-cell solve is one SVD of a matrix, in ; the full warp is for the field plus for the pixel warp. The paper documents an rank-one SVD update to exploit the observation that most cells share most weights.
- The bandwidth and the floor trade locality against stability. Small tightens locality and improves overlap-region alignment; small frees the warp in data-poor regions and risks degeneracy. The paper's defaults span pixels and for to images.
- The warp reduces gracefully to a global homography in two limits: as all weights equalise and every cell solves the same DLT; as the inter-camera translation tends to zero, the data become projectively consistent and every weighted DLT recovers the same .
- The estimator is local in the source image only. Two correspondences with similar but very different — moving objects, occluding edges — receive equal weights and pull the local homography toward an average, producing visible misalignment. The paper relies on RANSAC to remove such matches before MDLT and on downstream blending or seam cutting to absorb residuals.
- Cell partitioning is a computational shortcut, not a regularisation. Within a cell every pixel uses the same ; the field is piecewise-constant in but still continuous in the warped pixel position to within cell-boundary precision, since neighbouring cells solve nearly identical weighted SVDs.
- Common extensions name the limitation they address: the as-natural-as-possible warp (Lin 2015) attaches a global similarity prior to the boundary cells to suppress perspective distortion in extrapolation regions; bundle-adjusted multi-image stitching iterates MDLT and a shared similarity over views.
- Compared with Gao DHW: see When to choose Gao DHW over APAP on the Gao page, which hosts the comparison per the older-paper-hosts rule.
- Compared with Lin SVA: see When to choose Lin SVA over APAP on the Lin SVA page, which hosts the comparison per the older-paper-hosts rule.
References
- J. Zaragoza, T.-J. Chin, M. S. Brown, D. Suter. As-Projective-As-Possible Image Stitching with Moving DLT. IEEE CVPR, 2013. DOI: 10.1109/CVPR.2013.303
- R. I. Hartley. In Defense of the Eight-Point Algorithm. IEEE TPAMI, 1997. DOI: 10.1109/34.601246
- S. Schaefer, T. McPhail, J. Warren. Image Deformation Using Moving Least Squares. ACM SIGGRAPH, 2006. DOI: 10.1145/1141911.1141920
- J. Gao, S. J. Kim, M. S. Brown. Constructing Image Panoramas Using Dual-Homography Warping. IEEE CVPR, 2011. DOI: 10.1109/CVPR.2011.5995433
- W.-Y. Lin, S. Liu, Y. Matsushita, T.-T. Ng, L.-F. Cheong. Smoothly Varying Affine Stitching. IEEE CVPR, 2011. DOI: 10.1109/CVPR.2011.5995314