Expand description
Ergonomic ChESS / Radon corner-detector facade over
chess-corners-core.
§Overview
This crate is the high-level entry point for two chessboard-corner detectors that share the same output surface:
- ChESS (Chess-board Extraction by Subtraction and Summation) — a dense ring-difference response with NMS and a pluggable subpixel refiner. This is the default path and the fastest preset in the repository’s clean-image benchmark.
- Radon — a whole-image Duda-Frese accumulator that scores corners by summing ray intensities through each pixel. It is useful when the ChESS ring does not produce enough seeds, especially in the small-cell, blur, and low-contrast fixtures covered by the tests.
The Detector struct ties together the active strategy, the
orientation fit, and the multiscale / upscale scratch buffers
behind a single detect call. It returns subpixel
CornerDescriptor values in full-resolution input coordinates.
In most applications you construct a DetectorConfig (typically
via DetectorConfig::chess, DetectorConfig::chess_multiscale,
DetectorConfig::radon, or DetectorConfig::radon_multiscale),
optionally tweak its fields, build a Detector, and call
Detector::detect.
Building a Detector once and calling Detector::detect in a
loop reuses the pyramid, response, and upscale scratch buffers
across frames — no per-frame allocation.
§Quick start
§Using image (default)
The default feature set includes integration with the image
crate. This example reads from disk and is marked no_run:
use chess_corners::{ChessRefiner, Detector, DetectorConfig};
use image::io::Reader as ImageReader;
let img = ImageReader::open("board.png")?
.decode()?
.to_luma8();
let cfg = DetectorConfig::chess_multiscale()
.with_threshold(120.0)
.with_chess(|c| c.refiner = ChessRefiner::forstner());
let mut detector = Detector::new(cfg)?;
let corners = detector.detect(&img)?;
println!("found {} corners", corners.len());
for c in &corners {
// `axes` is `None` when the orientation fit was skipped
// (see `DetectorConfig::without_orientation`).
if let Some(axes) = c.axes {
println!(
"corner at ({:.2}, {:.2}), response {:.1}, axes [{:.2}, {:.2}] rad",
c.x, c.y, c.response, axes[0].angle, axes[1].angle,
);
}
}§Raw grayscale buffer
If you already have an 8-bit grayscale buffer, call
Detector::detect_u8:
use chess_corners::{Detector, DetectorConfig};
// 8×8 black/white checkerboard of 16-pixel squares (128×128).
let mut img = vec![0u8; 128 * 128];
for y in 0..128 {
for x in 0..128 {
if ((x / 16) + (y / 16)) % 2 == 0 {
img[y * 128 + x] = 255;
}
}
}
let cfg = DetectorConfig::chess();
let mut detector = Detector::new(cfg)?;
let corners = detector.detect_u8(&img, 128, 128)?;
assert!(!corners.is_empty());§Radon strategy
Switch to the whole-image Radon detector when ChESS misses corners on
the images you care about. The strategy lives inside
DetectorConfig::strategy; pick a Radon preset to get sensible
defaults:
use chess_corners::{Detector, DetectorConfig};
let mut img = vec![0u8; 128 * 128];
for y in 0..128 {
for x in 0..128 {
if ((x / 16) + (y / 16)) % 2 == 0 {
img[y * 128 + x] = 255;
}
}
}
let cfg = DetectorConfig::radon();
let mut detector = Detector::new(cfg)?;
let corners = detector.detect_u8(&img, 128, 128)?;
assert!(!corners.is_empty());§ML refiner (feature ml-refiner)
Pick the ML pipeline by selecting ChessRefiner::Ml inside the
ChESS strategy. The example is marked no_run because loading the
embedded ONNX model on first use is not appropriate for a doctest:
use chess_corners::{ChessRefiner, Detector, DetectorConfig};
use image::GrayImage;
let cfg = DetectorConfig::chess()
.with_chess(|c| c.refiner = ChessRefiner::Ml);
let img: GrayImage = image::open("board.png").unwrap().to_luma8();
let mut detector = Detector::new(cfg).unwrap();
let corners = detector.detect(&img).unwrap();The ML refiner runs a small ONNX model on normalized intensity
patches (uint8 / 255.0) centered at each candidate. The model
predicts [dx, dy, conf_logit], but the confidence output is
currently ignored; the offsets are applied directly. Current
accuracy benchmarks are synthetic; real-world accuracy still needs
validation. Per-refiner cost is measured in Part VIII §7.6 of the
book. The ML path is slower than the hand-coded refiners and should
be chosen only after measuring that its behavior helps your data.
§Python and JavaScript bindings
The workspace also ships bindings that wrap this facade:
crates/chess-corners-py(PyO3 / maturin) exposes achess_corners.Detectorclass whosedetect(image)method accepts a 2Duint8NumPy array and returns aDetectionsstructure-of-arrays object with named fields:.xy((N, 2)float32),.response((N,)float32),.angles((N, 2)float32, orNonewhen orientation is disabled), and.sigmas((N, 2)float32, orNonewhen orientation is disabled). See its README for usage and configuration details.crates/chess-corners-wasm(wasm-bindgen / wasm-pack) exposes the same surface to JavaScript / TypeScript via the@vitavision/chess-cornersnpm package.
§Configuration
DetectorConfig is strategy-typed: the DetectorConfig::strategy
field is a DetectionStrategy enum carrying either a
ChessConfig (detector ring, refiner) or a RadonConfig
(whole-image Duda-Frese parameters). Acceptance is a single
threshold number — read as an absolute
response floor by ChESS and as a fraction of the per-frame maximum by
Radon. MultiscaleConfig and UpscaleConfig live at the top level
and apply to both strategies. The detector translates this into
lower-level parameter structs internally. To drive those stages
yourself, lower a config with DetectorConfig::chess_params or
DetectorConfig::radon_detector_params and call the stage
functions re-exported from chess-corners-core.
Intermediate response maps and Radon heatmaps for debugging and
visualization live in the opt-in diagnostics module, which
carries a weaker stability promise than the facade root and is not
needed by typical consumers. For deeper internals (ring offsets, SAT
views, scalar reference paths) depend on chess-corners-core
directly.
§Features
image(default) – enablesDetector::detectandimage::GrayImageintegration.rayon– parallelizes response computation and multiscale refinement over image rows. Combine withpar_pyramidto parallelize pyramid downsampling as well.ml-refiner– enables the ML-backed refiner entry points via thechess-corners-mlcrate and embedded ONNX model.simd– enables portable-SIMD accelerated inner loops for the response kernel (requires a nightly compiler). Combine withpar_pyramidto SIMD-accelerate pyramid downsampling.par_pyramid– opt-in gate for SIMD/rayonacceleration inside the pyramid builder.tracing– emits structured spans for multiscale detection, suitable for use withtracing-subscriberor JSON tracing from the CLI.cli– builds thechess-cornersbinary shipped with this crate; it is not required when using the library as a dependency.
The library API is stable across feature combinations; features only affect performance and observability, not numerical results.
§Minimum supported Rust version
The default (stable) build requires Rust 1.88 or newer, as
declared by rust-version in Cargo.toml. The optional simd
feature uses portable_simd and therefore requires a nightly
toolchain; every other feature builds on stable.
§References
- Bennett, Lasenby. ChESS: A Fast and Accurate Chessboard Corner Detector. CVIU 2014.
- Duda, Frese. Accurate Detection and Localization of Checkerboard Corners for Calibration. BMVC 2018.
Modules§
- diagnostics
- Opt-in diagnostic channel for inspecting how a detection was produced.
Structs§
- Axis
Estimate - Direction of one local grid axis with its 1σ angular uncertainty.
- Center
OfMass Config - Configuration for the
CenterOfMassRefiner. - Chess
Config - Configuration for the ChESS detector branch of
crate::DetectionStrategy. - Corner
Descriptor - Describes a detected chessboard corner in full-resolution image coordinates.
- Detection
Params - Shared non-maximum-suppression and peak-clustering thresholds.
- Detector
- High-level chessboard-corner detector.
- Detector
Config - High-level detection configuration.
- Forstner
Config - Configuration for the
ForstnerRefiner. - Radon
Config - Configuration for the whole-image Radon detector branch of
crate::DetectionStrategy. - Saddle
Point Config - Configuration for the
SaddlePointRefiner. - Upscale
Buffers - Optional pre-pipeline integer bilinear upscaling stage. These are the
raw stage primitives behind
UpscaleConfig;Detectorapplies the stage automatically, so they are only needed when composing the pipeline by hand. Reusable scratch buffer for the upscaling stage.
Enums§
- Chess
Error - Errors returned by detection and heatmap entry points.
- Chess
Refiner - Subpixel refiner selection for the ChESS detector.
- Chess
Ring - ChESS sampling ring radius. Selects the
r=5(canonical) orr=10(broad) ring used by the dense response kernel. - Detection
Strategy - Top-level detector dispatch. Selects between the ChESS kernel pipeline and the Radon whole-image detector. The chosen variant carries all detector-specific tuning; settings that don’t apply to the active detector are simply unreachable, so the type system enforces correctness instead of silently ignoring fields.
- Multiscale
Config - Coarse-to-fine multiscale configuration.
- Orientation
Method - Method used to fit the two grid axes at a detected corner.
- Peak
FitMode - Subpixel peak-fitting mode.
- Upscale
Config - Optional pre-pipeline integer bilinear upscaling stage. These are the
raw stage primitives behind
UpscaleConfig;Detectorapplies the stage automatically, so they are only needed when composing the pipeline by hand. Optional pre-pipeline integer-factor upscaling. - Upscale
Error - Optional pre-pipeline integer bilinear upscaling stage. These are the
raw stage primitives behind
UpscaleConfig;Detectorapplies the stage automatically, so they are only needed when composing the pipeline by hand. Errors returned by upscaling setup or execution.
Functions§
- rescale_
descriptors_ to_ input - Optional pre-pipeline integer bilinear upscaling stage. These are the
raw stage primitives behind
UpscaleConfig;Detectorapplies the stage automatically, so they are only needed when composing the pipeline by hand. Rescale corner positions from an upscaled image back to the original input-image pixel frame. - upscale_
bilinear_ u8 - Optional pre-pipeline integer bilinear upscaling stage. These are the
raw stage primitives behind
UpscaleConfig;Detectorapplies the stage automatically, so they are only needed when composing the pipeline by hand. Bilinear upscaling by an integer factor into the provided buffer.