calib-targets 0.13.0

Main entry point crate for a collection of plain calibration target detectors built on top of ChESS corners
Documentation

calib-targets

Target gallery — chessboard, ChArUco, PuzzleBoard, marker board

Fast, robust calibration-target detection in Rust: chessboard, ChArUco, PuzzleBoard, and checkerboard marker boards. This is the facade crate — the one most users install. It re-exports every detector in the workspace and adds one-call helpers that take an image::GrayImage, run ChESS corner detection, and return a labelled grid.

Install-friendly entry for the workspace; each detector has its own crate with deeper documentation and tuning reference, linked below.

Book: https://vitalyvorobyev.github.io/calib-targets-rs/

Install

cargo add calib-targets

The image crate is re-exported as calib_targets::image (it ships with the default image feature), so you do not need to add it separately. Importing through the re-export guarantees your GrayImage type is exactly the one the helpers accept — no version-drift expected GrayImage, found GrayImage surprises. A direct cargo add image dependency still works.

Quickstart (chessboard)

use calib_targets::chessboard::ChessboardParams;
use calib_targets::detect;
use calib_targets::image::ImageReader;

fn main() -> Result<(), Box<dyn std::error::Error>> {
    let img = ImageReader::open("board.png")?.decode()?.to_luma8();
    let chess_cfg = detect::default_chess_config();
    let params = ChessboardParams::default();

    match detect::detect_chessboard(&img, &chess_cfg, &params) {
        Ok(det) => println!("labelled {} corners", det.corners.len()),
        Err(err) => println!("no board: {err}"),
    }
    Ok(())
}

Inputs (every helper)

  • image::GrayImage (or a GrayImageView on the detector traits).
  • A *Params config struct (ChessboardParams, CharucoParams, PuzzleBoardParams, MarkerBoardParams). Use ::default() for chessboard, ::for_board(spec) when a layout is required (constructors that store the board take it by value; the sweep_for_board(&spec) presets take it by reference).
  • For the *_best sweep helpers, a slice &[Params] — typically the 3-config preset ChessboardParams::sweep_default() for chessboards, or {Charuco,PuzzleBoard,MarkerBoard}Params::sweep_for_board(&spec) for the board detectors.

Outputs

Every detector emits a typed result object with a corners vector. Chessboard returns ChessboardCorner; ChArUco, PuzzleBoard, and marker boards return target-specific corner structs that can be converted to the shared TargetDetection carrier when needed. Each corner carries:

Field Meaning
position: Point2<f32> Sub-pixel image location.
grid (i, j) integer grid index, i right, j down, rebased so bounding-box min is (0, 0) where applicable.
id Logical corner ID on targets that provide one (ChArUco marker-referenced, PuzzleBoard master ID).
target_position Physical location on the printed board (mm / board units), when cell size and alignment are known.
score: f32 Detector-specific quality score.

Chessboard enforces two hard invariants on its output: no duplicate (i, j) labels, and (0, 0) sits at the visual top-left of the detected grid.

Supported targets

Target Facade helpers Dedicated crate
Chessboard detect_chessboard, detect_chessboard_all, detect_chessboard_best, detect_chessboard_with_diagnostics calib-targets-chessboard
ChArUco detect_charuco, detect_charuco_with_corners, diagnose_charuco, diagnose_charuco_with_corners, detect_charuco_best calib-targets-charuco
PuzzleBoard detect_puzzleboard, detect_puzzleboard_with_corners, diagnose_puzzleboard, diagnose_puzzleboard_with_corners, detect_puzzleboard_best calib-targets-puzzleboard
Marker board detect_marker_board, detect_marker_board_with_corners, diagnose_marker_board, diagnose_marker_board_with_corners, detect_marker_board_best calib-targets-marker
Printable targets printable::{render_target_bundle, write_target_bundle} calib-targets-print
ArUco / AprilTag primitives aruco::* (dictionaries, matcher) calib-targets-aruco

* gated behind the diagnostics feature.

Every detector ships a single-config helper and a 3-config *_best sweep. The sweep is the recommended default for new callers: it handles threshold tradeoffs without forcing manual tuning. The _with_corners variant reuses one ChESS corner pass across several target detectors on the same image; detect_t runs that pass itself from params.chess, so it is the one-liner for the common case.

Main ideas

  • Grid-first. Every detector reduces to "find a chessboard grid, then decode anchors / dots / circles in rectified cells". The heavy lifting lives in calib-targets-chessboard and projective-grid.
  • Precision-by-construction. Wrong (i, j) labels would corrupt calibration, so the detectors reject before they guess.
  • Local invariants, not global warps. The graph, seed, and validation pieces work on local neighbourhoods, so moderate perspective and radial distortion are handled without an explicit distortion model.
  • Partial boards supported. PuzzleBoard gives absolute IDs from any visible fragment; ChArUco and marker boards label whatever is visible.

Tuning difficult cases

Most callers never need to tune. When defaults fail:

  1. Switch to detect_*_best with the built-in 3-config sweep.
  2. Inspect which config succeeded (or none) — the sweep logs counts.
  3. If all fail, open the corresponding detector README: chessboard, ChArUco, PuzzleBoard, marker, or the book tuning chapter for cross-detector guidance.

Limitations

  • One target instance per image. Multiple simultaneous boards are not disambiguated; the largest detection wins.
  • Pinhole-ish optics only. Moderate perspective and radial distortion are handled gracefully; fisheye and extreme wide-angle lenses are not supported.
  • Grayscale input. Colour images must be converted by the caller (.to_luma8()).
  • No temporal tracking. Every call is independent.
  • Roughly-square cells. Strongly anisotropic aspect ratios degrade detection — rescale the input first.

Printable targets

calib_targets::printable re-exports calib-targets-print. PrintableTargetDocument is the canonical JSON input, and write_target_bundle writes <stem>.json, <stem>.svg, <stem>.png in one call. The calib_targets::generate module adds ergonomic constructors (chessboard_document, charuco_document, puzzleboard_document, marker_board_document) that hide the TargetSpec enum wrapping. Ready-made specs live under testdata/printable/.

CLI

cargo install calib-targets ships a calib-targets binary with two generation flows:

# One-step: flags directly to JSON+SVG+PNG bundle
calib-targets gen chessboard \
    --inner-rows 6 --inner-cols 8 --square-size-mm 20 \
    --out-stem my_board

calib-targets gen puzzleboard \
    --rows 8 --cols 10 --square-size-mm 15 \
    --out-stem puzzle

# Two-step: init a reviewable spec first, then render
calib-targets init charuco \
    --out spec.json \
    --rows 5 --cols 7 --square-size-mm 20 \
    --marker-size-rel 0.75 --dictionary DICT_4X4_50
calib-targets validate --spec spec.json
calib-targets generate --spec spec.json --out-stem my_charuco

Run calib-targets list-dictionaries to enumerate built-in ArUco dictionaries. The CLI is gated on the default cli feature; library-only consumers can disable it with default-features = false.

Canonical guide: printable-target book chapter.

Features

  • image (default) — enables the calib_targets::detect helpers that take image::GrayImage inputs and run chess-corners internally.
  • tracing — gates tracing spans across the workspace crates.
  • diagnostics (off) — forwards to calib-targets-chessboard/diagnostics and gates detect_chessboard_with_diagnostics (the DebugFrame channel) plus the diagnose_charuco, diagnose_puzzleboard, and diagnose_marker_board free functions (and their _with_corners counterparts). The hot detect_* paths build no trace when this is off.

Migrating to the current release

The detector structs and these free functions are now one symmetric surface. CharucoDetector, PuzzleBoardDetector and MarkerBoardDetector gained detect(image), which runs the ChESS corner pass from the params.chess field they always carried but never read; their old corner-consuming detect is now detect_with_corners, and detect_with_diagnostics is now diagnose_with_corners, joined by diagnose(image). MarkerBoardDetector returns Result<_, MarkerBoardDetectError> in place of Option. Successful detections are unchanged, and every break is a compile error rather than a silent behaviour change.

See the Migration Guide for before/after snippets covering Rust, the C ABI, Python and WebAssembly.

Examples

cargo run -p calib-targets --example detect_chessboard -- path/to/image.png
cargo run -p calib-targets --example detect_chessboard_best -- path/to/image.png
cargo run -p calib-targets --example detect_charuco -- path/to/image.png
cargo run -p calib-targets --example detect_charuco_best -- path/to/image.png
cargo run -p calib-targets --example detect_markerboard -- path/to/image.png
cargo run -p calib-targets --example detect_puzzleboard -- path/to/image.png
cargo run -p calib-targets --example detect_puzzleboard_best -- path/to/image.png
cargo run -p calib-targets --example generate_printable \
    -- testdata/printable/charuco_a4.json tmpdata/printable/charuco_a4

Other bindings

Crate map

Re-export Crate
calib_targets::core calib-targets-core — shared types, homographies
calib_targets::chessboard calib-targets-chessboard — invariant-first chessboard
calib_targets::aruco calib-targets-aruco — ArUco / AprilTag dictionaries + decoding
calib_targets::charuco calib-targets-charuco — ChArUco detection
calib_targets::puzzleboard calib-targets-puzzleboard — self-identifying chessboard
calib_targets::marker calib-targets-marker — checkerboard + 3 circle markers
calib_targets::printable calib-targets-print — printable targets

Underneath everything sits the standalone projective-grid library — useful if you want grid construction without the calibration layer.

Links