Skip to content

IntrinsicCalibrator

SUMMARY

IntrinsicCalibrator recovers a single camera's intrinsic matrix and distortion coefficients from a stack of calibration-board images. One class dispatches on whichever target you pass it, no separate class per board type.

The Skill

python
from telekinesis.axon import IntrinsicCalibrator, IntrinsicOptions

The Code

python
from telekinesis.axon import IntrinsicCalibrator, IntrinsicOptions
from telekinesis.axon.targets import CharucoTarget

target = CharucoTarget(squares_x=6, squares_y=9, square_length=0.012, marker_length=0.009)

options = IntrinsicOptions()
options.per_view_error_threshold = 0.8

calibrator = IntrinsicCalibrator(target, options)
result = calibrator.calibrate(images)

result.ok                     # bool
result.intrinsic_matrix       # (3, 3) np.ndarray
result.distortion_coefficients
result.reprojection_error
result.successful_indices
result.low_view_error_indices

Background

The pinhole model

Pinhole camera model: image plane, focal length, principal point, and an undistorted vs. distorted image comparison

IntrinsicCalibrator fits a pinhole camera model: a 3x3 intrinsic matrix K (focal lengths fx, fy and principal point cx, cy) plus a set of radial and tangential distortion coefficients that describe how the real lens deviates from an ideal pinhole. Given a set of images of a target with known geometry, cv::calibrateCamera solves for K, the distortion coefficients, and a per-view extrinsic pose (rvec, tvec) jointly, by minimizing the reprojection error: the pixel distance between each detected corner and where the fitted model predicts that corner should land.

Reading the fit

reprojection_error (the mean over all views) and per_view_errors (one value per view) are the two numbers that tell you how well the model fits, see Best Practices for how to read them.

Initialization

python
IntrinsicCalibrator(target, options=IntrinsicOptions())
ParameterTypeDescription
targetChessboardTarget | CharucoTarget | ArucoTargetCalibration target, see All Supported Targets.
optionsIntrinsicOptionsSolver tunables, see IntrinsicOptions.
SkillDescription
CalibrateDetect the target in every image and run cv::calibrateCamera.
Find CornersDetect the target in a set of images with no calibration solve.

See also IntrinsicCalibrator State to read back the target, options, and detections of the last calibrate() call.

Best Practices

Collecting a good dataset

Do thisWhy
Capture 15-20+ viewsFewer under-constrains the distortion coefficients; beyond ~20-25 good views, additional frames give diminishing returns unless you're specifically trying to cover more of the frame
Cover the whole frame, not just the centerDistortion is smallest near the principal point and largest toward the edges and corners; a board that only ever appears centered fits K reasonably but leaves distortion poorly constrained
Vary tilt, not just positionA set of fronto-parallel views (board always facing the camera) is close to degenerate for separating focal length from distance
Vary distance too, within your operating rangeCalibrating at one working distance doesn't generalize to another

Common pitfalls

Watch forWhy
Motion blur and inconsistent exposureA blurred or poorly-exposed corner detection is worse than a missing one; per_view_error_threshold in IntrinsicOptions and the resulting low_view_error_indices help you find and exclude these after the fact
A gap between reprojection_error and individual per_view_errorsA low mean with one or two much higher outliers usually means a bad detection on those frames (motion blur, glare, partial occlusion) rather than a systemic problem; drop them and recalibrate rather than accepting a mean pulled down by otherwise-good views