Random crop that keeps all bboxes inside (erosion_rate). Use when losing any object is unacceptable. For at least one bbox use AtLeastOneBBoxRandomCrop.
Similar to AtLeastOneBboxRandomCrop, but with a key difference:
This makes BBoxSafeRandomCrop more suitable for scenarios where:
The algorithm:
erosion_rateControls how much the valid crop region can deviate from the bbox union. Must be in range [0.0, 1.0].
pProbability of applying the transform. Defaults to 1.0.
>>> import numpy as np
>>> import albumentations as A
>>>
>>> # Prepare sample data
>>> image = np.random.randint(0, 256, (100, 100, 3), dtype=np.uint8)
>>> mask = np.random.randint(0, 2, (100, 100), dtype=np.uint8)
>>> bboxes = np.array([[10, 10, 50, 50], [40, 40, 80, 80]], dtype=np.float32)
>>> bbox_labels = [1, 2]
>>> keypoints = np.array([[20, 30], [60, 70]], dtype=np.float32)
>>> keypoint_labels = [0, 1]
>>>
>>> # Define transform with erosion_rate parameter
>>> transform = A.Compose([
... A.BBoxSafeRandomCrop(erosion_rate=0.2),
... ], bbox_params=A.BboxParams(coord_format='pascal_voc', label_fields=['bbox_labels']),
... keypoint_params=A.KeypointParams(coord_format='xy', label_fields=['keypoint_labels']))
>>>
>>> # Apply the transform
>>> result = transform(
... image=image,
... mask=mask,
... bboxes=bboxes,
... bbox_labels=bbox_labels,
... keypoints=keypoints,
... keypoint_labels=keypoint_labels
... )
>>>
>>> # Get the transformed data
>>> transformed_image = result['image'] # Cropped image containing all bboxes
>>> transformed_mask = result['mask'] # Cropped mask
>>> transformed_bboxes = result['bboxes'] # All bounding boxes preserved with adjusted coordinates
>>> transformed_bbox_labels = result['bbox_labels'] # Original labels preserved
>>> transformed_keypoints = result['keypoints'] # Keypoints with adjusted coordinates
>>> transformed_keypoint_labels = result['keypoint_labels'] # Original keypoint labels preserved
>>>
>>> # Example with a different erosion_rate
>>> transform_more_flexible = A.Compose([
... A.BBoxSafeRandomCrop(erosion_rate=0.5), # More flexibility in crop placement
... ], bbox_params=A.BboxParams(coord_format='pascal_voc', label_fields=['bbox_labels']))
>>>
>>> # Apply transform with only image and bboxes
>>> result_bboxes_only = transform_more_flexible(
... image=image,
... bboxes=bboxes,
... bbox_labels=bbox_labels
... )
>>> transformed_image = result_bboxes_only['image']
>>> transformed_bboxes = result_bboxes_only['bboxes'] # All bboxes still preserved