Random crop around the union of a randomly sampled subset of bboxes, for use when preserving every box is unnecessary and a variable-size crop is preferable.
Unlike BBoxSafeRandomCrop, which guarantees every bbox survives the crop, this transform samples a random subset of the available bboxes (sized between subset_fraction_range[0] and subset_fraction_range[1] of the total count), computes the union of only that subset, and crops around it. Bboxes outside the sampled subset may remain complete, be clipped, or be removed entirely depending on where they fall relative to the crop.
This makes BBoxSubsetSafeRandomCrop useful for:
The algorithm:
subset_fraction_rangeFraction of bboxes to select for the union, as (min_fraction, max_fraction). Must satisfy 0 < min_fraction <= max_fraction <= 1. A value of (1.0, 1.0) always selects every bbox. Defaults to (0.5, 1.0).
erosion_rateControls how much the valid crop region can deviate from the selected bboxes' union. Must be in range [0.0, 1.0].
aspect_ratio_rangeInclusive (height / width) range for the sampled crop when a feasible crop exists. Defaults to (0.5, 2.0).
pProbability of applying the transform. Defaults to 1.0.
>>> import numpy as np
>>> import albumentations as A
>>>
>>> image = np.random.randint(0, 256, (200, 200, 3), dtype=np.uint8)
>>> mask = np.random.randint(0, 2, (200, 200), dtype=np.uint8)
>>> bboxes = np.array(
... [[10, 10, 40, 40], [60, 60, 90, 90], [120, 20, 150, 50], [30, 120, 70, 160]],
... dtype=np.float32,
... )
>>> bbox_labels = [1, 2, 3, 4]
>>>
>>> transform = A.Compose(
... [
... A.BBoxSubsetSafeRandomCrop(
... subset_fraction_range=(0.5, 1.0),
... erosion_rate=0.2,
... aspect_ratio_range=(0.5, 2.0),
... ),
... ],
... bbox_params=A.BboxParams(coord_format="pascal_voc", label_fields=["bbox_labels"]),
... )
>>>
>>> result = transform(image=image, mask=mask, bboxes=bboxes, bbox_labels=bbox_labels)
>>> transformed_image = result["image"]
>>> transformed_bboxes = result["bboxes"]