Homography Estimation Fits Planes
Homography estimation solves the 3 by 3 matrix that maps one plane to another, so tilted documents flatten and photo pairs align.
Why Does This Exist?
Two photos of one flat surface differ by perspective, not just shift and zoom. Posters, documents, courts, and walls need a plane to plane map before they can merge or be measured. The homography is that map. Estimation turns matched keypoints into with the Direct Linear Transform inside RANSAC, then warps with it for stitching. For the transform basics first, read image transformations and homography.
Think of It Like This
Pinning a poster flat
A poster photographed at an angle looks like a trapezoid. Pin its four corners onto a rectangular frame and the print flattens, with each pin constraining the stretch a little more. Point pairs are those pins: four good pins define the warp and extra pins steady it against noise.
Where it stops: pins assume one flat sheet, so curved pages or scenes with real depth need richer models than a single homography.
How It Actually Works
A homography maps homogeneous points to up to scale:
Fixing leaves eight degrees of freedom, so at least four point pairs are needed. The Direct Linear Transform builds two rows of a matrix per pair from the cross product constraint and solves by SVD. Normalize points into first for stable math, then denormalize the result. RANSAC wraps DLT: sample four pairs, score every pair by reprojection error, keep the model with the most inliers under the pixel threshold, and refit on all inliers. Warp with inverse sampling plus bilinear interpolation for clean output.
Worked example
Map source corners , , , to the square , , , . Four pairs give two rows each, hence an matrix , and SVD returns the 9-vector up to scale with . A fifth pair at mapping near then reprojects within pixels under the fitted , so it counts as an inlier at a threshold of . The final refits on all inliers and warps source to destination. Note the pairs must spread over the plane: four collinear points leave perspective underdetermined and DLT returns a wild warp.
Code
The point of this snippet is the apply-and-check step, not the SVD: it maps a point through in homogeneous coordinates and measures the reprojection error that decides inliers.
def apply_h(H, x, y): xp = H[0][0] * x + H[0][1] * y + H[0][2] yp = H[1][0] * x + H[1][1] * y + H[1][2] w = H[2][0] * x + H[2][1] * y + H[2][2] return (xp / w, yp / w)
H = [[2.0, 0.0, 10.0], [0.0, 2.0, 20.0], [0.0, 0.0, 1.0]]print(apply_h(H, 5.0, 5.0))# -> (20.0, 30.0)
def reproj_error(H, x, y, xp, yp): qx, qy = apply_h(H, x, y) return ((qx - xp) ** 2 + (qy - yp) ** 2) ** 0.5
print(round(reproj_error(H, 5.0, 5.0, 20.0, 30.0), 2))# -> 0.0print(reproj_error(H, 5.0, 5.0, 21.5, 30.0) < 3.0)# -> TrueThe exact pair gives zero error, and a prediction pixels off still counts as an inlier at threshold , exactly the rule the worked fifth pair passes.
Watch Out For
Solving from collinear points
Four points on one line leave perspective underdetermined, and DLT returns wild warps. The symptom is a matrix that flattens everything into streaks. Check point spread and reject samples with tiny enclosed area before solving.
Using one homography off the plane
models one plane or pure rotation only, so foreground chairs against a back wall break it. The symptom is a wall that aligns while every chair ghosts double. Segment planes or move to epipolar geometry when depth varies.
The Quick Version
- A homography has eight degrees of freedom with fixed to one.
- Four point pairs give a minimal DLT solution through an matrix .
- Normalize points before SVD for stable results.
- RANSAC plus a reprojection threshold near pixels handles outliers.
- Warp with inverse mapping and interpolation for clean output.