Utilities for adapting LDF annotations to Albumentations.
The augmentation engine receives annotations in Luxonis Data Format (LDF), converts them to Albumentations-compatible arrays before spatial transforms, and converts them back afterward. This module keeps those boundary conversions centralized.
| Target | LDF layout | Albumentations layout |
|---|---|---|
| Masks | (C, H, W) or (N, H, W) | (H, W, C) or (H, W, N) |
| Bounding boxes | [c, x, y, w, h] | [xmin, ymin, xmax, ymax, c, i] |
| Keypoints | (N, 3K) normalized rows | (NK, 3) pixel-space rows |
The appended bbox index i is used during postprocessing to keep bbox-associated labels, such as instance masks and keypoints, aligned with the bounding boxes that survive augmentation and filtering.
| Function | postprocess |
Convert augmented bounding boxes back to LDF format. |
| Function | postprocess |
Convert augmented keypoints back to normalized LDF rows. |
| Function | postprocess |
Convert an augmented mask back to the LDF layout. |
| Function | preprocess |
Convert LDF bounding boxes to Albumentations format. |
| Function | preprocess |
Convert normalized LDF keypoints to absolute coordinates. |
| Function | preprocess |
Convert an LDF mask to the Albumentations mask layout. |
| Function | yield |
Yield fixed-size chunks of sample dictionaries. |
| Type Variable | T |
Undocumented |
np.ndarray, area_threshold: float = 0.0004) -> tuple[ np.ndarray, np.ndarray]:
¶
Convert augmented bounding boxes back to LDF format.
Bounding boxes smaller than area_threshold are discarded. The appended bbox indices are returned alongside the boxes so labels tied to boxes, such as instance masks, keypoints, arrays, and metadata, can be filtered in the same way.
Examples
>>> bboxes = np.array([[0.1, 0.2, 0.4, 0.6, 2, 5]], dtype=float) >>> out_bboxes, ordering = postprocess_bboxes(bboxes) >>> np.round(out_bboxes, 2).tolist() [[2.0, 0.1, 0.2, 0.3, 0.4]] >>> ordering.tolist() [5] >>> tiny = np.array([[0.0, 0.0, 0.01, 0.01, 1, 3]], dtype=float) >>> postprocess_bboxes(tiny, area_threshold=0.1)[0].shape (0, 5) >>> postprocess_bboxes(np.empty((0, 6)), area_threshold=0.1)[0].shape (0, 5)
| Parameters | |
bboxes:np.ndarray | Augmented bounding boxes of shape (N, 6) in [xmin, ymin, xmax, ymax, c, i] format, where c is the class ID and i is the stable bbox index. |
areafloat | Minimum normalized box area w⋅h required for a box to remain valid. |
| Returns | |
A tuple containing |
|
np.ndarray, bboxes_ordering: np.ndarray, image_height: int, image_width: int, n_keypoints: int) -> np.ndarray:
¶
Convert augmented keypoints back to normalized LDF rows.
The input contains pixel-space keypoints after Albumentations has applied spatial transforms. This function restores the original annotation grouping, keeps only annotations associated with surviving bounding boxes, marks out-of-image keypoints as invisible, clips coordinates to the image extent, and normalizes coordinates back to [0, 1].
Examples
>>> keypoints = np.array([[5, 5, 2], [12, -1, 2]], dtype=float) >>> out = postprocess_keypoints(keypoints, np.array([0]), 10, 10, 2) >>> np.round(out, 2).tolist() [[0.5, 0.5, 2.0, 1.0, 0.0, 0.0]] >>> keypoints = np.array([[1, 1, 2], [9, 9, 1]], dtype=float) >>> postprocess_keypoints(keypoints, np.array([1, 0]), 10, 10, 1).tolist() [[0.9, 0.9, 1.0], [0.1, 0.1, 2.0]]
| Parameters | |
keypoints:np.ndarray | Augmented keypoints of shape (NK, D), where the first 3K values per annotation are (x, y, v) triplets and any extra columns are discarded. |
bboxesnp.ndarray | Indices of bbox-associated annotations that survived bbox postprocessing. |
imageint | Height of the augmented image used to normalize y coordinates. |
imageint | Width of the augmented image used to normalize x coordinates. |
nint | Number of keypoints K in each annotation. |
| Returns | |
np.ndarray | Keypoints of shape (M, 3K), where M is the number of retained annotations. Each row is in normalized LDF format [x1, y1, v1, x2, y2, v2, …]. |
Convert an augmented mask back to the LDF layout.
Examples
>>> postprocess_mask(np.array([[1, 0], [0, 1]])).shape (1, 2, 2) >>> mask = np.array([[[1, 5], [2, 6]], [[3, 7], [4, 8]]]) >>> postprocess_mask(mask).tolist() [[[1, 2], [3, 4]], [[5, 6], [7, 8]]]
| Parameters | |
mask:np.ndarray | Augmented mask. Two-dimensional inputs are interpreted as a single mask of shape (H, W). Three-dimensional inputs are expected to have shape (H, W, C) or (H, W, N). |
| Returns | |
np.ndarray | Mask array in LDF channels-first layout. Two-dimensional inputs become (1, H, W), and three-dimensional inputs become (C, H, W) or (N, H, W). |
Convert LDF bounding boxes to Albumentations format.
LDF stores bounding boxes as normalized [c, x, y, w, h] rows, where c is the class ID and x and y are the top-left corner. Albumentations expects normalized [xmin, ymin, xmax, ymax, c] rows. This function also appends a stable per-box index used after augmentation to keep bbox-associated labels aligned with boxes that survived filtering.
Examples
>>> bboxes = np.array([[2, 0.1, 0.2, 0.3, 0.4]]) >>> out = preprocess_bboxes(bboxes, bbox_counter=5) >>> np.round(out[:, :4], 4).tolist() [[0.1, 0.2, 0.4, 0.6]] >>> out[:, 4:].astype(int).tolist() [[2, 5]]
| Parameters | |
bboxes:np.ndarray | Bounding boxes of shape (N, 5) in [c, x, y, w, h] format. |
bboxint | Offset used to create the appended bbox indices. The first output row receives this value, the next receives bbox_counter + 1, and so on. |
| Returns | |
np.ndarray | Bounding boxes of shape (N, 6) in [xmin, ymin, xmax, ymax, c, i] format, where i is the stable bbox index. |
Convert normalized LDF keypoints to absolute coordinates.
LDF stores keypoints as flattened rows of normalized (x, y, v) triplets. Albumentations expects one keypoint per row and uses pixel-space coordinates for spatial transforms.
Examples
>>> keypoints = np.array([[0.5, 0.25, 2, 1.0, 0.0, 1]]) >>> preprocess_keypoints(keypoints, height=8, width=4).tolist() [[2.0, 2.0, 2.0], [4.0, 0.0, 1.0]] >>> preprocess_keypoints(np.empty((0, 3)), 8, 4).shape (0, 3)
| Parameters | |
keypoints:np.ndarray | Keypoints of shape (N, 3K), where N is the number of annotations and K is the number of keypoints per annotation. Each row has format [x1, y1, v1, x2, y2, v2, …]. |
height:int | Image height used to scale normalized y coordinates. |
width:int | Image width used to scale normalized x coordinates. |
| Returns | |
np.ndarray | Keypoints of shape (NK, 3) in pixel-space [x, y, v] format. |
Convert an LDF mask to the Albumentations mask layout.
Luxonis Data Format stores semantic masks as (C, H, W) and instance masks as (N, H, W). Albumentations expects the spatial dimensions first, so this function moves the channel or instance dimension to the end.
Examples
>>> seg = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]]) >>> preprocess_mask(seg).shape (2, 2, 2) >>> preprocess_mask(seg).tolist() [[[1, 5], [2, 6]], [[3, 7], [4, 8]]]
| Parameters | |
seg:np.ndarray | Mask array of shape (C, H, W) or (N, H, W). |
| Returns | |
np.ndarray | Mask array of shape (H, W, C) or (H, W, N). |
list[ dict[ str, T]], batch_size: int) -> Iterator[ dict[ str, list[ T]]]:
¶
Yield fixed-size chunks of sample dictionaries.
Examples
>>> samples = [ ... {"image": "a", "label": 1}, ... {"image": "b", "label": 2}, ... {"image": "c", "label": 3}, ... ] >>> list(yield_batches(samples, 2)) [{'image': ['a', 'b'], 'label': [1, 2]}, {'image': ['c'], 'label': [3]}] >>> next(yield_batches(samples, 10))["label"] [1, 2, 3]
| Parameters | |
datalist[ | Dictionaries containing data for each sample. All dictionaries are expected to expose the same keys. |
batchint | Maximum number of samples in each yielded batch. |
| Returns | |
Iterator[ | Iterator over dictionaries grouped by key. For an input chunk of B samples, each yielded value maps every key to a list of B values. |