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:

  1. Calibration points: 2D-3D correspondences from the chessboard (same as planar intrinsics)
  2. 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:

  1. Undistort laser pixel to normalized coordinates
  2. Back-project to a ray in camera frame
  3. Intersect the ray with the target plane (at , transformed by pose ) to get a 3D point
  4. Compute signed distance from to the laser plane:

Residual dimension: 1 (meters)

LineDistNormalized (2D Line Distance) — Default

Algorithm:

  1. Compute the 3D intersection line of the laser plane and the target plane (in camera frame)
  2. Project this 3D line onto the normalized camera plane
  3. Undistort the laser pixel to normalized coordinates (done once, not per-iteration)
  4. Measure the perpendicular distance from the undistorted pixel to the projected line
  5. Scale by for pixel-comparable units:

Residual dimension: 1 (effective pixels)

Comparison

PropertyPointToPlaneLineDistNormalized
Residual unitsmeterspixels
UndistortionPer-iterationOnce per pixel
GeometryRay-plane intersection2D line distance
SpeedSlowerFaster
RecommendedAlternativeDefault

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.