data
BoundingBoxes
BoundingBoxes(data: Tensor, format: str, canvas_size: tuple[int, int], labels: Tensor | None = None)Wraps (N, 4) bounding boxes with a format + canvas size.
A typed target consumed by every GeometricTransform —
flips / crops / resizes update both the coordinates and the
reported canvas_size consistently. Optional labels ride
along the same row dimension so filter_boxes can drop
out-of-frame boxes + their labels in one step.
Parameters
dataTensor(N, 4) coordinates interpreted under format. For the
absolute formats (xyxy / xywh / cxcywh) units are
pixels; for the normalized formats (yolo / albumentations)
units are fractions of canvas_size.format{"xyxy", "xywh", "cxcywh", "yolo", "albumentations", \"pascal_voc", "coco"}
Coordinate convention.
"pascal_voc" is an alias for
"xyxy"; "coco" for "xywh". See
normalize_box_format.canvas_size(int, int)(H, W) of the image the boxes index into. Geometric
transforms (crop / resize / pad / rotate) re-emit a new
BoundingBoxes with the matching canvas.(N,) class indices (or any per-box scalar — score, track
id, ...). Carried through every geometric transform; trimmed
in lock-step with rows by filter_boxes. Default
None (no per-box labels).Raises
ValueErrorIf
format (after alias normalisation) is not one of the
recognised names.Notes
Format conventions (each row's 4 values):
xyxy—(x_min, y_min, x_max, y_max)xywh—(x_min, y_min, width, height)cxcywh—(cx, cy, width, height)yolo—(cx, cy, w, h), all in[0, 1]albumentations—(x_min, y_min, x_max, y_max), all in[0, 1]
Examples
>>> import lucid
>>> import lucid.utils.transforms as T
>>> boxes = T.BoundingBoxes(
... lucid.tensor([[10.0, 10.0, 40.0, 40.0]]),
... "xyxy",
... canvas_size=(100, 100),
... labels=lucid.tensor([1.0]),
... )
>>> out = T.HorizontalFlip(p=1.0)({"image": T.Image(lucid.rand(3, 100, 100)),
... "boxes": boxes})
>>> out["boxes"].labels.numpy().tolist()
[1.0]