Tutorial: Both Targets, End to End
This tutorial walks the full arc — generate → detect → interpret — for the two headline targets ringgrid supports:
- a coded hex target (16-sector rings, decoded to globally unique IDs), and
- a plain rect target (uncoded rings on a rectangular lattice, labeled by lattice coordinate and — with origin dots — anchored to absolute board mm).
Each generation step writes the same four artifacts: the canonical
target_spec.json, a printable .svg and .png, and a .dxf (2D CAD in
millimeters) for laser/CNC fabrication. See Target
Generation for every recipe field and the Compositional
Target Model for the geometry.
These two targets are hex_coded and rect_plain_dots — two of the six
built-in example recipes. All six combinations of {hex, rect} × {coded, plain}
× {origin dots, no dots} are available (see the
target matrix); origin-dot anchoring
now works for hex plain targets too.
Install the CLI once:
cargo install ringgrid --features cli
Part A — Coded hex target
1. Generate
Grab the built-in recipe and render it:
ringgrid example --name hex_coded --out hex_coded.toml
ringgrid gen hex_coded.toml --out ./out/hex
The equivalent Rust and Python (both write target_spec.json + .svg/.png/.dxf):
#![allow(unused)]
fn main() {
use ringgrid::TargetLayout;
let hex = TargetLayout::coded_hex(8.0, 15, 14, 4.8, 3.2, 1.152)?;
hex.write_json_file("./out/hex/target_spec.json".as_ref())?;
hex.write_target_svg("./out/hex/target_print.svg".as_ref(), &Default::default())?;
hex.write_target_png("./out/hex/target_print.png".as_ref(), &Default::default())?;
hex.write_target_dxf("./out/hex/target_print.dxf".as_ref())?;
}
import ringgrid
hex = ringgrid.TargetLayout.coded_hex(8.0, 15, 14, 4.8, 3.2, 1.152)
hex.write_svg("./out/hex/target_print.svg")
hex.write_png("./out/hex/target_print.png", dpi=600.0)
hex.write_dxf("./out/hex/target_print.dxf")
2. Detect
ringgrid detect \
--target ./out/hex/target_spec.json \
--image path/to/hex_photo.png \
--out ./out/hex/detect.json
3. Interpret
Coded markers decode to a unique id; IDs anchor an absolute board frame:
{
"board_frame": "absolute",
"detected_markers": [
{ "id": 42, "grid_coord": [3, -1], "center": [812.4, 655.1], "board_xy_mm": [24.0, 41.6] }
],
"homography": [ /* 3x3 board→image */ ]
}
id— codebook index (0–892), globally unique on the board.center— sub-pixel marker center in image pixels.board_xy_mm— the marker’s known board position (absolute).board_frameis alwaysabsolutefor coded targets.
Part B — Plain rect target
1. Generate
The built-in rect_plain_dots recipe is a 24×24 plain rect target with an
auto-placed origin-dot triad (the same target as the rect_24x24 preset):
ringgrid example --name rect_plain_dots --out rect_plain_dots.toml
ringgrid gen rect_plain_dots.toml --out ./out/rect
The equivalent in Python via the bundled preset:
import ringgrid
rect = ringgrid.TargetLayout.rect_24x24()
rect.write_svg("./out/rect/target_print.svg")
rect.write_png("./out/rect/target_print.png")
rect.write_dxf("./out/rect/target_print.dxf")
2. Detect
Detection is the same command — the target JSON tells the detector which path to run:
ringgrid detect \
--target ./out/rect/target_spec.json \
--image path/to/rect_photo.png \
--out ./out/rect/detect.json
3. Interpret
Plain markers carry no id — they are keyed by grid_coord. Whether
positions are absolute depends on origin resolution (see Plain / Rect Target
Detection):
{
"board_frame": "absolute",
"detected_markers": [
{ "id": null, "grid_coord": [0, 0], "center": [120.3, 133.7], "board_xy_mm": [0.0, 0.0] },
{ "id": null, "grid_coord": [1, 0], "center": [176.9, 133.5], "board_xy_mm": [14.0, 0.0] }
]
}
idisnull; usegrid_coord([col, row]for rect) as the marker key.board_frame: absolute— the origin dots were resolved, sogrid_coordis in board cells andboard_xy_mmis populated.board_frame: relative_canonical— no origin was resolved (target has no dots, or they were not visible).grid_coordis in a canonical relative frame and everyboard_xy_mmisnull. For a plain target without dots (rect_plain_nodots), passringgrid detect --strictto require the complete board. A wrong millimeter position is worse than none.
Recap
| Step | Coded hex | Plain rect |
|---|---|---|
| Recipe | hex_coded | rect_plain_dots |
| Generate | ringgrid gen hex_coded.toml … | ringgrid gen rect_plain_dots.toml … |
| Marker key | id (0–892) | grid_coord |
| Frame | always absolute | absolute (dots resolved) or relative_canonical |
| Artifacts | .json .svg .png .dxf | .json .svg .png .dxf |
Where to go next: the full result schema in Detection Output Format, the plain-path algorithm in Plain / Rect Target Detection, and frame semantics in Coordinate Frames.