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