Use a calibration¶
To get your own camera's calibration as calibration.json first, see
Get your camera's calibration.
Conventions¶
- Camera model: pinhole projection with equidistant (Kannala-Brandt) fisheye distortion,
distortion = [k1, k2, k3, k4]— OpenCV'scv2.fisheyemodel and Kalibr'spinhole-equi. - Camera frame: x right, y down, z forward (along the optical axis).
T_cam_imu/T_cam0_imu: 4×4 transform mapping a point from the IMU frame into the camera frame,p_cam = T_cam_imu · p_imu. Its translation column is the IMU origin in the camera frame. The IMU's axes differ by camera model; see Motion data axes.T_cam1_cam0: maps a point from the left eye (cam0) into the right eye (cam1). Its translation is about (−0.070, 0, 0) m: the right eye sits 70 mm to the right.- Stereo eyes: cam0 = the wearer's left eye = the left half of a side-by-side frame
(x = 0…1919); cam1 = the right eye = the right half (x = 1920…3839). On card recordings the eyes
are separate
_Land_Rfiles. - Time offset:
t_imu = t_cam + timeshift_cam_imu_s— add the time shift to put a camera timestamp on the IMU clock. Same sign convention as Kalibr'stimeshift_cam_imu. - Frame timestamps: Stereo (V5) timestamps refer to the centre image row at mid-exposure;
row
rof a frame was exposed att_frame + (r − 540) · line_delay_s. Stereo GS (V6) exposes all rows together; timestamps are mid-exposure. - IMU noise: continuous-time noise densities and random walks (Kalibr / OpenVINS convention), conservative defaults suited to VIO.
- Resolution: all values are for 1920×1080 per camera. If you scale images, scale
fx, fy, cx, cyby the same factor; distortion coefficients are unchanged.
Export to Kalibr / OpenVINS / VINS-Fusion / Basalt¶
From the Trinet-BatchCalibrations repository (Python 3):
python3 tools/to_kalibr_yaml.py stereo-rs/V5/trinet_pro_stereo_V5_batch_calibration.json out/
# -> out/camchain-imucam.yaml out/imu.yaml
python3 tools/to_kalibr_yaml.py mono/V4/trinet_pro_mono_V4_batch_calibration.json out/ \
--cam-topics /cam0/image_raw --imu-topic /imu0
Check your calibration in the field¶
A stereo camera's calibration describes its two lenses as they were when it was calibrated. Knocks, handling or a lens being touched can move them slightly; the usual symptom is a small vertical offset between the two eyes, which degrades depth and stereo tracking. The Python toolkit can measure that offset from an ordinary recording — no calibration target needed.
- Record a few seconds of a well-lit, textured scene 1–5 m away — a desk, shelves, a room. Avoid blank walls, the sky and dark scenes.
-
Run the check on the take (the calibration embedded in the recording is used; add
--calibration calibration.jsonto check a calibration file instead): -
Read the result:
| Verdict | Vertical offset | What to do |
|---|---|---|
| OK | up to 1.5 px | Nothing — the calibration fits. Healthy cameras typically read 0.5–1 px. |
| CHECK | 1.5 – 3 px | Re-run on another well-lit, textured take. If it stays in this range, plan a recalibration. |
| RECALIBRATE | above 3 px | The stereo mount has moved since calibration; depth from this camera is degraded until it is recalibrated — contact us. |
| INCONCLUSIVE | — | Too few features to measure — record a more textured, better-lit scene. |
The command exits with 0 (OK), 1 (CHECK), 2 (RECALIBRATE) or 3 (INCONCLUSIVE), and --json prints
the result for scripts — handy for checking every camera after a shoot. The check detects vertical
misalignment between the eyes, the most common way a stereo calibration drifts; it does not measure
a change of focal length.
Undistort (mono) or rectify (stereo) with OpenCV¶
Needs numpy and opencv-python:
python3 tools/undistort_example.py mono/V4/trinet_pro_mono_V4_batch_calibration.json frame.png undistorted.png
python3 tools/undistort_example.py stereo-gs/V6/trinet_pro_stereo_gs_V6_batch_calibration.json sbs.png rectified.png
The stereo example splits a side-by-side frame, rectifies both eyes with
cv2.fisheye.stereoRectify, draws horizontal check lines and prints the Q matrix for
disparity-to-depth. Options --balance and --fov-scale control how much of the fisheye image is
kept.
Refine online¶
The quantities that vary per unit are cheap to refine while running:
- Stereo relative rotation: pitch and roll between the eyes are observable from the vertical disparity of matched features in any scene; yaw from distant features, or from a VIO with online camera–IMU extrinsic refinement (for example OpenVINS or Basalt). Keep intrinsics and baseline fixed.
- Optical centre: refine together with the camera–IMU extrinsics in your VIO, or use a per-unit calibration.
With the toolkit¶
The Python toolkit reads the calibration embedded in recordings, uses it for MCAP export and OpenVINS configuration, and its SD-card ingest folds a calibration file into delivery metadata.