chess_corners_core/lib.rs
1#![cfg_attr(feature = "simd", feature(portable_simd))]
2#![warn(missing_docs)]
3//! Core primitives for ChESS/Radon response computation, subpixel
4//! refinement, and corner descriptors.
5//!
6//! The crate exposes a deliberate low-level contract through its
7//! crate root: response computation ([`chess_response_u8`],
8//! [`chess_response_u8_patch`], [`radon_response_u8`]), corner
9//! detection ([`find_corners_u8`], [`detect_corners_from_response`])
10//! and its individual stages — threshold + NMS via
11//! [`detect_peaks_from_response_with_refine_radius`] and image-domain
12//! refinement via [`refine_corners_on_image`] — the [`ChessParams`]
13//! configuration consumed by those stages together with its
14//! [`RefinerKind`] refiner selector, pluggable subpixel refinement (the
15//! [`CornerRefiner`] trait and built-in refiners), the two-axis
16//! orientation fit ([`fit_axes_at_point`], [`describe_corners`]), and
17//! the [`ImageView`] borrowed-buffer type. The detector pipeline
18//! composes three orthogonal stages — detection, refinement, and
19//! orientation fit — all reachable from the crate root.
20//!
21//! Most users should work through the `chess-corners` facade crate rather than
22//! depending on `chess-corners-core` directly. Depend on this crate only when
23//! you need raw response maps, custom refiners, or the Radon detector primitives.
24//!
25//! # Features
26//!
27//! - `std` *(default)* – compatibility feature reserved for future use.
28//! The current detector implementation requires the Rust standard library.
29//! - `rayon` – parallelizes the dense response computation and Radon accumulation
30//! over image rows using the `rayon` crate. Does not change numerical results.
31//! - `simd` – enables a SIMD‑accelerated inner loop for the ChESS response
32//! kernel, based on `portable_simd`. Requires a nightly compiler; the
33//! scalar path remains the reference implementation.
34//! - `tracing` – emits structured spans around response and detector functions
35//! using the [`tracing`](https://docs.rs/tracing) ecosystem, useful for
36//! profiling and diagnostics.
37//!
38//! Feature combinations:
39//!
40//! - no features / `std` only – single‑threaded scalar implementation.
41//! - `rayon` – same scalar math, but rows are processed in parallel.
42//! - `simd` – single‑threaded, but the inner ring computation is vectorized.
43//! - `rayon + simd` – rows are processed in parallel *and* each row uses the
44//! SIMD‑accelerated inner loop.
45//!
46//! The detector is independent of `rayon`/`simd`, and `tracing`
47//! only adds observability; none of these features change the numerical
48//! results, only performance and instrumentation.
49//!
50//! # Minimum supported Rust version
51//!
52//! The default (stable) build requires Rust **1.88** or newer, as
53//! declared by `rust-version` in `Cargo.toml`. The optional `simd`
54//! feature uses `portable_simd` and therefore requires a **nightly**
55//! toolchain; every other feature builds on stable.
56//!
57//! The ChESS idea is proposed in Bennett, Lasenby, *ChESS: A Fast and
58//! Accurate Chessboard Corner Detector*, CVIU 2014.
59
60mod detect;
61mod imageview;
62mod orientation;
63mod params;
64mod refine;
65
66/// Low-level ChESS detection parameters consumed by the response and
67/// detection stages. The `chess-corners` facade lowers its
68/// `DetectorConfig` onto this type; depend on it directly when driving
69/// the response and detection stages without going through the facade.
70pub use crate::params::ChessParams;
71
72pub use crate::detect::chess::response::{chess_response_u8, chess_response_u8_patch, Roi};
73pub use crate::detect::dense::{ChessBuffers, ChessDetector, DenseDetector, RadonDetector};
74pub use crate::detect::radon::primitives::PeakFitMode;
75pub use crate::detect::radon::{
76 detect_peaks_from_radon, radon_response_u8, RadonBuffers, RadonDetectorParams,
77 RadonResponseView,
78};
79pub use crate::detect::{
80 detect_corners_from_response, detect_corners_from_response_with_refiner,
81 detect_peaks_from_response_with_refine_radius, find_corners_u8, merge_corners_simple,
82 refine_corners_on_image, AxisEstimate, Corner, CornerDescriptor,
83};
84pub use crate::orientation::{
85 describe_corners, fit_axes_at_point, AxisFitResult, OrientationMethod,
86};
87pub use crate::refine::{
88 CenterOfMassConfig, CenterOfMassRefiner, CornerRefiner, ForstnerConfig, ForstnerRefiner,
89 RefineContext, RefineResult, RefineStatus, Refiner, RefinerKind, SaddlePointConfig,
90 SaddlePointRefiner,
91};
92pub use imageview::ImageView;
93
94/// Dense response map in row-major layout.
95#[derive(Clone, Debug, Default)]
96pub struct ResponseMap {
97 pub(crate) w: usize,
98 pub(crate) h: usize,
99 pub(crate) data: Vec<f32>,
100}
101
102impl ResponseMap {
103 /// Create a new response map. `data` must have exactly `w * h` elements.
104 ///
105 /// # Panics
106 ///
107 /// Panics if `data.len() != w * h`.
108 pub fn new(w: usize, h: usize, data: Vec<f32>) -> Self {
109 assert_eq!(data.len(), w * h, "ResponseMap data length mismatch");
110 Self { w, h, data }
111 }
112
113 /// Width of the response map.
114 #[inline]
115 pub fn width(&self) -> usize {
116 self.w
117 }
118
119 /// Height of the response map.
120 #[inline]
121 pub fn height(&self) -> usize {
122 self.h
123 }
124
125 /// Raw response data in row-major order.
126 #[inline]
127 pub fn data(&self) -> &[f32] {
128 &self.data
129 }
130
131 /// Mutable access to the raw response data.
132 #[inline]
133 pub fn data_mut(&mut self) -> &mut [f32] {
134 &mut self.data
135 }
136
137 #[inline]
138 /// Response value at an integer coordinate.
139 pub fn at(&self, x: usize, y: usize) -> f32 {
140 self.data[y * self.w + x]
141 }
142}