albumentations icon indicating copy to clipboard operation
albumentations copied to clipboard

Add RandomCropNearBorders transform

Open ternaus opened this issue 2 years ago • 2 comments

Transform used by @ZFTurbo

  1. Specify the distance from 4 sides in pixels or in percent.
  2. Sample distance from [0, specified_distance]
  3. Crop the corresponding part of the image/mask.
  4. Resize the crop to its original size.

ternaus avatar Jul 13 '22 18:07 ternaus

Something like this:

class RandomCropFromBorders(DualTransform):
    """Cuts out a rectangular portion of the image by randomly indenting each side. There is no resize of image at the end.

    Args:
        crop_value (float): float value in (0.0, 0.5) range. Default 0.1
        crop_left (float): float value in (0.0, 1.0) range. Default 0.1
        crop_right (float): float value in (0.0, 1.0) range. Default 0.1
        crop_top (float): float value in (0.0, 1.0) range. Default 0.1
        crop_bottom (float): float value in (0.0, 1.0) range. Default 0.1
        p (float): probability of applying the transform. Default: 1.

    Targets:
        image, mask, bboxes, keypoints

    Image types:
        uint8, float32
    """

    def __init__(
            self,
            crop_value=None,
            crop_left=None,
            crop_right=None,
            crop_top=None,
            crop_bottom=None,
            always_apply=False,
            p=1.0
    ):
        super(RandomCropFromBorders, self).__init__(always_apply, p)
        self.crop_left = 0.1
        self.crop_right = 0.1
        self.crop_top = 0.1
        self.crop_bottom = 0.1
        if crop_value is not None:
            self.crop_left = crop_value
            self.crop_right = crop_value
            self.crop_top = crop_value
            self.crop_bottom = crop_value
        if crop_left is not None:
            self.crop_left = crop_left
        if crop_right is not None:
            self.crop_right = crop_right
        if crop_top is not None:
            self.crop_top = crop_top
        if crop_bottom is not None:
            self.crop_bottom = crop_bottom

    def get_params_dependent_on_targets(self, params):
        img = params["image"]
        x_min = random.randint(0, int(self.crop_left * img.shape[1]))
        x_max = random.randint(max(x_min + 1, int((1 - self.crop_right) * img.shape[1])), img.shape[1])
        y_min = random.randint(0, int(self.crop_top * img.shape[0]))
        y_max = random.randint(max(y_min + 1, int((1 - self.crop_bottom) * img.shape[0])), img.shape[0])
        return {"x_min": x_min, "x_max": x_max, "y_min": y_min, "y_max": y_max}

    def apply(self, img, x_min=0, x_max=0, y_min=0, y_max=0, **params):
        return F_albu.clamping_crop(img, x_min, y_min, x_max, y_max)

    def apply_to_mask(self, mask, x_min=0, x_max=0, y_min=0, y_max=0, **params):
        return F_albu.clamping_crop(mask, x_min, y_min, x_max, y_max)

    def apply_to_bbox(self, bbox, x_min=0, x_max=0, y_min=0, y_max=0, **params):
        rows, cols = params["rows"], params['cols']
        return F_albu.bbox_crop(bbox, x_min, y_min, x_max, y_max, rows, cols)

    def apply_to_keypoint(self, keypoint, x_min=0, x_max=0, y_min=0, y_max=0, **params):
        return F_albu.crop_keypoint_by_coords(
            keypoint,
            crop_coords=(x_min, y_min, x_max, y_max),
            crop_height=y_max - y_min,
            crop_width=x_max - x_min,
            rows=params["rows"],
            cols=params["cols"],
        )

    @property
    def targets_as_params(self):
        return ["image"]

    def get_transform_init_args_names(self):
        return "crop_value", "crop_left", "crop_right", "crop_top", "crop_bottom"

ternaus avatar Jul 14 '22 19:07 ternaus

Hi @ternaus, I would like to work on this issue.

kishore-s-15 avatar Aug 08 '22 10:08 kishore-s-15