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/// Batched state container for Structure of Arrays (SoA) layout.
8pub mod batch;
9/// Configuration types for the detector pipeline.
10pub mod config;
11/// Tag decoding traits and implementations.
12pub mod decoder;
13/// The primary public API for the detector.
14pub mod detector;
15/// Tag family dictionaries (AprilTag, ArUco).
16pub mod dictionaries;
17/// EDLines localized quad extraction.
18pub(crate) mod edlines;
19/// Error types for the detection pipeline.
20pub mod error;
21/// Edge-preserving filtering for small tag detection.
22pub mod filter;
23/// Fast-path decoding funnel.
24pub mod funnel;
25/// Gradient computation for edge refinement.
26pub mod gradient;
27/// Gradient-Weighted Line Fitting (GWLF).
28pub mod gwlf;
29/// Image buffer abstractions.
30pub mod image;
31/// 3D Pose Estimation (PnP).
32pub mod pose;
33/// Weighted pose estimation logic.
34pub mod pose_weighted;
35/// Quad extraction and geometric primitives.
36pub mod quad;
37/// Connected components labeling using Union-Find.
38pub mod segmentation;
39/// SIMD optimized mathematical kernels.
40pub mod simd;
41/// SIMD-Accelerated Connected Components Labeling (CCL).
42pub mod simd_ccl_fusion;
43/// Decoding strategies (Hard vs Soft).
44pub mod strategy;
45/// Utilities for testing and synthetic data generation.
46pub mod test_utils;
47/// Adaptive thresholding implementation.
48pub mod threshold;
49/// Thread-local workspace arena for per-candidate allocations.
50pub(crate) mod workspace;
51
52// Re-exports for the public API
53pub use crate::config::{
54    CornerRefinementMode, DecodeMode, DetectOptions, DetectorConfig, PoseEstimationMode,
55    QuadExtractionMode, TagFamily,
56};
57pub use crate::detector::{Detector, DetectorBuilder};
58pub use crate::error::{ConfigError, DetectorError};
59pub use crate::image::ImageView;
60pub use crate::pose::CameraIntrinsics;
61
62#[cfg(feature = "bench-internals")]
63pub mod bench_api {
64    //! Internal API exposed exclusively for benchmarking and integration testing.
65    pub use crate::batch::*;
66    pub use crate::decoder::*;
67    pub use crate::dictionaries::*;
68    pub use crate::filter::*;
69    pub use crate::funnel::*;
70    pub use crate::pose::*;
71    pub use crate::quad::*;
72    pub use crate::segmentation::*;
73    pub use crate::simd::sampler::*;
74    pub use crate::simd_ccl_fusion::*;
75    pub use crate::test_utils::*;
76    pub use crate::threshold::*;
77}
78
79/// A single tag detection result.
80#[derive(Clone, Debug, Default)]
81pub struct Detection {
82    /// The decoded ID of the tag.
83    pub id: u32,
84    /// The center coordinates of the tag in image pixels (x, y).
85    pub center: [f64; 2],
86    /// The 4 corners of the tag in image pixels.
87    pub corners: [[f64; 2]; 4],
88    /// The number of hamming errors corrected during decoding.
89    pub hamming: u32,
90    /// The rotation of the tag relative to its canonical orientation (0-3).
91    pub rotation: u8,
92    /// The decision margin of the decoding (higher is more confident).
93    pub decision_margin: f64,
94    /// The extracted bits from the tag.
95    pub bits: u64,
96    /// The 3D pose of the tag relative to the camera (if requested).
97    pub pose: Option<crate::pose::Pose>,
98    /// The covariance of the estimated 3D pose (6x6 matrix), if computed.
99    pub pose_covariance: Option<[[f64; 6]; 6]>,
100}
101
102impl Detection {
103    /// Compute the axis-aligned bounding box (AABB) of the detection.
104    ///
105    /// Returns (min_x, min_y, max_x, max_y) in integer pixel coordinates.
106    #[must_use]
107    #[allow(clippy::cast_sign_loss)]
108    pub fn aabb(&self) -> (usize, usize, usize, usize) {
109        let mut min_x = f64::INFINITY;
110        let mut min_y = f64::INFINITY;
111        let max_x = self
112            .corners
113            .iter()
114            .fold(f64::NEG_INFINITY, |acc, p| acc.max(p[0]));
115        let max_y = self
116            .corners
117            .iter()
118            .fold(f64::NEG_INFINITY, |acc, p| acc.max(p[1]));
119        for p in &self.corners {
120            min_x = min_x.min(p[0]);
121            min_y = min_y.min(p[1]);
122        }
123
124        (
125            min_x.floor().max(0.0) as usize,
126            min_y.floor().max(0.0) as usize,
127            max_x.ceil().max(0.0) as usize,
128            max_y.ceil().max(0.0) as usize,
129        )
130    }
131}
132
133/// A 2D point with f64 precision.
134#[derive(Clone, Copy, Debug, Default)]
135pub struct Point {
136    /// X coordinate.
137    pub x: f64,
138    /// Y coordinate.
139    pub y: f64,
140}
141
142/// A 3D pose (rotation + translation).
143pub use crate::pose::Pose;
144
145/// Returns version and build information for the core library.
146#[must_use]
147pub fn core_info() -> String {
148    "Locus Core v0.1.0 Engine (Encapsulated)".to_string()
149}