locus-tag
Locus detects AprilTag and ArUco markers as well as AprilGrid and ChArUco boards. The library is implemented in Rust and provides zero-copy Python bindings.
[!WARNING] Experimental Status: API is subject to breaking changes until 1.0.0 ships. The main workstreams towards 1.0.0 are reducing the API surface and validating against non-synthetic data. Until then, this library isn't recommended for production systems. The support for distortion models is experimental and requires a ground-up redesign. Addition of default tag families may happen on request, the current defaults were chosen to be minimal and support most commonly used tags.
Technical Capabilities
- Zero-Copy Ingestion: Accesses NumPy arrays via the Python Buffer Protocol.
- Parallel Execution: Releases the Python GIL during detection to allow multi-threaded use.
- Vectorized Results: Returns a
DetectionBatchwith parallel arrays for IDs, corners, and poses. - Memory: Uses
bumpaloarena allocation for zero heap allocations in the detection loop. - Solvers: 6-DOF recovery using IPPE-Square or weighted Levenberg-Marquardt with corner uncertainty.
Performance Profiles
Locus optimises for high recall, low corner RMSE, and low latency. Profiles are selected by name; the three shipped profiles are authored as JSON files and embedded in the wheel.
profile |
Primary characteristic |
|---|---|
"standard" |
Production default; balanced recall + precision. |
"grid" |
4-connectivity for touching tags — ChArUco / AprilGrid boards. |
"high_accuracy" |
EdLines + axis-imbalance gate + adaptive PPB; prioritises pose precision and tail-rotation control. |
ICRA 2020 Forward (community benchmark)
ICRA 2020 Forward is the closest thing the AprilTag community has to a neutral benchmark. The 50-frame subset we report on is synthetic (not real-camera), but it's public, peer-reviewed, and the basis for prior detector comparisons — we report on it for continuity with the literature.
| Detector | Recall | Corner RMSE |
|---|---|---|
Locus (standard) |
96.2 % | 0.315 px |
| AprilTag 3 (UMich) | 62.3 % | 0.22 px |
OpenCV (cv2.aruco) |
52.6 % | 0.98 px |
The OpenCV row is its recall-best OpenCV 5.0 config (tuned subpix); the
tag-aware apriltag refinement more than halves corner RMSE (0.39 px) but
rejects ICRA's marginal small tags, dropping recall to ~30 %.
render-tag (high-fidelity Blender + PSF)
render-tag is our in-house render suite — Blender with calibrated
PSF, exposure, sensor noise, and lens distortion models. The
detection scenes carry pixel-accurate ground truth for both corners
and 6-DOF pose, which lets us report translation / rotation
percentiles in addition to recall. Numbers below are the 2026-07-13
single-threaded SOTA snapshot on the 1080p 50-scene subset (OpenCV 5.0.0,
re-tuned) (see
docs/engineering/benchmarking/render_tag_sota_20260713.md
for methodology, the 2160p table, and OpenCV's two operating points).
| Detector | Recall | Trans p50 | Trans p99 | Rot p50 | Rot p99 | Latency |
|---|---|---|---|---|---|---|
Locus (high_accuracy) |
100 % | 0.4 mm | 18.6 mm | 0.057 ° | 0.600 ° | 13.8 ms |
Locus (standard) |
100 % | 3.5 mm | 50.3 mm | 0.288 ° | 27.248 ° | 32.7 ms |
OpenCV (cv2.aruco, subpix) |
100 % | 3.5 mm | 66.6 mm | 0.127 ° | 0.569 ° | 101.1 ms |
OpenCV (cv2.aruco, apriltag) |
100 % | 3.0 mm | 55.3 mm | 0.067 ° | 0.376 ° | 195.8 ms |
| AprilTag-C (pupil) | 100 % | 2.9 mm | 54.4 mm | 0.061 ° | 65.365 ° | 78.5 ms |
Latencies are single-thread. Locus high_accuracy wins the translation tail and
is 14× faster than OpenCV's best-accuracy apriltag config; that config in turn
has the best rotation tail among the default profiles (0.376°). OpenCV ships two
operating points — fast subpix and accurate-but-~2×-slower apriltag. AprilTag-C's
median rotation is best in class (0.06°) but its p99 explodes to 65° on symmetric-tag
IRLS branch-ambiguity failures.
Optional: model-edge pose refinement. Setting
pose.pose_edge_refinement_enabled = Trueadds an Accurate-mode stage that refines each decoded tag's pose against its ~40 internal bit-grid edges (rotation from the distributed edges; translation re-anchored to the corners). It takeshigh_accuracyrotation p99 to 0.249° (p95 0.180°) — below OpenCVapriltag's 0.376° — at ~2.7× better translation and +~1 ms/frame, with 2D corner RMSE unchanged and reprojection RMSE improved. Off by default (shipped detection stays byte-identical); requires camera intrinsics +tag_size. Seedocs/…/model_edge_refinement_20260715.md.
Installation
pip install locus-tag
The PyPI wheel is compiled for rectified (pinhole) imagery. For unrectified cameras (Brown-Conrady polynomial, Kannala-Brandt equidistant fisheye), see Install with distortion support.
Quick Start
Basic Detection
import cv2
import locus
img = cv2.imread("tags.jpg", cv2.IMREAD_GRAYSCALE)
detector = locus.Detector(families=[locus.TagFamily.AprilTag36h11])
# batch contains parallel NumPy arrays
batch = detector.detect(img)
print(f"IDs: {batch.ids}")
print(f"Corners: {batch.corners.shape}") # (N, 4, 2)
6-DOF Pose Estimation
from locus import Detector, CameraIntrinsics
# fx, fy, cx, cy
intrinsics = CameraIntrinsics(fx=800.0, fy=800.0, cx=640.0, cy=360.0)
# Returns [tx, ty, tz, qx, qy, qz, qw] for each tag
batch = detector.detect(
img,
intrinsics=intrinsics,
tag_size=0.10, # physical side length in meters
)
if batch.poses is not None:
# First tag translation
print(batch.poses[0, :3])
Configuration Overrides
Settings are nested and validated by Pydantic. Start from a shipped profile, edit the group you care about, and hand it back to the detector:
base = locus.DetectorConfig.from_profile("high_accuracy").model_dump()
base["quad"]["upscale_factor"] = 2
base["decoder"]["max_hamming_error"] = 1
detector = locus.Detector(config=locus.DetectorConfig.model_validate(base))
Visual Debugging
Built-in integration with the Rerun SDK:
batch = detector.detect(img, debug_telemetry=True)
if batch.telemetry:
print(batch.telemetry.subpixel_jitter)
Documentation
License
Dual-licensed under Apache 2.0 or MIT.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file locus_tag-0.7.0.tar.gz.
File metadata
- Download URL: locus_tag-0.7.0.tar.gz
- Upload date:
- Size: 392.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d58251e3a99ec630384eaf699d15597ca069cf6beb6e383ef2229a57e8a4d82c
|
|
| MD5 |
dbb70919e79e0930d5ec3c086fc42cf7
|
|
| BLAKE2b-256 |
4d4cb8e76c1801ba8cb1e84535fc6669353f130cbf442e639cb43e5e47784f35
|
Provenance
The following attestation bundles were made for locus_tag-0.7.0.tar.gz:
Publisher:
release.yml on NoeFontana/locus-tag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
locus_tag-0.7.0.tar.gz -
Subject digest:
d58251e3a99ec630384eaf699d15597ca069cf6beb6e383ef2229a57e8a4d82c - Sigstore transparency entry: 2202186445
- Sigstore integration time:
-
Permalink:
NoeFontana/locus-tag@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/NoeFontana
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Trigger Event:
push
-
Statement type:
File details
Details for the file locus_tag-0.7.0-cp310-abi3-win_amd64.whl.
File metadata
- Download URL: locus_tag-0.7.0-cp310-abi3-win_amd64.whl
- Upload date:
- Size: 589.6 kB
- Tags: CPython 3.10+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f737356092e09f2153e3c44a4231d63c619e42f27c11e4a282d451f44f38452a
|
|
| MD5 |
4ad4a178e7660eb28a9e94ce17f9e0cc
|
|
| BLAKE2b-256 |
19e51c94a9860d2282b234314f08a4ee1f1444429133be7fbbbe83281159a1cc
|
Provenance
The following attestation bundles were made for locus_tag-0.7.0-cp310-abi3-win_amd64.whl:
Publisher:
release.yml on NoeFontana/locus-tag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
locus_tag-0.7.0-cp310-abi3-win_amd64.whl -
Subject digest:
f737356092e09f2153e3c44a4231d63c619e42f27c11e4a282d451f44f38452a - Sigstore transparency entry: 2202189813
- Sigstore integration time:
-
Permalink:
NoeFontana/locus-tag@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/NoeFontana
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Trigger Event:
push
-
Statement type:
File details
Details for the file locus_tag-0.7.0-cp310-abi3-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: locus_tag-0.7.0-cp310-abi3-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 917.7 kB
- Tags: CPython 3.10+, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7c1798fd5c05fe2f4746a6ed6b86e5cad687c6d4348d791178f4ffd7ca6cc89f
|
|
| MD5 |
9ec430c071b594240e5a24bde9ca83bc
|
|
| BLAKE2b-256 |
98851b49ef5ff01999d3b87a2791b69a395a4c075290ee0e986869096d5775cc
|
Provenance
The following attestation bundles were made for locus_tag-0.7.0-cp310-abi3-musllinux_1_2_x86_64.whl:
Publisher:
release.yml on NoeFontana/locus-tag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
locus_tag-0.7.0-cp310-abi3-musllinux_1_2_x86_64.whl -
Subject digest:
7c1798fd5c05fe2f4746a6ed6b86e5cad687c6d4348d791178f4ffd7ca6cc89f - Sigstore transparency entry: 2202187156
- Sigstore integration time:
-
Permalink:
NoeFontana/locus-tag@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/NoeFontana
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Trigger Event:
push
-
Statement type:
File details
Details for the file locus_tag-0.7.0-cp310-abi3-musllinux_1_2_aarch64.whl.
File metadata
- Download URL: locus_tag-0.7.0-cp310-abi3-musllinux_1_2_aarch64.whl
- Upload date:
- Size: 822.5 kB
- Tags: CPython 3.10+, musllinux: musl 1.2+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4e247a3eaed712d59d783fd5dd44f96712bd8223a41cebd633ac7a13628731ef
|
|
| MD5 |
1d5c25407a3baef825cdb73d80ebe31e
|
|
| BLAKE2b-256 |
9655b6e8bc058387171224ab3eca2478abe1a2a3f7def58556f2a3a7a1812dc1
|
Provenance
The following attestation bundles were made for locus_tag-0.7.0-cp310-abi3-musllinux_1_2_aarch64.whl:
Publisher:
release.yml on NoeFontana/locus-tag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
locus_tag-0.7.0-cp310-abi3-musllinux_1_2_aarch64.whl -
Subject digest:
4e247a3eaed712d59d783fd5dd44f96712bd8223a41cebd633ac7a13628731ef - Sigstore transparency entry: 2202188398
- Sigstore integration time:
-
Permalink:
NoeFontana/locus-tag@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/NoeFontana
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Trigger Event:
push
-
Statement type:
File details
Details for the file locus_tag-0.7.0-cp310-abi3-manylinux_2_28_x86_64.whl.
File metadata
- Download URL: locus_tag-0.7.0-cp310-abi3-manylinux_2_28_x86_64.whl
- Upload date:
- Size: 702.4 kB
- Tags: CPython 3.10+, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8e5d18f7bbb77648f1154fef5819cd772f1fde403dd3bd5582b22f992772acc1
|
|
| MD5 |
9b29d643deb6ad07b5e1aca1ea3114df
|
|
| BLAKE2b-256 |
50c7dff7cb960b6a9ec936bcd100d59ee76f9c5e3904e9ae250c116424f1d0fd
|
Provenance
The following attestation bundles were made for locus_tag-0.7.0-cp310-abi3-manylinux_2_28_x86_64.whl:
Publisher:
release.yml on NoeFontana/locus-tag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
locus_tag-0.7.0-cp310-abi3-manylinux_2_28_x86_64.whl -
Subject digest:
8e5d18f7bbb77648f1154fef5819cd772f1fde403dd3bd5582b22f992772acc1 - Sigstore transparency entry: 2202187490
- Sigstore integration time:
-
Permalink:
NoeFontana/locus-tag@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/NoeFontana
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Trigger Event:
push
-
Statement type:
File details
Details for the file locus_tag-0.7.0-cp310-abi3-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: locus_tag-0.7.0-cp310-abi3-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 645.1 kB
- Tags: CPython 3.10+, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
33aaad7e7b864fdb137e1c523e4af4a7de2307c9b97a1cb5914203b5a8420ebd
|
|
| MD5 |
9e23fb956056b762ba1a92c54d12ab56
|
|
| BLAKE2b-256 |
16aa26d7a9668ababc44cd8d7a4c3dd6a2fde24e11e7ce4af197e8b7805665fb
|
Provenance
The following attestation bundles were made for locus_tag-0.7.0-cp310-abi3-manylinux_2_28_aarch64.whl:
Publisher:
release.yml on NoeFontana/locus-tag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
locus_tag-0.7.0-cp310-abi3-manylinux_2_28_aarch64.whl -
Subject digest:
33aaad7e7b864fdb137e1c523e4af4a7de2307c9b97a1cb5914203b5a8420ebd - Sigstore transparency entry: 2202189232
- Sigstore integration time:
-
Permalink:
NoeFontana/locus-tag@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/NoeFontana
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Trigger Event:
push
-
Statement type:
File details
Details for the file locus_tag-0.7.0-cp310-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: locus_tag-0.7.0-cp310-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 641.7 kB
- Tags: CPython 3.10+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4734468b8128076a65395fc263c829be427a8f11863fdee43d6a50e9ecb90eee
|
|
| MD5 |
796cc78fe0cef9f19442283e39caf456
|
|
| BLAKE2b-256 |
9e8f812ec9a0d21e6e207fc89a59b066818f929787374d9107f6ed5e0f4bb7db
|
Provenance
The following attestation bundles were made for locus_tag-0.7.0-cp310-abi3-macosx_11_0_arm64.whl:
Publisher:
release.yml on NoeFontana/locus-tag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
locus_tag-0.7.0-cp310-abi3-macosx_11_0_arm64.whl -
Subject digest:
4734468b8128076a65395fc263c829be427a8f11863fdee43d6a50e9ecb90eee - Sigstore transparency entry: 2202188884
- Sigstore integration time:
-
Permalink:
NoeFontana/locus-tag@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/NoeFontana
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Trigger Event:
push
-
Statement type:
File details
Details for the file locus_tag-0.7.0-cp310-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: locus_tag-0.7.0-cp310-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 665.4 kB
- Tags: CPython 3.10+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/6.1.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
55a98343be3ae4c19ad0214c7fe946500340a8d44e499c0cf74704b8193ed1ac
|
|
| MD5 |
0cf881f092069b7ae0c208c6652ea0f1
|
|
| BLAKE2b-256 |
8b1750691c6d6d94bf4f85545fdc10dd99d94f71de29d2c0b7db8beda28f98c7
|
Provenance
The following attestation bundles were made for locus_tag-0.7.0-cp310-abi3-macosx_10_12_x86_64.whl:
Publisher:
release.yml on NoeFontana/locus-tag
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
locus_tag-0.7.0-cp310-abi3-macosx_10_12_x86_64.whl -
Subject digest:
55a98343be3ae4c19ad0214c7fe946500340a8d44e499c0cf74704b8193ed1ac - Sigstore transparency entry: 2202187977
- Sigstore integration time:
-
Permalink:
NoeFontana/locus-tag@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Branch / Tag:
refs/tags/v0.7.0 - Owner: https://github.com/NoeFontana
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@6ad952010ec4b96c43c296f138e0262b5ae91aee -
Trigger Event:
push
-
Statement type: