chess-corners
Ergonomic chessboard corner detector on top of chess-corners-core.
This crate is the public Rust API:
- strategy-typed
DetectorConfig(DetectionStrategy::Chess(ChessConfig)/DetectionStrategy::Radon(RadonConfig)) with a single numericthresholdand per-ChESS-detector refiner selection (ChessRefiner) - top-level
MultiscaleConfig(SingleScale | Pyramid { ... }) andUpscaleConfig(Disabled | Fixed(factor)), honoured by both detectors symmetrically - single-scale and coarse-to-fine multiscale detection through a single
Detectorstruct that reuses pyramid and scratch buffers across frames - optional
image::GrayImagehelpers - optional CLI binary and ML-backed refinement pipeline
chess-corners-core and box-image-pyramid remain available as
lower-level sharp tools, but chess-corners is the intended
compatibility boundary.
Quick start
use ;
use ImageReader;
Detector owns the pyramid and upscale scratch buffers, so calling
detector.detect(&img) repeatedly on successive frames does not
re-allocate.
Presets
| Preset | Detector | Scale |
|---|---|---|
DetectorConfig::chess() |
ChESS | Single-scale |
DetectorConfig::chess_multiscale() |
ChESS | 3-level pyramid |
DetectorConfig::radon() |
Radon | Single-scale |
DetectorConfig::radon_multiscale() |
Radon | 3-level pyramid |
Use chess() and chess_multiscale() for single-scale and multiscale
ChESS detection respectively.
Public config shape
DetectorConfig groups detector-specific tuning under a typed
DetectionStrategy enum and shares cross-cutting fields at the top
level:
use ;
let cfg = chess
.with_threshold // ChESS: absolute floor on the raw response (default 30)
.with_merge_radius
.with_multiscale
.with_upscale
.with_chess
.with_detection;
// Or switch to the Radon strategy:
let cfg = cfg.with_radon;
Three guarantees follow from this shape:
- One place per knob.
cfg.strategy.chess.ring = ChessRing::Broadis the only way to request the wider ChESS ring. - Per-detector refiners.
ChessRefinerlists the refiners that operate on ChESS output. The Radon detector uses its built-in Gaussian peak fit (RadonConfig.peak_fit), not a pluggable refiner. - Symmetric encoding.
MultiscaleConfig,UpscaleConfig, andChessRefineruse the same enum-with-payload shape, so the JSON and binding surface stays uniform. (thresholdis a plain number, so it carries no tag.)
Descriptor output
Each detection is a CornerDescriptor with:
x,y— subpixel position.response— raw unnormalized detector response (the ChESS paper's score for ChESS,(max α S_α − min α S_α)²for Radon).axes—Some([axis0, axis1])carries the two local grid axes with per-axis 1σ angular uncertainty from the Gauss-Newton covariance (σθᵢ = √((SSR / 12) · (JᵀJ)⁻¹[i,i])). Axes are not assumed orthogonal;axis0.angle ∈ [0, π)andaxis1.angle ∈ (axis0.angle, axis0.angle + π), with the CCW arc between them spanning a dark sector. It isNonewhen the orientation fit is disabled.
The orientation fit is the dominant per-corner cost. If a downstream
stage recovers board geometry from corner positions alone, disable it
with DetectorConfig::without_orientation(): detection still runs and
every descriptor's axes comes back None.
Refiner configuration
ChessRefiner is a tagged enum; each variant carries its tuning struct
as a payload, so switching kinds cannot leave a stale per-refiner config
behind:
use ;
let cfg = chess.with_chess;
The Radon detector does not have a pluggable refiner. Its subpixel step
is the built-in 3-point Gaussian peak fit, selected via
RadonConfig.peak_fit (PeakFitMode::Parabolic or Gaussian).
CLI config shape
The CLI uses the same DetectorConfig schema, combined with
application fields such as image, output_json, output_png,
log_level, and ml.
See:
config/chess_algorithm_config_example.jsonfor the pureDetectorConfigshape (round-trips through the Rust and Python APIs).config/chess_cli_config_example.jsonfor a complete CLI runner input (algorithm config + envelope).
ML refiner
Enable the ml-refiner feature, then pick the Ml variant on the
ChESS strategy's refiner:
#
#
The ML path is slower than the classic refiners in the shipped benchmark and falls back to the classic CenterOfMass refiner at coarse pyramid levels.
Examples
- Single-scale:
cargo run -p chess-corners --example single_scale_image -- testimages/mid.png - Multiscale:
cargo run -p chess-corners --example multiscale_image -- testimages/large.png
Feature flags
image(default):image::GrayImageintegrationrayon: parallel response/refinementsimd: optional high-performance path — portablestd::simdin the core response path (nightly only)par_pyramid: SIMD/rayonin pyramid constructiontracing: structured spansml-refiner: ONNX-backed ML refinementcli: build thechess-cornersbinary
The stable scalar/autovectorized build is the supported, portable
baseline — correct and fast enough for typical use. It requires Rust
1.88 or newer (rust-version in Cargo.toml). The simd feature
uses std::simd and is the only feature that needs a nightly
toolchain; every other feature builds on stable.