Skip to main content

locus_core/
lib.rs

1//! High-performance AprilTag and ArUco detection engine.
2//!
3//! Locus is a research-oriented, memory-safe fiducial marker detector targeting low
4//! latency. It provides a performance-focused pipeline for robotics and computer vision,
5//! with strict zero-heap allocation in the detection hot-path.
6//!
7//! # Cargo features
8//!
9//! - `non_rectified` — enables [`BrownConradyModel`] and [`KannalaBrandtModel`] alongside
10//!   the corresponding [`pose::DistortionCoeffs`] variants. Off by default; opt in for
11//!   cameras with significant lens distortion (OpenCV Brown-Conrady or Kannala-Brandt
12//!   equidistant fisheye). See `README.md` for the full feature matrix.
13
14/// Batched state container for Structure of Arrays (SoA) layout.
15pub(crate) mod batch;
16/// Board-level configuration and layout utilities.
17pub mod board;
18/// Zero-cost camera distortion model trait and implementations.
19pub mod camera;
20/// ChAruco board saddle-point extraction and pose estimation.
21pub mod charuco;
22/// Configuration types for the detector pipeline.
23pub mod config;
24/// Tag decoding traits and implementations.
25pub(crate) mod decoder;
26/// The primary public API for the detector.
27pub mod detector;
28/// Tag family dictionaries (AprilTag, ArUco).
29pub(crate) mod dictionaries;
30/// Unified ERF-based sub-pixel edge refinement shared by quad and decoder stages.
31pub(crate) mod edge_refinement;
32/// EDLines localized quad extraction.
33pub(crate) mod edlines;
34/// Error types for the detection pipeline.
35pub mod error;
36/// Edge-preserving filtering for small tag detection.
37pub(crate) mod filter;
38/// Fast-path decoding funnel.
39pub(crate) mod funnel;
40/// Gradient computation for edge refinement.
41pub(crate) mod gradient;
42/// Gradient-Weighted Line Fitting (GWLF).
43pub(crate) mod gwlf;
44/// Image buffer abstractions.
45pub mod image;
46/// 3D Pose Estimation (PnP).
47pub mod pose;
48/// Weighted pose estimation logic.
49pub(crate) mod pose_weighted;
50/// Quad extraction and geometric primitives.
51pub(crate) mod quad;
52/// Connected components labeling using Union-Find.
53pub(crate) mod segmentation;
54/// SIMD optimized mathematical kernels.
55pub(crate) mod simd;
56/// SIMD-Accelerated Connected Components Labeling (CCL).
57pub(crate) mod simd_ccl_fusion;
58/// Decoding strategies (Hard vs Soft).
59pub(crate) mod strategy;
60/// Utilities for testing and synthetic data generation.
61#[cfg(any(test, feature = "bench-internals"))]
62pub(crate) mod test_utils;
63/// Adaptive thresholding implementation.
64pub(crate) mod threshold;
65/// Thread-local workspace arena for per-candidate allocations.
66pub(crate) mod workspace;
67
68// Re-exports for the public API
69pub use crate::batch::TelemetryPayload;
70pub use crate::board::{AprilGridTopology, BoardConfigError, CharucoTopology};
71#[cfg(feature = "non_rectified")]
72pub use crate::camera::{BrownConradyModel, KannalaBrandtModel};
73pub use crate::camera::{CameraModel, PinholeModel};
74pub use crate::config::{
75    CornerRefinementMode, DecodeMode, DetectOptions, DetectorConfig, PoseEstimationMode,
76    QuadExtractionMode, TagFamily,
77};
78pub use crate::detector::{Detector, DetectorBuilder, FrameContext, LocusEngine};
79pub use crate::error::{ConfigError, DetectorError};
80pub use crate::image::ImageView;
81pub use crate::pose::{CameraIntrinsics, DistortionCoeffs};
82
83#[cfg(feature = "bench-internals")]
84pub mod bench_api {
85    //! Internal API exposed exclusively for benchmarking and integration testing.
86    pub use crate::batch::*;
87    pub use crate::camera::*;
88    pub use crate::decoder::*;
89    pub use crate::dictionaries::*;
90    pub use crate::edge_refinement::*;
91    pub use crate::filter::*;
92    pub use crate::funnel::*;
93    pub use crate::gwlf::*;
94    pub use crate::pose::*;
95    pub use crate::pose_weighted::bench_compute_corner_covariance;
96    pub use crate::quad::*;
97    pub use crate::segmentation::*;
98    pub use crate::simd::sampler::*;
99    pub use crate::simd_ccl_fusion::*;
100    pub use crate::strategy::*;
101    pub use crate::test_utils::*;
102    pub use crate::threshold::*;
103}
104
105/// A single tag detection result.
106#[derive(Clone, Debug, Default)]
107pub struct Detection {
108    /// The decoded ID of the tag.
109    pub id: u32,
110    /// The center coordinates of the tag in image pixels (x, y).
111    pub center: [f64; 2],
112    /// The 4 corners of the tag in image pixels.
113    pub corners: [[f64; 2]; 4],
114    /// The number of hamming errors corrected during decoding.
115    pub hamming: u32,
116    /// The rotation of the tag relative to its canonical orientation (0-3).
117    pub rotation: u8,
118    /// The decision margin of the decoding (higher is more confident).
119    pub decision_margin: f64,
120    /// The extracted bits from the tag.
121    pub bits: u64,
122    /// The 3D pose of the tag relative to the camera (if requested).
123    pub pose: Option<crate::pose::Pose>,
124    /// The covariance of the estimated 3D pose (6x6 matrix), if computed.
125    pub pose_covariance: Option<[[f64; 6]; 6]>,
126}
127
128impl Detection {
129    /// Compute the axis-aligned bounding box (AABB) of the detection.
130    ///
131    /// Returns (min_x, min_y, max_x, max_y) in integer pixel coordinates.
132    #[must_use]
133    #[allow(clippy::cast_sign_loss)]
134    pub fn aabb(&self) -> (usize, usize, usize, usize) {
135        let mut min_x = f64::INFINITY;
136        let mut min_y = f64::INFINITY;
137        let max_x = self
138            .corners
139            .iter()
140            .fold(f64::NEG_INFINITY, |acc, p| acc.max(p[0]));
141        let max_y = self
142            .corners
143            .iter()
144            .fold(f64::NEG_INFINITY, |acc, p| acc.max(p[1]));
145        for p in &self.corners {
146            min_x = min_x.min(p[0]);
147            min_y = min_y.min(p[1]);
148        }
149
150        (
151            min_x.floor().max(0.0) as usize,
152            min_y.floor().max(0.0) as usize,
153            max_x.ceil().max(0.0) as usize,
154            max_y.ceil().max(0.0) as usize,
155        )
156    }
157}
158
159/// A 2D point with f64 precision.
160#[derive(Clone, Copy, Debug, Default)]
161pub struct Point {
162    /// X coordinate.
163    pub x: f64,
164    /// Y coordinate.
165    pub y: f64,
166}
167
168/// A 3D pose (rotation + translation).
169pub use crate::pose::Pose;
170
171/// Returns version and build information for the core library.
172#[must_use]
173pub fn core_info() -> String {
174    "Locus Core v0.1.0 Engine (Encapsulated)".to_string()
175}