Camera Calibration: The Complete Mathematical Guide
A rigorous walkthrough of Zhang's camera calibration method — homography, intrinsic recovery, and distortion modeling — with Python examples.
Camera calibration is one of the most foundational operations in computer vision. Yet it's often treated as a black box. In this post I'll unpack the full mathematical machinery.
The Pinhole Camera Model
A 3D world point is projected to image point via the projection matrix :
where is the intrinsic matrix:
Here are focal lengths in pixels, is the principal point, and is the skew (nearly always zero for modern sensors).
Homography from a Planar Target
Zhang's method uses a planar checkerboard (). Setting collapses the projection to a homography :
has 8 DOF and is estimated from point correspondences via DLT (Direct Linear Transform).
Recovering Intrinsics
Each homography provides 2 constraints on (a symmetric matrix with 6 unknowns):
With images we can solve for all 5 intrinsics using SVD.
Lens Distortion
Radial distortion is the dominant aberration for most lenses. The distortion model:
where is the radial distance in normalized coordinates. Tangential distortion adds:
Coefficients are estimated jointly with intrinsics via non-linear least squares.
Practical Tips
- Use at least 15–20 images with varied orientations.
- Check reprojection error: < 0.3 px RMS is excellent; > 1.0 px signals problems.
- Fisheye lenses need the Kannala-Brandt model (
cv2.fisheyein OpenCV). - Avoid images where the board fills less than 20% of the frame — corners are poorly conditioned.
import cv2
import numpy as np
# Detect corners
ret, corners = cv2.findChessboardCorners(gray, (9, 6), None)
# Refine to sub-pixel
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
corners = cv2.cornerSubPix(gray, corners, (11, 11), (-1, -1), criteria)
# Calibrate
ret, K, dist, rvecs, tvecs = cv2.calibrateCamera(
obj_points, img_points, gray.shape[::-1], None, None
)
print(f"RMS reprojection error: {ret:.4f} px")
The reprojection RMSE from calibrateCamera is your primary quality metric. Chase it below 0.3 px.