Skip to main content

Crate chess_corners

Crate chess_corners 

Source
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, Threshold};
use image::io::Reader as ImageReader;

let img = ImageReader::open("board.png")?
    .decode()?
    .to_luma8();

let cfg = DetectorConfig::chess_multiscale()
    .with_threshold(Threshold::Relative(0.15))
    .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 {
    println!(
        "corner at ({:.2}, {:.2}), response {:.1}, axes [{:.2}, {:.2}] rad",
        c.x, c.y, c.response, c.axes[0].angle, c.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 a chess_corners.Detector class whose detect(image) method accepts a 2D uint8 NumPy array and returns a float32 (N, 9) array with columns [x, y, response, contrast, fit_rms, axis0_angle, axis0_sigma, axis1_angle, axis1_sigma]. 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-corners npm package.

§Configuration

DetectorConfig is strategy-typed: the DetectorConfig::strategy field is a DetectionStrategy enum carrying either a ChessConfig (detector ring, descriptor ring, NMS, refiner) or a RadonConfig (whole-image Duda-Frese parameters). Acceptance is a single Threshold enum (Absolute or Relative). MultiscaleConfig and UpscaleConfig live at the top level and apply to both strategies. The detector translates this into lower-level parameter structs internally; those structs (ChessParams, RadonDetectorParams) are exposed for hand-composed pipelines in low_level.

Two opt-in channels sit alongside the primary Detector API for callers who need more than a finished detection result. The curated low-level surface for hand-composing the detection pipeline (response -> detect -> describe), including its parameter structs and scratch buffers, lives in low_level; intermediate response maps and Radon heatmaps for debugging and visualization live in diagnostics. Both carry a weaker stability promise than the facade root and are not needed by typical consumers. For deeper internals (ring offsets, SAT views, scalar reference paths) depend on chess-corners-core directly.

§Features

  • image (default) – enables Detector::detect and image::GrayImage integration.
  • rayon – parallelizes response computation and multiscale refinement over image rows. Combine with par_pyramid to parallelize pyramid downsampling as well.
  • ml-refiner – enables the ML-backed refiner entry points via the chess-corners-ml crate and embedded ONNX model.
  • simd – enables portable-SIMD accelerated inner loops for the response kernel (requires a nightly compiler). Combine with par_pyramid to SIMD-accelerate pyramid downsampling.
  • par_pyramid – opt-in gate for SIMD/rayon acceleration inside the pyramid builder.
  • tracing – emits structured spans for multiscale detection, suitable for use with tracing-subscriber or JSON tracing from the CLI.
  • cli – builds the chess-corners binary 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.

§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.
low_level
Deliberate escape hatch for callers hand-composing the detection pipeline.

Structs§

AxisEstimate
Direction of one local grid axis with its 1σ angular uncertainty.
CenterOfMassConfig
Configuration for the CenterOfMassRefiner.
ChessConfig
Configuration for the ChESS detector branch of DetectionStrategy.
CornerDescriptor
Describes a detected chessboard corner in full-resolution image coordinates.
Detector
High-level chessboard-corner detector.
DetectorConfig
High-level detection configuration.
ForstnerConfig
Configuration for the ForstnerRefiner.
RadonConfig
Configuration for the whole-image Radon detector branch of DetectionStrategy.
RadonPeakConfig
Configuration for RadonPeakRefiner.
SaddlePointConfig
Configuration for the SaddlePointRefiner.

Enums§

ChessError
Errors returned by detection and heatmap entry points.
ChessRefiner
Subpixel refiner selection for the ChESS detector.
ChessRing
ChESS sampling ring radius. Selects the r=5 (canonical) or r=10 (broad) ring used by the dense response kernel.
DescriptorRing
Descriptor sampling ring selection. Independent of the detector ring chosen by ChessRing.
DetectionStrategy
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.
MultiscaleConfig
Coarse-to-fine multiscale configuration.
OrientationMethod
Method used to fit the two grid axes at a detected corner.
PeakFitMode
Subpixel peak-fitting mode.
RadonRefiner
Subpixel refiner selection for the whole-image Radon detector.
Threshold
Detector acceptance threshold.
UpscaleConfig
Optional pre-pipeline integer-factor upscaling.
UpscaleError
Errors returned by upscaling setup or execution.