Skip to main content

A high-performance fiducial marker detector for robotics.

Project description

locus-tag

CI License: MIT License: Apache 2.0

Locus is a high-performance fiducial marker detector (AprilTag & ArUco) written in Rust with zero-copy Python bindings. Designed for robotics and autonomous systems, it aims to balance low latency, high recall, and sub-pixel precision.

[!WARNING] Experimental Status: Locus is currently an experimental project. The API is subject to breaking changes. While performance exceeds alternatives on ICRA2020, it is not recommended for production systems. Photo-realistic benchmarks are being developed under render-tag.

Key Features

  • High-Performance Core: Written in Rust (2024 Edition) with a focus on Data-Oriented Design.
  • Encapsulated Facade: Simple, ergonomic Detector API that manages complex memory lifetimes (arenas, SoA batches) internally.
  • Runtime SIMD Dispatch: Automatically utilizes AVX2, AVX-512, or NEON based on host CPU capabilities.
  • Vectorized Python API: Returns detection results as a single DetectionBatch object containing parallel NumPy arrays for maximum throughput.
  • GIL-Free Execution: Releases the Python Global Interpreter Lock (GIL) during detection to enable true multi-threaded applications.
  • Memory Efficient: Uses bumpalo arena allocation to achieve zero heap allocations in the detection hot-path.
  • Advanced Pose Estimation: High-precision 6-DOF recovery using IPPE-Square or weighted Levenberg-Marquardt with corner uncertainty modeling.
  • Visual Debugging: Native integration with the Rerun SDK for real-time pipeline inspection.

Performance

Locus ships three scenario-specific SOTA presets alongside the production default. Choose the preset that matches your use case:

Scenario Preset Key metric
Dense multi-tag detection sota_pure_tags_default() 96.2% recall (ICRA forward, 50 images)
Touching-tag checkerboard grids sota_checkerboard_default() 91.4% recall (ICRA checkerboard, 50 images)
Single-tag metrology / calibration sota_metrology_default() 0.16–0.29 px corner RMSE (hub, 4 resolutions)
Balanced production production_default() 100% recall + precision on fixtures

ICRA 2020 — Multi-Tag Detection (50 images, forward/pure_tags)

Detector Recall RMSE
Locus (sota_pure_tags_default) 96.2% 0.315 px
Locus (production_default) 76.9% 0.274 px
AprilTag 3 62.3% 0.22 px
OpenCV 33.2% 0.92 px

ICRA 2020 — Checkerboard (50 images, forward/checkerboard_corners)

Detector Recall RMSE
Locus (sota_checkerboard_default) 91.4% 0.458 px
Locus (legacy checkerboard) 73.0% 0.332 px
Locus (production_default)

Production without 4-connectivity merges adjacent tag regions; not applicable to checkerboard scenes.

Hub — Single-Tag Metrology (720p, PoseEstimationMode::Accurate)

Config Recall Corner RMSE Trans P50 Rot P50
Locus (sota_metrology_default) 96.0% 0.277 px 1.0 mm 0.35°
Locus (production_default) 100% 0.933 px 5.8 mm 2.20°

sota_metrology_default uses the EdLines Joint Gauss-Newton solver — per-corner 2×2 covariances propagate directly to the weighted LM pose solver, achieving 3–6× lower corner RMSE and 6–8× lower pose error vs production.

Full benchmark tables, methodology, and per-resolution results: docs/engineering/benchmarking/sota_metrology_20260321.md

Quick Start

Installation

pip install locus-tag

For development, build from source using uv:

git clone https://github.com/NoeFontana/locus-tag
cd locus-tag
uv run maturin develop -r

Basic Usage

The simplest way to detect tags using default settings:

import cv2
import locus

# Load image in grayscale
img = cv2.imread("image.jpg", cv2.IMREAD_GRAYSCALE)

# Create detector and detect tags (defaults to AprilTag 36h11)
detector = locus.Detector()
batch = detector.detect(img)

# batch is a vectorized DetectionBatch object
for i in range(len(batch)):
    print(f"ID: {batch.ids[i]}, Center: {batch.centers[i]}")

Advanced Configuration

Use semantic keyword arguments for fine-grained control and performance tuning:

from locus import Detector, TagFamily, DecodeMode

# Configure for maximum recall on small, blurry tags
detector = Detector(
    decode_mode=DecodeMode.Soft,
    upscale_factor=2,
    families=[TagFamily.AprilTag36h11, TagFamily.ArUco4x4_50]
)

batch = detector.detect(img)

3D Pose Estimation

Recover the 6-DOF transformation between the camera and the tag:

from locus import CameraIntrinsics, PoseEstimationMode

# Camera parameters (fx, fy, cx, cy)
intrinsics = CameraIntrinsics(fx=800.0, fy=800.0, cx=640.0, cy=360.0)

# Pass intrinsics and physical tag size (meters)
batch = detector.detect(
    img, 
    intrinsics=intrinsics, 
    tag_size=0.10,
    pose_estimation_mode=PoseEstimationMode.Accurate
)

if batch.poses is not None:
    # batch.poses is (N, 7) array: [tx, ty, tz, qx, qy, qz, qw]
    print(f"First tag translation: {batch.poses[0, :3]}")
    print(f"First tag quaternion: {batch.poses[0, 3:]}")

Visual Debugging with Rerun

Locus provides a powerful visualization tool to inspect every stage of the pipeline (thresholding, segmentation, quad candidates, bit grids).

# Run the visualizer on a dataset using the dev/bench dependency groups
uv run --group dev --group bench tools/cli.py visualize --scenario forward --limit 5

Development & Benchmarking

Locus includes a rigorous suite to ensure detection quality and latency targets.

# Prepare local datasets
uv run --group dev --group bench tools/cli.py bench prepare

# Run full evaluation suite and compare with competitors
uv run --group dev --group bench tools/cli.py bench real --compare

Detailed documentation for profiling, architecture, and coordinate systems is available in the Docs Site.

License

Dual-licensed under Apache 2.0 or MIT.

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

locus_tag-0.3.0.tar.gz (233.7 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

locus_tag-0.3.0-cp310-abi3-manylinux_2_28_x86_64.whl (506.9 kB view details)

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

locus_tag-0.3.0-cp310-abi3-manylinux_2_28_aarch64.whl (457.8 kB view details)

Uploaded CPython 3.10+manylinux: glibc 2.28+ ARM64

File details

Details for the file locus_tag-0.3.0.tar.gz.

File metadata

  • Download URL: locus_tag-0.3.0.tar.gz
  • Upload date:
  • Size: 233.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for locus_tag-0.3.0.tar.gz
Algorithm Hash digest
SHA256 25738c02cdcf6f39054cd5be74400bfe8e96297871709d4e7325b8a071c383bd
MD5 41ae25bcce6bfa2532de40547a1c27d6
BLAKE2b-256 a8bcc1a9bc374ccf3627e6fa520b4c2db5d6f920d377fb1b81a7b7d4179423ed

See more details on using hashes here.

File details

Details for the file locus_tag-0.3.0-cp310-abi3-manylinux_2_28_x86_64.whl.

File metadata

  • Download URL: locus_tag-0.3.0-cp310-abi3-manylinux_2_28_x86_64.whl
  • Upload date:
  • Size: 506.9 kB
  • Tags: CPython 3.10+, manylinux: glibc 2.28+ x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for locus_tag-0.3.0-cp310-abi3-manylinux_2_28_x86_64.whl
Algorithm Hash digest
SHA256 f7c4eb2408adb5088adda291ea7b5935a027f94289abf32cde687545fc17a3d4
MD5 57dea8e02e2bd905a188957137e47322
BLAKE2b-256 059e8d878507033823df9a3b55e5e18dec6591deac9bd8ff06ce1a4dd51dce92

See more details on using hashes here.

File details

Details for the file locus_tag-0.3.0-cp310-abi3-manylinux_2_28_aarch64.whl.

File metadata

  • Download URL: locus_tag-0.3.0-cp310-abi3-manylinux_2_28_aarch64.whl
  • Upload date:
  • Size: 457.8 kB
  • Tags: CPython 3.10+, manylinux: glibc 2.28+ ARM64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

File hashes

Hashes for locus_tag-0.3.0-cp310-abi3-manylinux_2_28_aarch64.whl
Algorithm Hash digest
SHA256 9d7d0ff99e3edaa921dae1cb1474a35a6a2f279b6f1085c67e39b7e79d693418
MD5 09917c36bbb60bb30d2a84327a64e1f9
BLAKE2b-256 4d5f2ef9705fd046441956aab94cdb1e0968ba3188b8d17db2bc2725dc155dc5

See more details on using hashes here.

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