Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Proposal Diagnostics

The proposal stage can be run standalone to inspect candidate centers and the vote accumulator heatmap without running the full detection pipeline.

Python API

Raw mode (no scale prior)

import ringgrid
from ringgrid import viz

# Default ProposalConfig
proposals = ringgrid.propose("photo.png")
result = ringgrid.propose_with_heatmap("photo.png")

print(len(result.proposals))
print(result.heatmap.shape)  # (H, W), float32

viz.plot_proposal_diagnostics(
    image="photo.png",
    diagnostics=result,
    out="proposal_overlay.png",
)

Detector-aware mode (scale-tuned)

When a board layout and marker diameter are available, the proposal config is derived from MarkerScalePrior for tighter search windows:

target = ringgrid.TargetLayout.default_hex()
cfg = ringgrid.DetectConfig(target)
detector = ringgrid.Detector(cfg)

result = detector.propose_with_heatmap("photo.png")

Or via the module-level convenience function:

result = ringgrid.propose_with_heatmap(
    "photo.png",
    target=board,
    marker_diameter=32.0,
)

Custom ProposalConfig

config = ringgrid.ProposalConfig(
    r_min=5.0,
    r_max=40.0,
    min_distance=15.0,
    radius_step=1,
)
result = ringgrid.propose_with_heatmap("photo.png", config=config)

Rust API

ringgrid re-exports standalone proposal entry points at the crate root. They work on any grayscale image, independent of the ringgrid detection pipeline:

#![allow(unused)]
fn main() {
use ringgrid::{find_ellipse_centers, find_ellipse_centers_with_heatmap, ProposalConfig};

let config = ProposalConfig {
    r_min: 5.0,
    r_max: 30.0,
    min_distance: 15.0,
    ..Default::default()
};

// Proposals only
let proposals = find_ellipse_centers(&gray, &config);

// Proposals + heatmap
let result = find_ellipse_centers_with_heatmap(&gray, &config);
println!("heatmap size: {:?}", result.image_size);
}

ProposalResult Fields

FieldTypeDescription
proposalslist[Proposal]Detected center candidates with (x, y, score)
heatmapnp.ndarray (H, W), float32Post-smoothed vote accumulator used for NMS
image_size[int, int][width, height] of the input image

The heatmap is the Gaussian-smoothed vote accumulator that the proposal stage uses for thresholding and NMS. It is useful for understanding where the detector sees radial symmetry evidence.

ProposalConfig Parameters

ParameterDefaultDescription
r_min3.0Minimum voting radius (pixels)
r_max12.0Maximum voting radius (pixels)
min_distance10.0Minimum distance between output proposals (pixels)
grad_threshold0.05Gradient magnitude threshold (fraction of max)
min_vote_frac0.1Minimum accumulator peak (fraction of max)
radius_step1Stride between voting radii (1 = every integer radius; 2+ subsamples for speed at the cost of recall; max radius always included)
max_candidatesNoneOptional hard cap on proposals

Visualization Tool

The repo includes a CLI tool for proposal visualization with optional ground-truth recall overlay:

python tools/plot_proposal.py \
    --image tools/out/synth_001/img_0000.png \
    --gt tools/out/synth_001/gt_0000.json \
    --out tools/out/synth_001/proposals_0000.png

To emulate a marker scale prior, constrain the voting-radius band around the expected outer-ring radius (≈16 px for 32 px-diameter markers):

python tools/plot_proposal.py \
    --image testdata/target_3_split_00.png \
    --r-min 10 --r-max 24 \
    --out proposals_overlay.png

A full ProposalConfig JSON can also be supplied via --config; individual flags override its fields.

Backward Compatibility

The Python class ProposalDiagnostics is a deprecated alias for ProposalResult. Existing code using ProposalDiagnostics will continue to work.