chess_corners/config/chess.rs
1use chess_corners_core::{CenterOfMassConfig, ForstnerConfig, SaddlePointConfig};
2use serde::{Deserialize, Serialize};
3
4// ---------------------------------------------------------------------------
5// Detector kernel / ring selection
6// ---------------------------------------------------------------------------
7
8/// ChESS sampling ring radius. Selects the `r=5` (canonical) or `r=10`
9/// (broad) ring used by the dense response kernel.
10#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
11#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
12#[serde(rename_all = "snake_case")]
13#[non_exhaustive]
14pub enum ChessRing {
15 /// Paper-default radius-5 ring (16 samples).
16 #[default]
17 Canonical,
18 /// Radius-10 ring. Larger support window for callers that want the
19 /// detector to sample farther from the candidate center.
20 Broad,
21}
22
23// ---------------------------------------------------------------------------
24// Refiner enum
25// ---------------------------------------------------------------------------
26
27/// Subpixel refiner selection for the ChESS detector.
28///
29/// Each variant carries its own tuning struct as a payload: there is
30/// no shared discriminator + parallel-tuning-struct shape, so
31/// switching variants can never leave a stale config field behind.
32#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
33#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
34#[serde(rename_all = "snake_case")]
35#[non_exhaustive]
36pub enum ChessRefiner {
37 /// Center-of-mass (intensity centroid) refinement on the response
38 /// map. Cheapest refiner in the shipped benchmark; the library default.
39 CenterOfMass(CenterOfMassConfig),
40 /// Förstner structure-tensor refinement on the image patch.
41 Forstner(ForstnerConfig),
42 /// Quadratic surface fit at the saddle point.
43 SaddlePoint(SaddlePointConfig),
44 /// ML-backed subpixel refinement. Runs a small ONNX model on a
45 /// normalized intensity patch around each candidate. Requires the
46 /// `ml-refiner` feature.
47 #[cfg(feature = "ml-refiner")]
48 Ml,
49}
50
51impl Default for ChessRefiner {
52 fn default() -> Self {
53 Self::CenterOfMass(CenterOfMassConfig::default())
54 }
55}
56
57impl ChessRefiner {
58 /// Center-of-mass refinement with default tuning.
59 pub fn center_of_mass() -> Self {
60 Self::CenterOfMass(CenterOfMassConfig::default())
61 }
62 /// Förstner structure-tensor refinement with default tuning.
63 pub fn forstner() -> Self {
64 Self::Forstner(ForstnerConfig::default())
65 }
66 /// Saddle-point quadratic fit with default tuning.
67 pub fn saddle_point() -> Self {
68 Self::SaddlePoint(SaddlePointConfig::default())
69 }
70}
71
72// ---------------------------------------------------------------------------
73// Per-strategy config
74// ---------------------------------------------------------------------------
75
76/// Configuration for the ChESS detector branch of [`crate::DetectionStrategy`].
77///
78/// Carries the detector ring choice and the subpixel refiner. The shared
79/// NMS / clustering thresholds ([`crate::DetectionParams`]), multiscale, and
80/// upscale live at the top level of [`crate::DetectorConfig`] and apply to both
81/// strategies. Descriptors always sample at the detector ring radius.
82///
83/// # Common knobs
84///
85/// - [`ring`](ChessConfig::ring) — choose the detector kernel radius.
86/// - [`refiner`](ChessConfig::refiner) — select and configure the
87/// subpixel refinement backend.
88#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
89#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
90#[serde(default)]
91#[non_exhaustive]
92pub struct ChessConfig {
93 /// Detector ring radius. `Canonical` selects the paper's `r=5`,
94 /// `Broad` selects `r=10`. Descriptors sample at this same radius.
95 pub ring: ChessRing,
96 /// Subpixel refiner. Each variant carries its tuning struct.
97 pub refiner: ChessRefiner,
98}
99
100impl Default for ChessConfig {
101 fn default() -> Self {
102 Self {
103 ring: ChessRing::Canonical,
104 refiner: ChessRefiner::default(),
105 }
106 }
107}