Object detection¶
Ask a model for axis-aligned boxes on a gridded preview, convert its answer into normalized coordinates, then render the boxes back so it can correct them before you store anything.
from annotools import (
BBoxObject,
GridOptions,
draw_bboxes,
draw_grid,
encode,
load_image,
normalize_coordinates,
preview,
)
view = preview(load_image("photo.jpg"), max_width=768, max_height=768)
view.image = draw_grid(view.image, GridOptions(columns=10, rows=10)).image
gridded = encode(view.image, "jpeg") # ask the model for boxes on this view
width, height = view.metadata["output_size"]
answer = [[144, 72, 432, 360]] # the model's pixels of the view it saw
boxes = normalize_coordinates(answer, width, height, crop=view.metadata["crop"])
check = draw_bboxes(view, [BBoxObject(bbox=boxes[0], label="cat")])
boxes is [[0.1875, 0.125, 0.5625, 0.625]] — normalized to the uncropped source, which is
what the store keeps. draw_grid returns a new result, but only its image is taken: view keeps
the crop and scale that both normalize_coordinates and draw_bboxes map through, so the
boxes land on the same gridded view the model answered on.
preview_image_grid, then normalize_coordinates on the answer, then
preview_image_bboxes to show the model its own boxes:
{
"coordinates": [[144, 72, 432, 360]],
"base_width": 768,
"base_height": 576,
"crop": [0, 0, 1, 1]
}
{
"source": "photo.jpg",
"objects": [{ "bbox": [0.1875, 0.125, 0.5625, 0.625], "label": "cat" }],
"grid": { "columns": 10, "rows": 10 },
"max_width": 768,
"max_height": 768
}
base_width / base_height and crop are the grid call's own output_width, output_height
and applied crop — read them off its metadata rather than assuming, since the fit depends on
the source aspect ratio (768x576 for a 4:3 photo) and crop is only the full frame while the
model is looking at the whole image.
The grid call adds grid (columns, rows, step_x / step_y, cell_width / cell_height)
to the usual metadata; normalize_coordinates answers {"coordinates": [[...]]}; the box call
adds objects, the number drawn. Repeat propose → verify → correct by index for a bounded number
of rounds, then commit each accepted box to the store.
Then: preview_image_grid,
preview_image_bboxes and
normalize_coordinates for the parameters;
draw_bboxes and
normalize_coordinates for the
library contract. The loop itself — class definitions, prompts, round limits, quality checks — is in
skills/task-object-detection
and skills/localization-annotation-guide;
complete pipelines in
examples/object-detection-claude
and examples/object-detection-codex.