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}