Skip to main content

Python bindings for the fast ChESS chessboard corner detector (Rust backend)

Project description

chess_corners (Python)

Python-first bindings for the chess-corners detector.

The installed package is a mixed Rust/Python package:

  • chess_corners is a pure-Python public API with type hints, docstrings, JSON helpers, and readable config objects.
  • chess_corners._native is the private PyO3 extension module that runs the detector.

Quick start

import numpy as np
import chess_corners

img = np.zeros((128, 128), dtype=np.uint8)

cfg = chess_corners.DetectorConfig.chess_multiscale()
cfg.threshold = chess_corners.Threshold.relative(0.15)
cfg.strategy.chess.refiner = chess_corners.ChessRefiner.forstner()

detector = chess_corners.Detector(cfg)
corners = detector.detect(img)
print(corners.shape, corners.dtype)
print(cfg)

Detector(cfg).detect(image) returns a NumPy float32 array of shape (N, 9) with columns:

  1. x — subpixel corner x in input pixels
  2. y — subpixel corner y in input pixels
  3. response — raw detector response at the detected peak
  4. contrast — amplitude of the fitted bright/dark structure
  5. fit_rms — RMS residual of the two-axis intensity fit (gray levels)
  6. axis0_angle — angle of the first local grid axis, radians in [0, π)
  7. axis0_sigma — 1σ uncertainty of axis0_angle, radians
  8. axis1_angle — angle of the second local grid axis, radians in (axis0_angle, axis0_angle + π)
  9. axis1_sigma — 1σ uncertainty of axis1_angle, radians

Rotating CCW from axis0_angle toward axis1_angle (by less than π) traverses a dark sector of the corner; the two grid axes are not assumed to be orthogonal, so this output correctly captures projective warp and lens distortion.

Input requirements:

  • image must be a 2D uint8 NumPy array with shape (H, W)
  • it must be C-contiguous

The rows are sorted deterministically by response descending, then x, then y.

Public config API

DetectorConfig is strategy-typed: detector-specific tuning lives inside a DetectionStrategy variant. Top-level fields are threshold, multiscale, upscale, orientation_method, and merge_radius.

cfg = chess_corners.DetectorConfig.chess()  # ChESS, no pyramid
cfg.threshold = chess_corners.Threshold.relative(0.2)
cfg.merge_radius = 3.0

# Enable the coarse-to-fine pyramid (both detectors honour this):
cfg.multiscale = chess_corners.MultiscaleConfig.pyramid(
    levels=3, min_size=128, refinement_radius=3,
)

# Detector-specific knobs live inside the strategy. Nested getters
# return the live shared object, so direct attribute assignment
# propagates back to `cfg` — no rebuild needed:
cfg.strategy.chess.ring = chess_corners.ChessRing.BROAD
cfg.strategy.chess.descriptor_ring = chess_corners.DescriptorRing.FOLLOW_DETECTOR
cfg.strategy.chess.nms_radius = 2
cfg.strategy.chess.min_cluster_size = 2

# Switch the active strategy by assigning a new one:
cfg.strategy = chess_corners.DetectionStrategy.from_radon(
    chess_corners.RadonConfig()
)

For one-shot configuration, the chainable with_chess(**kwargs) / with_radon(**kwargs) builders return a new config with only the named fields replaced:

cfg = (
    chess_corners.DetectorConfig.chess_multiscale()
    .with_chess(
        refiner=chess_corners.ChessRefiner.forstner(),
        ring=chess_corners.ChessRing.BROAD,
        nms_radius=2,
    )
)

Refiners are per-detector: ChessRefiner carries one of center_of_mass, forstner, saddle_point, or ml (with the ml-refiner feature). RadonRefiner carries one of radon_peak or center_of_mass. The active variant's tuning is reachable via the payload property:

fcfg = chess_corners.ForstnerConfig()
fcfg.max_offset = 2.0
cfg.strategy.chess.refiner = chess_corners.ChessRefiner.forstner(fcfg)

assert cfg.strategy.chess.refiner.kind == "forstner"
assert cfg.strategy.chess.refiner.payload.max_offset == 2.0

Tagged classes:

  • Threshold: Threshold.absolute(value) / Threshold.relative(frac); read cfg.threshold.kind and cfg.threshold.value.
  • MultiscaleConfig: MultiscaleConfig.single_scale() / MultiscaleConfig.pyramid(levels=, min_size=, refinement_radius=); read cfg.multiscale.kind and (when pyramid) levels, min_size, refinement_radius.
  • UpscaleConfig: UpscaleConfig.disabled() / UpscaleConfig.fixed(factor); read cfg.upscale.kind and (when fixed) factor.
  • ChessRefiner: center_of_mass(), forstner(), saddle_point(), ml() (with the ml-refiner feature).
  • RadonRefiner: radon_peak(), center_of_mass().

Enums:

  • ChessRing: CANONICAL, BROAD
  • DescriptorRing: FOLLOW_DETECTOR, CANONICAL, BROAD
  • PeakFitMode: PARABOLIC, GAUSSIAN
  • OrientationMethod: RING_FIT, DISK_FIT

ChessRing.BROAD uses the wider radius-10 detector sampling pattern. Leave descriptor_ring at FOLLOW_DETECTOR unless you have a reason to override descriptor sampling separately.

JSON helpers and printing

Every public config object supports:

  • to_dict()
  • from_dict(...)
  • to_json()
  • from_json(...)
  • pretty()
  • print()

Example:

cfg = chess_corners.DetectorConfig.chess_multiscale()
text = cfg.to_json(indent=2)
restored = chess_corners.DetectorConfig.from_json(text)

print(restored)
restored.print()

If rich is installed, .print() uses it automatically and the config objects also expose a Rich render hook.

Canonical JSON schema

The same algorithm config schema is used by Rust, Python, docs, and the CLI:

{
  "strategy": {
    "chess": {
      "ring": "broad",
      "descriptor_ring": "canonical",
      "nms_radius": 3,
      "min_cluster_size": 1,
      "refiner": {
        "forstner": {
          "radius": 3,
          "min_trace": 20.0,
          "min_det": 0.001,
          "max_condition_number": 60.0,
          "max_offset": 2.0
        }
      }
    }
  },
  "threshold": { "absolute": 0.5 },
  "multiscale": {
    "pyramid": {
      "levels": 3,
      "min_size": 96,
      "refinement_radius": 4
    }
  },
  "upscale": "disabled",
  "orientation_method": "ring_fit",
  "merge_radius": 2.5
}

Switch to the Radon strategy by replacing the strategy object:

"strategy": {
  "radon": {
    "ray_radius": 4,
    "image_upsample": 2,
    "response_blur_radius": 1,
    "peak_fit": "gaussian",
    "nms_radius": 4,
    "min_cluster_size": 2,
    "refiner": { "radon_peak": {} }
  }
}

Unknown keys are rejected with a clear ConfigError.

Example runners

For a complete Pillow-based example that loads the full config from JSON, run:

uv run --python .venv/bin/python python crates/chess-corners-py/examples/run_with_full_config.py \
  testimages/mid.png \
  config/chess_algorithm_config_example.json

For a complete Pillow-based example that defines the entire config directly in Python code and only takes the image path as an argument, run:

uv run --python .venv/bin/python python crates/chess-corners-py/examples/run_with_code_config.py \
  testimages/mid.png

Both examples use Pillow only for image loading:

uv pip install --python .venv/bin/python Pillow

ML refiner

If the bindings are built with the ml-refiner feature, the ML pipeline is selected by passing ChessRefiner.ml() as the active variant on the ChESS strategy. The ML refiner runs a small ONNX model on normalized intensity patches around each candidate.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chess_corners-0.11.2.tar.gz (955.0 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

chess_corners-0.11.2-cp310-abi3-win_amd64.whl (6.1 MB view details)

Uploaded CPython 3.10+Windows x86-64

chess_corners-0.11.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (7.0 MB view details)

Uploaded CPython 3.10+manylinux: glibc 2.17+ x86-64

chess_corners-0.11.2-cp310-abi3-macosx_11_0_arm64.whl (5.9 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

File details

Details for the file chess_corners-0.11.2.tar.gz.

File metadata

  • Download URL: chess_corners-0.11.2.tar.gz
  • Upload date:
  • Size: 955.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for chess_corners-0.11.2.tar.gz
Algorithm Hash digest
SHA256 3ccad1a4050440768e6da24a215fb0d4abfc4fc53a86c3be7eabb501a7cca018
MD5 5ef1a1829e5a93eabdd92a0d797c152a
BLAKE2b-256 a25c06cc2e4e4c8363192015e056f2abb97fbd24d1f186a8904ba81546daa40d

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_corners-0.11.2.tar.gz:

Publisher: release-pypi.yml on VitalyVorobyev/chess-corners-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_corners-0.11.2-cp310-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for chess_corners-0.11.2-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 86460170c76f186f652298226034af385efafd7878f5d08e88125587a491083e
MD5 7e834287383850207cde7f3e75c44312
BLAKE2b-256 25d8d48b2bc0f3f4ac988be6ee199e86cc32195968d09c8c0583debe1d50dbdb

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_corners-0.11.2-cp310-abi3-win_amd64.whl:

Publisher: release-pypi.yml on VitalyVorobyev/chess-corners-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_corners-0.11.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for chess_corners-0.11.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 fc9768bee616bb86251f8681d039f734133ad17993237b2fb8e30a6fe2e1765a
MD5 ced1f527e70777929d2f274c0b3dbd18
BLAKE2b-256 a3f7bcbcc0d4b265c011e741a215c3bb4fefe98a7b2f633826f2e8823d1fe762

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_corners-0.11.2-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: release-pypi.yml on VitalyVorobyev/chess-corners-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chess_corners-0.11.2-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chess_corners-0.11.2-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 0df11fa489aec0b16375f1e9738fa7bfe930460bc6d4bfd7d58478714c26770a
MD5 202eea3e32ee31a0149717999a9fa807
BLAKE2b-256 a020b50cea77620e6e455673a7f0d4b38b565d922f6eaa8a9ddfa687c87ba751

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_corners-0.11.2-cp310-abi3-macosx_11_0_arm64.whl:

Publisher: release-pypi.yml on VitalyVorobyev/chess-corners-rs

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page