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.0.tar.gz (952.8 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.0-cp310-abi3-win_amd64.whl (6.0 MB view details)

Uploaded CPython 3.10+Windows x86-64

chess_corners-0.11.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-0.11.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-0.11.0.tar.gz.

File metadata

  • Download URL: chess_corners-0.11.0.tar.gz
  • Upload date:
  • Size: 952.8 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.0.tar.gz
Algorithm Hash digest
SHA256 c9740c6345f6bb45e99c7ac630071fac29ce7a14161d777e9e0dcdf31caee6a8
MD5 e8badf60cdc5c2fe7a1b744c9cc8b14b
BLAKE2b-256 a4bc94425f71c1e9ba2ebae780d7ff1496aee0af59326c8f2cfa760d2a5cdf8c

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for chess_corners-0.11.0-cp310-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 0cfbfc39afb3ad8aaa7fa6e7c80b804cc0f53681f636a485ea59e987d307f867
MD5 1998af56f5bbd7f3b0f78c114c6c8c80
BLAKE2b-256 aba8a70fee5e5ae963efd54bcd5d05c65fca22191bc36acfd678ec472afbf7a7

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for chess_corners-0.11.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 e32dfce68fd9339e25ccb0fcc65e322d0457e02444044dc486535ce16000e69b
MD5 d8ddbd2375fcd91916bc196755ca9288
BLAKE2b-256 dbcd24bc951f26a6282076284dcafb2f1ec6c1fe8a46f3b4a597b06e74f49b83

See more details on using hashes here.

Provenance

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

File metadata

File hashes

Hashes for chess_corners-0.11.0-cp310-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 c601b17dc0f5654e5bb83e3b216545819018e5f4c500cb6dccbf49dd1fa59319
MD5 e75104e437a2c4281a6b4da90ee1ff40
BLAKE2b-256 142660e68c4602d024993361380ee657cce4eeeed904385fd01f4cd3399448ed

See more details on using hashes here.

Provenance

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