Skip to main content

ringgrid/
lib.rs

1//! # ringgrid
2//!
3//! Pure-Rust detector for dense coded ring calibration targets on a hex lattice.
4//!
5//! ringgrid detects ring markers in grayscale images, decodes their 16-sector
6//! binary IDs from a 893-codeword codebook, fits subpixel ellipses via
7//! Fitzgibbon's direct method with RANSAC, and estimates a board-to-image
8//! homography. No OpenCV dependency — all image processing is in Rust.
9//!
10//! ## Detection Modes
11//!
12//! - **Simple** — [`Detector::detect`]: single-pass detection in image coordinates.
13//!   Use when the camera has negligible distortion.
14//! - **External mapper** — [`Detector::detect_with_mapper`]: two-pass pipeline
15//!   with a [`PixelMapper`] (e.g. [`CameraModel`]) for distortion-aware detection.
16//! - **Self-undistort** — [`Detector::detect`] with
17//!   [`SelfUndistortConfig::enable`] set to `true`: estimates a 1-parameter
18//!   division-model distortion from detected markers and optionally re-runs
19//!   detection with the estimated correction.
20//!
21//! ## Quick Start
22//!
23//! ```no_run
24//! use ringgrid::{BoardLayout, Detector};
25//! use std::path::Path;
26//!
27//! let board = BoardLayout::from_json_file(Path::new("target.json")).unwrap();
28//! let image = image::open("photo.png").unwrap().to_luma8();
29//!
30//! let detector = Detector::new(board);
31//! let result = detector.detect(&image);
32//!
33//! for marker in &result.detected_markers {
34//!     if let Some(id) = marker.id {
35//!         println!("Marker {id} at ({:.1}, {:.1})", marker.center[0], marker.center[1]);
36//!     }
37//! }
38//! ```
39//!
40//! ## Coordinate Frames
41//!
42//! Marker centers ([`DetectedMarker::center`]) are always in image-pixel
43//! coordinates, regardless of mapper usage. When a [`PixelMapper`] is active,
44//! [`DetectedMarker::center_mapped`] provides the working-frame (undistorted)
45//! coordinates, and the homography maps board coordinates to the working frame.
46//! [`DetectedMarker::board_xy_mm`] provides board-space marker coordinates in
47//! millimeters when a valid decoded ID is available on the active board.
48//!
49//! See [`DetectionResult::center_frame`] and [`DetectionResult::homography_frame`]
50//! for the frame metadata on each result.
51
52mod api;
53mod board_layout;
54mod conic;
55mod detector;
56mod homography;
57mod marker;
58mod pipeline;
59mod pixelmap;
60mod ring;
61#[cfg(test)]
62pub(crate) mod test_utils;
63
64// ── Public API ──────────────────────────────────────────────────────────
65
66// High-level detector facade
67pub use api::Detector;
68
69// Result types
70pub use detector::Proposal;
71pub use detector::{DetectedMarker, FitMetrics, InnerFitReason, InnerFitStatus};
72pub use homography::RansacStats;
73pub use marker::DecodeMetrics;
74pub use pipeline::{DetectionFrame, DetectionResult};
75
76// Configuration
77pub use detector::{
78    CircleRefinementMethod, CompletionParams, DetectConfig, IdCorrectionConfig,
79    InnerAsOuterRecoveryConfig, InnerFitConfig, MarkerScalePrior, OuterFitConfig,
80    ProjectiveCenterParams, SeedProposalParams,
81};
82pub use homography::RansacHomographyConfig;
83
84// Sub-configs not re-exported from detector::config
85pub use detector::ProposalConfig;
86pub use marker::DecodeConfig;
87pub use ring::{EdgeSampleConfig, OuterEstimationConfig};
88
89// Geometry
90pub use board_layout::{
91    BoardLayout, BoardLayoutLoadError, BoardLayoutValidationError, BoardMarker,
92};
93pub use conic::Ellipse;
94pub use marker::MarkerSpec;
95
96// Camera / distortion
97// These raw codebook/codec modules are re-exported for the ringgrid-cli diagnostic
98// commands (codebook-info, decode-test). They are not part of the stable library
99// API — external code should use the high-level Detector interface.
100#[doc(hidden)]
101pub use marker::codebook;
102#[doc(hidden)]
103pub use marker::codec;
104pub use pixelmap::{
105    CameraIntrinsics, CameraModel, DivisionModel, PixelMapper, RadialTangentialDistortion,
106    SelfUndistortConfig, SelfUndistortResult,
107};