chess_corners (Python)
Python-first bindings for the chess-corners detector.
The installed package is a mixed Rust/Python package:
chess_cornersis a pure-Python public API with type hints, docstrings, JSON helpers, and readable config objects.chess_corners._nativeis 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 pixelsdet.response—(N,)float32, raw detector response at each peakdet.angles—(N, 2)float32,[axis0_angle, axis1_angle]in radians[0, π), orNonewhen orientation is disableddet.sigmas—(N, 2)float32, 1σ uncertainty per axis in radians, orNonewhen 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:
imagemust be a 2Duint8NumPy 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=); readcfg.multiscale.kindand (whenpyramid)levels,min_size,refinement_radius.UpscaleConfig:UpscaleConfig.disabled()/UpscaleConfig.fixed(factor); readcfg.upscale.kindand (whenfixed)factor.ChessRefiner:center_of_mass(),forstner(),saddle_point(),ml()(with theml-refinerfeature).
Enums:
ChessRing:CANONICAL,BROADPeakFitMode:PARABOLIC,GAUSSIANOrientationMethod:RING_FIT,DISK_FIT; disable the fit entirely withcfg.without_orientation()(thendet.anglesanddet.sigmasareNone)
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.
Metadata
Release files for chess-corners 1.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| chess_corners-1.3.0.tar.gz | 972.1 kB | Details |
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| chess_corners-1.3.0-cp310-abi3-win_amd64.whl | CPython 3.10 | abi3 | Windows x86-64 | Details |
| chess_corners-1.3.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl | CPython 3.10 | abi3 | Linux glibc 2.17+ x86-64 | Details |
| chess_corners-1.3.0-cp310-abi3-macosx_11_0_arm64.whl | CPython 3.10 | abi3 | macOS 11.0+ ARM64 | Details |
Total release size: 29.6 MB
Release files / chess_corners-1.3.0.tar.gz
| Download URL | chess_corners-1.3.0.tar.gz |
|---|---|
| Size | 972.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2402df4925305190e7b295bc53da965a58e259bdf971e587a3d9c5a408317aaf
|
|
BLAKE2b-256 checksum How to use checksums |
886f3b388e4cbd1354b618629342b17970f77fae65bbe936b1cca236e5c55bad
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / chess_corners-1.3.0-cp310-abi3-win_amd64.whl
| Download URL | chess_corners-1.3.0-cp310-abi3-win_amd64.whl |
|---|---|
| Size | 9.2 MB |
| Tags | CPython 3.10 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
e4a0ec0a5b505e5c7772d9883aa5a3ac9b6c9c714dc6034f9442537561c937df
|
|
BLAKE2b-256 checksum How to use checksums |
6a36793e817b885649e09348398d983cbe0c3da16c0917bfc78f69e2701def07
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / chess_corners-1.3.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
| Download URL | chess_corners-1.3.0-cp310-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl |
|---|---|
| Size | 10.4 MB |
| Tags | CPython 3.10 Linux glibc 2.17+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
96c249d1341dfa77508ca4be1ce26d0fea1eb8692addd11246a853c5b5693e09
|
|
BLAKE2b-256 checksum How to use checksums |
e672fe2f8c8df6feccf887131bbb25bb281e467c9943b9e86f73f429ccd03f31
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency logRelease files / chess_corners-1.3.0-cp310-abi3-macosx_11_0_arm64.whl
| Download URL | chess_corners-1.3.0-cp310-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 9.0 MB |
| Tags | CPython 3.10 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
3036c4ec1a0d694a036583026e107fad53c918127673e7682e1ec4a32ea91ce1
|
|
BLAKE2b-256 checksum How to use checksums |
86358c0f08bf4b04c84d5ba5778c595b9b5c3936cfdcc575335e133d997836d3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 3, 2026.
Transparency log