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 = 60.0  # ChESS: absolute floor on the raw response (default 30)
cfg.strategy.chess.refiner = chess_corners.ChessRefiner.forstner()

detector = chess_corners.Detector(cfg)
det = detector.detect(img)
print(det.xy.shape, det.xy.dtype)  # (N, 2) float32
if det.angles is not None:
    print(det.angles.shape)        # (N, 2) float32
print(cfg)

Detector(cfg).detect(image) returns a Detections object with named arrays:

  • det.xy(N, 2) float32, subpixel corner positions (x, y) in input pixels
  • det.response(N,) float32, raw detector response at each peak
  • det.angles(N, 2) float32, [axis0_angle, axis1_angle] in radians [0, π), or None when orientation is disabled
  • det.sigmas(N, 2) float32, 1σ uncertainty per axis in radians, or None when orientation is disabled

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.

The orientation fit is the dominant per-corner cost, and it is optional. A pipeline that recovers board geometry from corner positions alone can skip it with cfg.without_orientation(); in that case det.angles and det.sigmas are None.

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 = 60.0  # plain float; ChESS = absolute response floor (default 30), Radon = fraction of per-frame max (default 0.28)
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.detection.nms_radius = 2
cfg.detection.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,
    )
    .with_detection(nms_radius=2, min_cluster_size=2)
)

Refiners are per-detector: ChessRefiner carries one of center_of_mass, forstner, saddle_point, or ml (with the ml-refiner feature). The Radon detector uses its built-in Gaussian peak fit (PeakFitMode); it does not expose a pluggable refiner. The active ChessRefiner 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:

  • 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).

Enums:

  • ChessRing: CANONICAL, BROAD
  • PeakFitMode: PARABOLIC, GAUSSIAN
  • OrientationMethod: RING_FIT, DISK_FIT; disable the fit entirely with cfg.without_orientation() (then det.angles and det.sigmas are None)

ChessRing.BROAD uses the wider radius-10 detector sampling pattern. Descriptors always sample at the detector ring radius.

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",
      "refiner": {
        "forstner": {
          "radius": 3,
          "min_trace": 20.0,
          "min_det": 0.001,
          "max_condition_number": 60.0,
          "max_offset": 2.0
        }
      }
    }
  },
  "threshold": 60.0,
  "detection": { "nms_radius": 3, "min_cluster_size": 1 },
  "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 and setting the shared detection params:

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

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

The published wheel is built with the ml-refiner feature on by default (pip install cannot toggle Cargo features), so ChessRefiner.ml() is always available out of the box. 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-1.0.0.tar.gz (965.3 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-1.0.0-cp310-abi3-win_amd64.whl (6.0 MB view details)

Uploaded CPython 3.10+Windows x86-64

chess_corners-1.0.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (6.9 MB view details)

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

chess_corners-1.0.0-cp310-abi3-macosx_11_0_arm64.whl (5.8 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

File details

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

File metadata

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

File hashes

Hashes for chess_corners-1.0.0.tar.gz
Algorithm Hash digest
SHA256 9d89329304dfa71fc6f5c63cc16056bb780c999c4addf1b0099e60354934c50f
MD5 ab5f52e8c7e0551e309b0dff08b07e40
BLAKE2b-256 0f0fd6222ed8436eedbbe06d2b72ef60abf49de4250b5827ca092985e54fc600

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_corners-1.0.0.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-1.0.0-cp310-abi3-win_amd64.whl.

File metadata

File hashes

Hashes for chess_corners-1.0.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 7d204b6b0e1d512d4f3176bac5774969a26a7bf732f479a8af0148de56810bdb
MD5 4ab632db6306b82b4ac62f7c91292112
BLAKE2b-256 48d37019951bd53e898db8b5b992e30ad46edc9244626f141288cdb93824d040

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_corners-1.0.0-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-1.0.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for chess_corners-1.0.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a60d53db973297677a642e0d6b8cdd25ce44ac9acda6a8a6c58c1b4cc89dc61d
MD5 dde67b590b95ef5871aa88cc70f137d3
BLAKE2b-256 5e623de3d4400430acb35337d98a2db15ee12b954113c5aac9bc51fa5e7183ac

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_corners-1.0.0-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-1.0.0-cp310-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for chess_corners-1.0.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 138a55144c6938daf00adc5d0b823e69f7e8a802d2b73d80a692e47b4af35fbd
MD5 ff5ab7e1c2eea48d2c1b1dc43536f8ee
BLAKE2b-256 2d56bc45892c90692b59507a2191dd6998ac940e31ee7668a5bf7b238398820d

See more details on using hashes here.

Provenance

The following attestation bundles were made for chess_corners-1.0.0-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