Laserline Device Calibration
Laserline calibration jointly estimates camera parameters and a laser plane from observations of both a calibration board and laser line projections on the board. This is used in laser triangulation systems where a camera and laser are rigidly mounted together.
Problem Formulation
Parameters
- Camera intrinsics:
- Distortion:
- Sensor tilt: (optional, for Scheimpflug cameras)
- Per-view poses: (camera-to-target SE(3))
- Laser plane: normal , distance
Observations
Each view provides two types of observations:
- Calibration points: 2D-3D correspondences from the chessboard (same as planar intrinsics)
- Laser pixels: 2D pixel positions where the laser line appears on the target
Objective
The cost function has two terms:
where are weights, are (possibly different) robust loss functions, and is the laser residual.
Laser Residual Types
Two approaches are implemented for the laser residual, selectable via configuration.
PointToPlane (3D Distance)
Algorithm:
- Undistort laser pixel to normalized coordinates
- Back-project to a ray in camera frame
- Intersect the ray with the target plane (at , transformed by pose ) to get a 3D point
- Compute signed distance from to the laser plane:
Residual dimension: 1 (meters)
LineDistNormalized (2D Line Distance) — Default
Algorithm:
- Compute the 3D intersection line of the laser plane and the target plane (in camera frame)
- Project this 3D line onto the normalized camera plane
- Undistort the laser pixel to normalized coordinates (done once, not per-iteration)
- Measure the perpendicular distance from the undistorted pixel to the projected line
- Scale by for pixel-comparable units:
Residual dimension: 1 (effective pixels)
Comparison
| Property | PointToPlane | LineDistNormalized |
|---|---|---|
| Residual units | meters | pixels |
| Undistortion | Per-iteration | Once per pixel |
| Geometry | Ray-plane intersection | 2D line distance |
| Speed | Slower | Faster |
| Recommended | Alternative | Default |
Both approaches yield similar accuracy in practice (<6% intrinsics error, <5° plane normal error in synthetic tests).
Derivation: Line-Distance Residual
Plane-Plane Intersection Line
The laser plane and the target plane (normal , distance from camera, derived from pose ) intersect in a 3D line with:
Projection onto Normalized Plane
Project the 3D line to the plane:
Perpendicular Distance
For an undistorted pixel in normalized coordinates, the perpendicular distance to the 2D line is:
Configuration
#![allow(unused)] fn main() { pub struct LaserlineDeviceConfig { // Initialization pub init_iterations: usize, // Iterative intrinsics iterations (default: 2) pub fix_k3_in_init: bool, // Fix k3 during init (default: true) pub fix_tangential_in_init: bool, // Fix p1, p2 during init (default: false) pub zero_skew: bool, // Enforce zero skew (default: true) pub sensor_init: ScheimpflugParams, // Initial sensor tilt (default: identity) // Optimization pub max_iters: usize, // LM iterations (default: 50) pub verbosity: usize, pub calib_loss: RobustLoss, // Default: Huber { scale: 1.0 } pub laser_loss: RobustLoss, // Default: Huber { scale: 0.01 } pub calib_weight: f64, // Weight for calibration residuals (default: 1.0) pub laser_weight: f64, // Weight for laser residuals (default: 1.0) pub fix_intrinsics: bool, pub fix_distortion: bool, pub fix_k3: bool, // Default: true pub fix_sensor: bool, // Default: true pub fix_poses: Vec<usize>, // Default: vec![0] pub fix_plane: bool, pub laser_residual_type: LaserlineResidualType, // Default: LineDistNormalized } }
Weight Balancing
Since calibration residuals (in pixels) and laser residuals may have different scales, the weights allow balancing their relative influence. A common starting point is calib_weight = 1.0 and laser_weight = 1.0, adjusting if one term dominates.
Complete Example
#![allow(unused)] fn main() { use vision_calibration::prelude::*; use vision_calibration::laserline_device::*; let mut session = CalibrationSession::<LaserlineDeviceProblem>::new(); session.set_input(laserline_input)?; run_calibration(&mut session, None)?; let export = session.export()?; println!("Plane normal: {:?}", export.estimate.params.plane.normal); println!("Plane distance: {:.4}", export.estimate.params.plane.distance); println!("Reprojection error: {:.4} px", export.mean_reproj_error); println!("Laser error: {:.4}", export.stats.mean_laser_error); }
Scheimpflug Support
For laser profilers with tilted sensors, the sensor model parameters are jointly optimized. The ReprojPointPinhole4Dist5Scheimpflug2 factor handles the extended camera model.