Skip to main content

chess_corners/config/
radon.rs

1use chess_corners_core::{PeakFitMode, RadonDetectorParams};
2use serde::{Deserialize, Serialize};
3
4/// Configuration for the whole-image Radon detector branch of
5/// [`crate::DetectionStrategy`].
6///
7/// All radii and counts are in **working-resolution** pixels (i.e.
8/// after `image_upsample`). The shared NMS / clustering thresholds
9/// ([`crate::DetectionParams`]), multiscale, and upscale live at the top level
10/// of [`crate::DetectorConfig`] and apply to both strategies.
11///
12/// # Common knobs
13///
14/// - [`image_upsample`](RadonConfig::image_upsample) — `2` (the default)
15///   reproduces the paper's 2× supersampled detection; `1` is faster but
16///   less accurate on low-resolution inputs.
17///
18/// # Advanced tuning
19///
20/// The remaining fields control low-level detection behaviour. The
21/// defaults reproduce the paper's recommended settings and work well
22/// for typical camera images. Adjust them only when you have a specific
23/// reason (e.g. a non-standard image resolution or SNR budget).
24#[derive(Clone, Copy, Debug, PartialEq, Serialize, Deserialize)]
25#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
26#[serde(default)]
27#[non_exhaustive]
28pub struct RadonConfig {
29    /// Advanced tuning. Half-length of each Radon ray, in
30    /// working-resolution pixels (integer `>= 1`; the ray has
31    /// `2·ray_radius + 1` samples). Paper default at `image_upsample = 2`
32    /// is `4`. Shorter rays are faster but integrate less signal; longer
33    /// rays are more discriminating but may cross into neighbouring cells.
34    #[cfg_attr(feature = "schemars", schemars(range(min = 1)))]
35    #[cfg_attr(feature = "schemars", schemars(extend("x-unit" = "px")))]
36    pub ray_radius: u32,
37    /// Image-level supersampling factor applied before ray integration
38    /// (`1` or `2`). `1` operates on the input grid; `2` (paper default)
39    /// bilinearly upsamples the input first, giving sub-pixel ray
40    /// positioning. The core detector clamps values outside `1..=2`.
41    #[cfg_attr(feature = "schemars", schemars(range(min = 1, max = 2)))]
42    pub image_upsample: u32,
43    /// Advanced tuning. Half-size of the box blur applied to the Radon
44    /// response map after integration, in working-resolution pixels
45    /// (integer `>= 0`). `0` disables blurring; the default `1` yields a
46    /// 3×3 box that smooths quantisation noise.
47    #[cfg_attr(feature = "schemars", schemars(extend("x-unit" = "px")))]
48    pub response_blur_radius: u32,
49    /// Advanced tuning. Peak-fit mode for the 3-point subpixel
50    /// refinement of the response-map argmax. `Gaussian` (default) fits
51    /// on log-response (more accurate near the peak); `Parabolic` fits
52    /// directly on the response values. See [`PeakFitMode`].
53    pub peak_fit: PeakFitMode,
54}
55
56impl Default for RadonConfig {
57    fn default() -> Self {
58        // Single source of truth: mirror `RadonDetectorParams::default()`
59        // (chess-corners-core) rather than restating the paper defaults here.
60        let core_defaults = RadonDetectorParams::default();
61        Self {
62            ray_radius: core_defaults.ray_radius,
63            image_upsample: core_defaults.image_upsample,
64            response_blur_radius: core_defaults.response_blur_radius,
65            peak_fit: core_defaults.peak_fit,
66        }
67    }
68}