Skip to main content

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.

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.1.0.tar.gz (963.2 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.1.0-cp310-abi3-win_amd64.whl (9.1 MB view details)

Uploaded CPython 3.10+Windows x86-64

chess_corners-1.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (10.4 MB view details)

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

chess_corners-1.1.0-cp310-abi3-macosx_11_0_arm64.whl (9.0 MB view details)

Uploaded CPython 3.10+macOS 11.0+ ARM64

File details

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

File metadata

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

File hashes

Hashes for chess_corners-1.1.0.tar.gz
Algorithm Hash digest
SHA256 e36bd4a3e21840897971435d4413e3eb79e14b22f119709375df1a8b4e828056
MD5 82d4cb3c3ecd7e01020f7af4496bf21b
BLAKE2b-256 ff9fead8a9fa8e29707e11ba3fef9ee267488b43c216525902c4a315ebf6aecb

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for chess_corners-1.1.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 d920112c37aead1411cc48e3c0670dff780e30b7f10c588ca0c8cb1910c8fe1a
MD5 34f74bf711ff9cc74f5e736724ab512f
BLAKE2b-256 22f5f3df76bd99025c19dff156f8fb8c24755471768f18aec0f71651b301b478

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for chess_corners-1.1.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 1f7c964aa0c5fd3d465191f5164c2b4d3f21747a53c6c768bae53fcdc21df16c
MD5 05e096aad7f8638c33cc25c0dea297de
BLAKE2b-256 3a12d9b828996f91cc06b8c839f4c0f7b13ab47b4b567178d78cce2174223994

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for chess_corners-1.1.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 10b061f79e54c3b9ecf87cb29631fe852d22ec9ef315db7fa676077a011e33a3
MD5 5447db350a4c0c9000e0f6b1a60684a2
BLAKE2b-256 8388bc894a2aaa55b74abf964e02d2f50e4173fb2bac107dc9baa3e265338757

See more details on using hashes here.

Provenance

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

Release history Release notifications | RSS feed

1.2.0

4 files

This release

1.1.0 This release

4 files

1.0.0

4 files

0.11.2

4 files

0.11.0

4 files

0.10.0

4 files

0.9.0

4 files

0.8.0

4 files

0.7.0

4 files

0.6.0

4 files

0.5.0

4 files

0.4.2

4 files

0.4.1

4 files

0.4.0

4 files

0.3.2

4 files

0.3.1

4 files

0.3.0

4 files

0.1.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page