def test_transform_pipeline_serialization(seed, image, mask): aug = A.Compose([ A.OneOrOther( A.Compose([ A.Resize(1024, 1024), A.RandomSizedCrop(min_max_height=(256, 1024), height=512, width=512, p=1), A.OneOf([ A.RandomSizedCrop(min_max_height=(256, 512), height=384, width=384, p=0.5), A.RandomSizedCrop(min_max_height=(256, 512), height=512, width=512, p=0.5), ]) ]), A.Compose([ A.Resize(1024, 1024), A.RandomSizedCrop(min_max_height=(256, 1025), height=256, width=256, p=1), A.OneOf([ A.HueSaturationValue(p=0.5), A.RGBShift(p=0.7) ], p=1), ]) ), A.HorizontalFlip(p=1), A.RandomBrightnessContrast(p=0.5) ]) serialized_aug = A.to_dict(aug) deserialized_aug = A.from_dict(serialized_aug) random.seed(seed) aug_data = aug(image=image, mask=mask) random.seed(seed) deserialized_aug_data = deserialized_aug(image=image, mask=mask) assert np.array_equal(aug_data['image'], deserialized_aug_data['image']) assert np.array_equal(aug_data['mask'], deserialized_aug_data['mask'])
def test_force_apply(): """ Unit test for https://github.com/albu/albumentations/issues/189 """ aug = A.Compose( [ A.OneOrOther( A.Compose( [ A.RandomSizedCrop(min_max_height=(256, 1025), height=512, width=512, p=1), A.OneOf( [ A.RandomSizedCrop(min_max_height=(256, 512), height=384, width=384, p=0.5), A.RandomSizedCrop(min_max_height=(256, 512), height=512, width=512, p=0.5), ] ), ] ), A.Compose( [ A.RandomSizedCrop(min_max_height=(256, 1025), height=256, width=256, p=1), A.OneOf([A.HueSaturationValue(p=0.5), A.RGBShift(p=0.7)], p=1), ] ), ), A.HorizontalFlip(p=1), A.RandomBrightnessContrast(p=0.5), ] ) res = aug(image=np.zeros((1248, 1248, 3), dtype=np.uint8)) assert res["image"].shape[0] in (256, 384, 512) assert res["image"].shape[1] in (256, 384, 512)
def test_transform_pipeline_serialization_with_keypoints(seed, image, keypoints, keypoint_format, labels): aug = A.Compose([ A.OneOrOther( A.Compose([ A.RandomRotate90(), A.OneOf([ A.HorizontalFlip(p=0.5), A.VerticalFlip(p=0.5), ]) ]), A.Compose([ A.Rotate(p=0.5), A.OneOf([ A.HueSaturationValue(p=0.5), A.RGBShift(p=0.7) ], p=1), ]) ), A.HorizontalFlip(p=1), A.RandomBrightnessContrast(p=0.5) ], keypoint_params={'format': keypoint_format, 'label_fields': ['labels']}) serialized_aug = A.to_dict(aug) deserialized_aug = A.from_dict(serialized_aug) random.seed(seed) aug_data = aug(image=image, keypoints=keypoints, labels=labels) random.seed(seed) deserialized_aug_data = deserialized_aug(image=image, keypoints=keypoints, labels=labels) assert np.array_equal(aug_data['image'], deserialized_aug_data['image']) assert np.array_equal(aug_data['keypoints'], deserialized_aug_data['keypoints'])
def test_transform_pipeline_serialization_with_bboxes(seed, image, bboxes, bbox_format, labels): aug = A.Compose( [ A.OneOrOther( A.Compose([ A.RandomRotate90(), A.OneOf([A.HorizontalFlip(p=0.5), A.VerticalFlip(p=0.5)]) ]), A.Compose([ A.Rotate(p=0.5), A.OneOf([A.HueSaturationValue(p=0.5), A.RGBShift(p=0.7)], p=1) ]), ), A.HorizontalFlip(p=1), A.RandomBrightnessContrast(p=0.5), ], bbox_params={ "format": bbox_format, "label_fields": ["labels"] }, ) serialized_aug = A.to_dict(aug) deserialized_aug = A.from_dict(serialized_aug) set_seed(seed) aug_data = aug(image=image, bboxes=bboxes, labels=labels) set_seed(seed) deserialized_aug_data = deserialized_aug(image=image, bboxes=bboxes, labels=labels) assert np.array_equal(aug_data["image"], deserialized_aug_data["image"]) assert np.array_equal(aug_data["bboxes"], deserialized_aug_data["bboxes"])
def create_runtime_tfms(): mean, std = [0.5] * 3, [0.5] * 3 resize_to_64 = A.SmallestMaxSize(IMG_SIZE, interpolation=cv2.INTER_AREA) out = [ A.HorizontalFlip(p=0.5), A.Normalize(mean=mean, std=std), ToTensor() ] rand_crop = A.Compose([ A.SmallestMaxSize(IMG_SIZE + 8, interpolation=cv2.INTER_AREA), A.RandomCrop(IMG_SIZE, IMG_SIZE) ]) affine_1 = A.ShiftScaleRotate(shift_limit=0, scale_limit=0.1, rotate_limit=8, interpolation=cv2.INTER_CUBIC, border_mode=cv2.BORDER_REFLECT_101, p=1.0) affine_1 = A.Compose([affine_1, resize_to_64]) affine_2 = A.ShiftScaleRotate(shift_limit=0.06, scale_limit=(-0.06, 0.18), rotate_limit=6, interpolation=cv2.INTER_CUBIC, border_mode=cv2.BORDER_REFLECT_101, p=1.0) affine_2 = A.Compose([affine_2, resize_to_64]) tfm_0 = A.Compose(out) tfm_1 = A.Compose([A.OneOrOther(affine_1, rand_crop, p=1.0), *out]) tfm_2 = A.Compose([affine_2, *out]) return [tfm_0, tfm_1, tfm_2]
def aug_tfms( size: Union[int, Tuple[int, int]], presize: Optional[Union[int, Tuple[int, int]]] = None, horizontal_flip: Optional[A.HorizontalFlip] = A.HorizontalFlip(), shift_scale_rotate: Optional[A.ShiftScaleRotate] = A.ShiftScaleRotate(), rgb_shift: Optional[A.RGBShift] = A.RGBShift(), lightning: Optional[A.RandomBrightnessContrast] = A.RandomBrightnessContrast(), blur: Optional[A.Blur] = A.Blur(blur_limit=(1, 3)), crop_fn: Optional[A.DualTransform] = partial(A.RandomSizedBBoxSafeCrop, p=0.5), pad: Optional[A.DualTransform] = partial( A.PadIfNeeded, border_mode=cv2.BORDER_CONSTANT, value=[124, 116, 104] ), ) -> List[A.BasicTransform]: """Collection of useful augmentation transforms. # Arguments size: The final size of the image. If an `int` is given, the maximum size of the image is rescaled, maintaing aspect ratio. If a `tuple` is given, the image is rescaled to have that exact size (height, width). presizing: Rescale the image before applying other transfroms. If `None` this transform is not applied. First introduced by fastai,this technique is explained in their book in [this](https://github.com/fastai/fastbook/blob/master/05_pet_breeds.ipynb) chapter (tip: search for "Presizing"). horizontal_flip: Flip around the y-axis. If `None` this transform is not applied. shift_scale_rotate: Randomly shift, scale, and rotate. If `None` this transform is not applied. rgb_shift: Randomly shift values for each channel of RGB image. If `None` this transform is not applied. lightning: Randomly changes Brightness and Contrast. If `None` this transform is not applied. blur: Randomly blur the image. If `None` this transform is not applied. crop_fn: Randomly crop the image. If `None` this transform is not applied. Use `partial` to saturate other parameters of the class. pad: Pad the image to `size`, squaring the image if `size` is an `int`. If `None` this transform is not applied. Use `partial` to sature other parameters of the class. # Returns A list of albumentations transforms. """ height, width = (size, size) if isinstance(size, int) else size tfms = [] tfms += [_resize(presize, A.SmallestMaxSize) if presize is not None else None] tfms += [horizontal_flip, shift_scale_rotate, rgb_shift, lightning, blur] # Resize as the last transforms to reduce the number of artificial artifacts created if crop_fn is not None: crop = crop_fn(height=height, width=width) tfms += [A.OneOrOther(crop, _resize(size), p=crop.p)] else: tfms += [_resize(size)] tfms += [pad(min_height=height, min_width=width) if pad is not None else None] tfms = [tfm for tfm in tfms if tfm is not None] return tfms
def crop_transform(image_size: Tuple[int, int], min_scale=0.75, max_scale=1.25, input_size=5000): return A.OneOrOther( A.RandomSizedCrop( (int(image_size[0] * min_scale), int(min(input_size, image_size[0] * max_scale))), image_size[0], image_size[1], ), A.CropNonEmptyMaskIfExists(image_size[0], image_size[1]), )
def crop_transform_xview2(image_size: Tuple[int, int], min_scale=0.4, max_scale=0.75, input_size=1024): return A.OneOrOther( A.RandomSizedCrop( (int(image_size[0] * min_scale), int(min(input_size, image_size[0] * max_scale))), image_size[0], image_size[1], ), A.Compose( [A.Resize(input_size * 2, input_size * 2), A.CropNonEmptyMaskIfExists(image_size[0], image_size[1])] ), )
def set_transforms(self) -> dict: d4_tansforms = [ A.SmallestMaxSize(self.img_size[0], interpolation=0, p=1.), # D4 Group augmentations A.HorizontalFlip(p=0.5), A.VerticalFlip(p=0.5), A.RandomRotate90(p=0.5), A.Transpose(p=0.5), ] tensor_norm = [ ToTensor(), Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]), ] geometric = [ A.SmallestMaxSize(self.img_size[0], interpolation=0, p=1.), A.ShiftScaleRotate(shift_limit=self.shift_limit, self.scale_limit, rotate_limit=self.rotate_limit, interpolation=cv2.INTER_LINEAR, border_mode=cv2.BORDER_CONSTANT, value=0, mask_value=0, p=0.5), # crop and resize A.RandomSizedCrop( (self.crop_size[0], min(self.crop_size[1], self.img_size[0], self.img_size[1])), self.img_size[0], self.img_size[1], w2h_ratio=1.0, interpolation=cv2.INTER_LINEAR, always_apply=False, p=0.2), ] resize_crop = [ A.SmallestMaxSize(max(self.img_size[0], self.img_size[1]), interpolation=0, p=1.), A.RandomCrop(self.img_size[0], self.img_size[1], p=1.), ] train_light = [ A.SmallestMaxSize(self.img_size[0], interpolation=0, p=1.), A.RandomCrop(self.img_size[0], self.img_size[1], p=1.), A.HorizontalFlip(p=0.5), A.RandomBrightnessContrast(p=0.5), ] train_medium = train_light.append([ A.ShiftScaleRotate(shift_limit=self.shift_limit, self.scale_limit, rotate_limit=self.rotate_limit, p=0.5), A.OneOf([ A.RandomBrightnessContrast(p=0.7), A.Equalize(p=0.3), A.HueSaturationValue(p=0.5), A.RGBShift(p=0.5), A.RandomGamma(p=0.4), A.ChannelShuffle(p=0.05), ], p=0.9), A.OneOf([ A.GaussNoise(p=0.5), A.ISONoise(p=0.5), A.MultiplicativeNoise(0.5), ], p=0.2), ]) valid_ade = [ A.SmallestMaxSize(self.img_size, p=1.), A.Lambda(name="Pad32", image=pad_x32, mask=pad_x32), ] # from bloodaxe # https://github.com/BloodAxe/Catalyst-Inria-Segmentation-Example/blob/master/inria/augmentations.py crop = [ #(image_size: Tuple[int, int], min_scale=0.75, max_scale=1.25, input_size=5000): A.OneOrOther( A.RandomSizedCrop((self.crop_size[0], min(self.crop_size[1], self.img_size[0], self.img_size[1])), self.img_size[0], self.img_size[1]), A.CropNonEmptyMaskIfExists(self.img_size[0], self.img_size[1]), ) ] safe_augmentations = [A.HorizontalFlip(), A.RandomBrightnessContrast()] light_augmentations = [ A.HorizontalFlip(), A.RandomBrightnessContrast(), A.OneOf([ A.ShiftScaleRotate(scale_limit=self.scale_limit, rotate_limit=self.rotate_limit, border_mode=cv2.BORDER_CONSTANT), A.IAAAffine(), A.IAAPerspective(), A.NoOp() ]), A.HueSaturationValue(), ] medium_augmentations = [ A.HorizontalFlip(), A.ShiftScaleRotate(scale_limit=self.scale_limit, rotate_limit=self.rotate_limit, border_mode=cv2.BORDER_CONSTANT), # Add occasion blur/sharpening A.OneOf([A.GaussianBlur(), A.IAASharpen(), A.NoOp()]), # Spatial-preserving augmentations: A.OneOf( [A.CoarseDropout(), A.MaskDropout(max_objects=5), A.NoOp()]), A.GaussNoise(), A.OneOf([ A.RandomBrightnessContrast(), A.CLAHE(), A.HueSaturationValue(), A.RGBShift(), A.RandomGamma() ]), # Weather effects A.RandomFog(fog_coef_lower=0.01, fog_coef_upper=0.3, p=0.1), ] hard_augmentations = [ A.RandomRotate90(), A.Transpose(), A.RandomGridShuffle(), A.ShiftScaleRotate(scale_limit=self.scale_limit, rotate_limit=self.rotate_limit, border_mode=cv2.BORDER_CONSTANT, mask_value=0, value=0), A.ElasticTransform(border_mode=cv2.BORDER_CONSTANT, alpha_affine=5, mask_value=0, value=0), # Add occasion blur A.OneOf([ A.GaussianBlur(), A.GaussNoise(), A.IAAAdditiveGaussianNoise(), A.NoOp() ]), # D4 Augmentations A.OneOf( [A.CoarseDropout(), A.MaskDropout(max_objects=10), A.NoOp()]), # Spatial-preserving augmentations: A.OneOf([ A.RandomBrightnessContrast(brightness_by_max=True), A.HueSaturationValue(), A.RGBShift(), A.RandomGamma(), A.NoOp(), ]), # Weather effects A.OneOf([ A.RandomFog(fog_coef_lower=0.01, fog_coef_upper=0.3, p=0.1), A.NoOp() ]), ] TRANSFORMS = { "d4": d4_tansforms, "resize_crop": resize_crop, "geometric": geometric, "light": train_light, "medium": train_medium, "ade_valid": valid_ade, "flip_bright": safe_augmentations, "crop": crop, "inria_light": light_augmentations, "inria_medium": medium_augmentations, "inria_hard": hard_augmentations, "inria_valid": safe_augmentations, } return TRANSFORMS def get_transforms(self): augs = [] if self.augs_name: augs = self.set_transforms[self.augs_name] augs.append( A.Resize(height=self.img_size[0], width=self.img_size[1], p=1.0)) if self.use_d4: augs.append(self.set_transforms["d4"]) if self.vflip: augs.append(A.VerticalFlip(p=0.5)) if self.hflip: augs.append(A.HorizontalFlip(p=0.5)) if self.normalise: augs.append(A.Normalize()) return A.Compose(augs)