Skip to content

User Guide

This guide covers advanced configuration and features of the Locus detector.

Performance Tuning & Decimation

For performance-critical applications, using decimation can significantly speed up the detection pipeline by processing a downsampled version of the image.

import locus

detector = locus.Detector(
    threshold_tile_size=16, # Larger tiles are faster (8-16 is typical)
    enable_bilateral=False  # Disable for 20-30% speedup if image noise is low
)

# Use decimation=2 to process at half resolution (4x speed boost)
# Note: Use decimation=1 if tags are small (< 20 pixels)
tags = detector.detect(img, decimation=2)

print(f"Detected {len(tags)} tags")
Parameter Impact Recommendation
decimation Linear speedup in preprocessing. Use 2 for 1080p+ images if tags are >40px.
enable_bilateral High. Improves noise rejection. Disable for high-SNR sensors.
threshold_tile_size Low. Affects local adaptive threshold. Use 8 or 16.

Soft-Decision Decoding (Maximum Recall)

For challenging conditions where tags are tiny, blurry, or noisy, Locus supports Soft-Decision Decoding. This mode uses Log-Likelihood Ratios (LLRs) instead of hard bit-binarization, typically providing a +10-15% recall boost on difficult datasets.

# Enable Soft-Decision mode
config = locus.DetectorConfig(
    decode_mode=locus.DecodeMode.Soft,
    decoder_min_contrast=10.0 # Lower threshold to capture faint tags
)
detector = locus.Detector(config=config)

tags = detector.detect(img)
Mode Use Case Latency
Hard (Default) High Resolution / Clean Imagery. Minimum latency.
Soft Small / Blurry / Noisy Tags. ~20% overhead.

Specialized Profiles

Locus includes pre-configured profiles for specific use cases.

Checkerboard Detection

Used for calibration patterns or densely packed tags where black squares touch. This profile uses 4-way connectivity to prevent component merging.

detector = locus.Detector.checkerboard()

Targeted Families

Searching for fewer families reduces the decoding search space and improves latency.

detector.set_families([
    locus.TagFamily.AprilTag36h11,
    locus.TagFamily.ArUco4x4_50
])

Precise Configuration

The DetectorConfig class allows fine-tuning every stage of the pipeline:

config = locus.DetectorConfig(
    quad_min_area=16,           # Filter small components early
    subpixel_refinement_sigma=0.8, # Gaussian kernel for corner refinement
    decoder_min_contrast=10.0      # Sensitivity to bit transitions
)
detector = locus.Detector(config=config)

Pose Estimation

Locus implements modern pose solvers to recover the 6-DOF transformation between the camera and the tag.

IPPE-Square

For standard detection, we use IPPE-Square (Infinitesimal Plane-Based Pose Estimation). It provides an analytical solution that resolves the Necker reversal (perspective flip) ambiguity.

intrinsics = locus.CameraIntrinsics(fx=800.0, fy=800.0, cx=640.0, cy=360.0)

# Pass intrinsics and tag size (meters) to enable pose estimation
tags = detector.detect(
    img,
    intrinsics=intrinsics,
    tag_size=0.16
)

for t in tags:
    if t.pose:
        print(f"Translation: {t.pose.translation}") # [x, y, z]
        print(f"Rotation: {t.pose.rotation}")       # 3x3 Matrix

High-Precision (Probabilistic) Mode

When PoseEstimationMode.Accurate is selected, Locus computes the Structure Tensor for each corner to estimate position uncertainty, then performs an Anisotropic Weighted Levenberg-Marquardt refinement.

tags = detector.detect(
    img,
    intrinsics=intrinsics,
    tag_size=0.16,
    pose_estimation_mode=locus.PoseEstimationMode.Accurate
)

for t in tags:
    if t.pose_covariance:
        # Full 6x6 covariance matrix [R|t]
        print(f"Pose Uncertainty: {t.pose_covariance}")