def augment(self): #p=.5): return Compose([ RandomRotate90(), Flip(), Transpose(), ShiftScaleRotate( shift_limit=0.0625, scale_limit=0.2, rotate_limit=45, p=.2), OneOf([ OpticalDistortion(p=0.3), GridDistortion(p=.1), IAAPiecewiseAffine(p=0.3), ], p=0.2), OneOf([ IAAAdditiveGaussianNoise(), GaussNoise(), ], p=0.2), RandomCrop(256, 256, p=1), OneOf([ MedianBlur(blur_limit=3, p=.1), Blur(blur_limit=3, p=.1), ], p=0.2), OneOf([ CLAHE(clip_limit=2), IAASharpen(), IAAEmboss(), RandomContrast(), RandomBrightness(), ], p=0.3), HueSaturationValue(p=0.7), ], p=1)
def img_augment(p=1.): return Compose( [ #RandomSizedCrop((300, 300), img_sz, img_sz, p=1.), Resize(img_sz, img_sz), HorizontalFlip(p=0.8), #RandomRotate90(p=0.25), OneOf([ CLAHE(clip_limit=2), IAASharpen(), IAAEmboss(), RandomContrast(), RandomBrightness(), ], p=0.3), # ShiftScaleRotate( shift_limit=0.0625, scale_limit=0.1, rotate_limit=10, p=.75), RandomBrightnessContrast(p=0.2), #GaussNoise(), #Blur(blur_limit=3, p=.33), #OpticalDistortion(p=.33), #GridDistortion(p=.33), #HueSaturationValue(p=.33) ], p=p)
def get_augmentations(p=1.0): return Compose([ RandomSizedCrop((250, 600), 224, 224), OneOf([ IAAAdditiveGaussianNoise(), GaussNoise(), ], p=1), OneOf([ MotionBlur(p=.6), MedianBlur(blur_limit=3, p=0.6), Blur(blur_limit=3, p=0.6), ], p=1), ShiftScaleRotate(shift_limit=0.0825, scale_limit=0.3, rotate_limit=30, p=1), OneOf([ OpticalDistortion(p=0.5), GridDistortion(p=.4), IAAPiecewiseAffine(p=0.5), ], p=0.8), OneOf([ CLAHE(clip_limit=2), IAASharpen(), IAAEmboss(), RandomBrightnessContrast(), ], p=0.9), HueSaturationValue(p=0.3), ], p=p)
def select_aug(atype, param, p=1): from albumentations import JpegCompression, Blur, Downscale, CLAHE, HueSaturationValue, \ RandomBrightnessContrast, IAAAdditiveGaussianNoise, GaussNoise, GaussianBlur, MedianBlur, MotionBlur if atype == 'JpegCompression': trans_aug = JpegCompression(quality_lower=param, quality_upper=param, p=p) # strong_aug_pixel() elif atype == 'Blur': trans_aug = Blur(blur_limit=param, p=p) elif atype == 'Downscale': trans_aug = Downscale(scale_min=param, scale_max=param, p=p) elif atype == 'CLAHE': trans_aug = CLAHE(clip_limit=param, p=p) elif atype == 'HueSaturationValue': trans_aug = HueSaturationValue(hue_shift_limit=param, sat_shift_limit=param, val_shift_limit=param, p=p) elif atype == 'RandomBrightnessContrast': trans_aug = RandomBrightnessContrast(brightness_limit=param, contrast_limit=param, p=p) elif atype == 'IAAAdditiveGaussianNoise': trans_aug = IAAAdditiveGaussianNoise(loc=param, p=p) elif atype == 'GaussNoise': trans_aug = GaussNoise(mean=param, p=p) elif atype == 'GaussianBlur': trans_aug = GaussianBlur(blur_limit=param, p=p) elif atype == 'MedianBlur': trans_aug = MedianBlur(blur_limit=param, p=p) elif atype == 'MotionBlur': trans_aug = MotionBlur(blur_limit=param, p=p) else: raise NotImplementedError(atype) aug = trans_aug return aug
def pixel_aug(p=.5): print('[DATA]: pixel aug') from albumentations import JpegCompression, Blur, Downscale, CLAHE, HueSaturationValue, \ RandomBrightnessContrast, IAAAdditiveGaussianNoise, GaussNoise, GaussianBlur, MedianBlur, MotionBlur, \ Compose, OneOf from random import sample, randint, uniform return Compose([ # Jpeg Compression OneOf([ JpegCompression(quality_lower=20, quality_upper=99, p=1) ], p=0.2), # Gaussian Noise OneOf([ IAAAdditiveGaussianNoise(loc=randint(1, 9), p=1), GaussNoise(mean=uniform(0, 10.0), p=1), ], p=0.3), # Blur OneOf([ GaussianBlur(blur_limit=15, p=1), MotionBlur(blur_limit=19, p=1), Downscale(scale_min=0.3, scale_max=0.99, p=1), Blur(blur_limit=15, p=1), MedianBlur(blur_limit=9, p=1) ], p=0.4), # Color OneOf([ CLAHE(clip_limit=4.0, p=1), HueSaturationValue(p=1), RandomBrightnessContrast(p=1), ], p=0.1) ], p=p)
def strong_aug(p=.5): return Compose([ HorizontalFlip(), OneOf([ IAAAdditiveGaussianNoise(), GaussNoise(), ], p=0.4), OneOf([ MotionBlur(p=.2), MedianBlur(blur_limit=3, p=.1), Blur(blur_limit=3, p=.1), ], p=0.3), OneOf([ OpticalDistortion(p=0.3), GridDistortion(p=.1), IAAPiecewiseAffine(p=0.3), ], p=0.2), OneOf([ CLAHE(clip_limit=2), IAASharpen(), RandomContrast(), RandomBrightness(), ], p=0.3), HueSaturationValue(p=0.3), ChannelShuffle(), Cutout(num_holes=20, max_h_size=16, max_w_size=16) ], p=p)
def strong_aug(p=1): return Compose([ RandomRotate90(), Flip(), Transpose(), OneOf([ IAAAdditiveGaussianNoise(), GaussNoise(), ], p=0.2), OneOf([ MotionBlur(p=0.2), MedianBlur(blur_limit=3, p=0.1), Blur(blur_limit=3, p=0.1), ], p=0.2), OneOf([ CLAHE(clip_limit=2), IAASharpen(), IAAEmboss(), RandomBrightnessContrast(), ], p=0.3), HueSaturationValue(p=0.3), ], p=p)
def __get_augmentation(self): return [ #HorizontalFlip(p=0.5), OneOf([ IAAAdditiveGaussianNoise(), GaussNoise(), MultiplicativeNoise() ], p=0.25), #OneOf([ # MotionBlur(p=0.2), # MedianBlur(blur_limit=3, p=0.1), # Blur(blur_limit=3, p=0.1), #], p=0.2), #ShiftScaleRotate( #shift_limit=0.0625, #scale_limit=0.2, # rotate_limit=10, # p=0.25 #), OneOf( [ CLAHE(clip_limit=2), IAASharpen(), RandomBrightnessContrast(), #OpticalDistortion() ], p=0.3), #HueSaturationValue(p=0.3), ]
def train_aug(self, image, label): aug = Compose( [ OneOf( [CLAHE(), IAASharpen(), IAAEmboss()], p=0.5), # OneOf([IAAAdditiveGaussianNoise(), GaussNoise()], p=0.2), # OneOf([MotionBlur(p=0.2), MedianBlur(blur_limit=3, p=0.1), Blur(blur_limit=3, p=0.1)], p=0.2), RandomContrast(), RandomBrightness(), # ChannelShuffle(), RandomRotate90(), Flip(), # RandomScale(scale_limit=(0.0, 0.1)), OneOf([ ElasticTransform(), OpticalDistortion(), GridDistortion(), IAAPiecewiseAffine() ], p=0.5), # HueSaturationValue(p=0.3), ], p=0.9) augmented = aug(image=image, mask=label) augmented = ToGray(p=1)(image=augmented['image'], mask=augmented['mask']) augmented = RandomCrop(256, 256)(image=augmented['image'], mask=augmented['mask']) image, label = augmented['image'], augmented['mask'] return image, label
def augment(self, image, mask): aug = Compose([ OneOf([ RandomSizedCrop(min_max_height=(50, 101), height=self.out_size, width=self.out_size, p=0.5), PadIfNeeded( min_height=self.out_size, min_width=self.out_size, p=0.5) ], p=1), VerticalFlip(p=0.5), RandomRotate90(p=0.5), OneOf([ ElasticTransform(p=0.5, alpha=120, sigma=120 * 0.05, alpha_affine=120 * 0.03), GridDistortion(p=0.5), OpticalDistortion(p=1, distort_limit=2, shift_limit=0.5) ], p=0.8), CLAHE(p=0.8), RandomBrightnessContrast(p=0.8), RandomGamma(p=0.8) ]) augmented = aug(image=image, mask=mask) image_heavy = augmented['image'] mask_heavy = augmented['mask'] return image_heavy, mask_heavy
def augmentation(image, mask, noise=False, transform=False, clahe=True, r_bright=True, r_gamma=True): aug_list = [ VerticalFlip(p=0.5), HorizontalFlip(p=0.5), RandomRotate90(p=0.5), ] if r_bright: aug_list += [RandomBrightnessContrast(p=.5)] if r_gamma: aug_list += [RandomGamma(p=.5)] if clahe: aug_list += [CLAHE(p=1., always_apply=True)] if noise: aug_list += [GaussNoise(p=.5, var_limit=1.)] if transform: aug_list += [ ElasticTransform(p=.5, sigma=1., alpha_affine=20, border_mode=0) ] aug = Compose(aug_list) augmented = aug(image=image, mask=mask) image_heavy = augmented['image'] mask_heavy = augmented['mask'] return image_heavy, mask_heavy
def get_corrupter(self): distortion_augs = OneOf([OpticalDistortion(p=1), GridDistortion(p=1)], p=1) effects_augs = OneOf([ IAASharpen(p=1), IAAEmboss(p=1), IAAPiecewiseAffine(p=1), IAAPerspective(p=1), CLAHE(p=1) ], p=1) misc_augs = OneOf([ ShiftScaleRotate(p=1), HueSaturationValue(p=1), RandomBrightnessContrast(p=1) ], p=1) blur_augs = OneOf( [Blur(p=1), MotionBlur(p=1), MedianBlur(p=1), GaussNoise(p=1)], p=1) aug = Compose([distortion_augs, effects_augs, misc_augs, blur_augs]) return aug
def get_transforms(): Compose([ RandomRotate90(), Flip(), Transpose(), OneOf([ IAAAdditiveGaussianNoise(), GaussNoise(), ], p=0.2), OneOf([ MotionBlur(p=.2), MedianBlur(blur_limit=3, p=0.1), Blur(blur_limit=3, p=0.1), ], p=0.2), ShiftScaleRotate(shift_limit=0.0625, scale_limit=0.2, rotate_limit=90, p=0.5), OneOf([ OpticalDistortion(p=0.3), GridDistortion(p=.1), IAAPiecewiseAffine(p=0.3), ], p=0.2), OneOf([ CLAHE(clip_limit=2), IAASharpen(), IAAEmboss(), RandomBrightnessContrast(), ], p=0.3), HueSaturationValue(p=0.3), ], p=0.8)
def strong_aug(config, aug_prob): return Compose( [ # Resize(config.image_height, config.image_width, always_apply=True), RandomSizedCrop( p=config.random_sized_crop_prob, min_max_height=(int( config.image_height * config.min_max_height), config.image_height), height=config.image_height, width=config.image_width, w2h_ratio=config.image_width / config.image_height), HorizontalFlip(p=config.horizontal_flip_prob), RandomGamma(p=config.random_gamma_prob), RandomContrast(p=config.random_contrast_prob, limit=config.random_contrast_limit), RandomBrightness(p=config.random_brightness_prob, limit=config.random_brightness_limit), OneOf([ MotionBlur(p=config.motion_blur_prob), MedianBlur(blur_limit=config.median_blur_limit, p=config.median_blur_prob), Blur(blur_limit=config.blur_limit, p=config.blur_prob), ], p=config.one_of_blur_prob), CLAHE(clip_limit=config.clahe_limit, p=config.clahe_prob), IAAEmboss(p=config.iaaemboss_prob), HueSaturationValue(p=config.hue_saturation_value_prob, hue_shift_limit=config.hue_shift_limit, sat_shift_limit=config.sat_shift_limit, val_shift_limit=config.val_shift_limit) ], p=aug_prob)
def __init__(self, root_dir, partition, augment): self.root_dir = root_dir self.list_IDs = os.listdir(os.path.join(self.root_dir, 'y_{}'.format(partition))) self.partition = partition self.augment = augment self.to_tensor = transforms.ToTensor() self.augmentator = Compose([ # Non destructive transformations VerticalFlip(p=0.6), HorizontalFlip(p=0.6), RandomRotate90(), Transpose(p=0.6), ShiftScaleRotate(p=0.45, scale_limit=(0.1, 0.3)), # # Non-rigid transformations # ElasticTransform(p=0.25, alpha=160, sigma=180 * 0.05, alpha_affine=120 * 0.03), Blur(blur_limit=3, p=0.2), # Color augmentation RandomBrightness(p=0.5), RandomContrast(p=0.5), RGBShift(p=0.3), RandomGamma(p=0.5), CLAHE(p=0.5) ] )
def hard_transform(image_size: int = 256, p: float = 0.5, **kwargs): """Hard augmentations (on training)""" _add_transform_default_params(kwargs) transforms = Compose([ ShiftScaleRotate( shift_limit=0.1, scale_limit=0.1, rotate_limit=15, border_mode=cv2.BORDER_REFLECT, p=p, ), IAAPerspective(scale=(0.02, 0.05), p=p), OneOf([ HueSaturationValue(p=p), ToGray(p=p), RGBShift(p=p), ChannelShuffle(p=p), ]), RandomBrightnessContrast(brightness_limit=0.5, contrast_limit=0.5, p=p), RandomGamma(p=p), CLAHE(p=p), JpegCompression(quality_lower=50, p=p), PadIfNeeded(image_size, image_size, border_mode=cv2.BORDER_CONSTANT), ], **kwargs) return transforms
def get_train_transforms(): augmentations = Compose([ Resize(236,236), Flip(), OneOf([ IAAAdditiveGaussianNoise(p=.5), GaussNoise(p=.4), ], p=0.4), OneOf([ MotionBlur(p=0.6), Blur(blur_limit=3, p=0.2), ], p=0.4), ShiftScaleRotate(shift_limit=0.0725, scale_limit=0.2, rotate_limit=45, p=0.6), OneOf([ OpticalDistortion(p=0.3), GridDistortion(p=0.4), IAAPiecewiseAffine(p=0.2), ], p=0.3), OneOf([ CLAHE(clip_limit=2), IAASharpen(), IAAEmboss(), RandomBrightnessContrast(), ], p=0.25), HueSaturationValue(p=0.3), CenterCrop(224,224), Normalize( mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225] ), ToTensor() ]) return lambda img:augmentations(image=np.array(img))
def build_transforms(mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225), divide_by=255.0, scale_limit=0.0, shear_limit=0, rotate_limit=0, brightness_limit=0.0, contrast_limit=0.0, clahe_p=0.0, blur_p=0.0, autoaugment=False, ): norm = Normalize(mean=mean, std=std, max_pixel_value=divide_by) if autoaugment: train_transform = Compose([ torch_custom.AutoAugmentWrapper(p=1.0), torch_custom.RandomCropThenScaleToOriginalSize(limit=scale_limit, p=1.0), norm, ]) else: train_transform = Compose([ IAAAffine(rotate=(-rotate_limit, rotate_limit), shear=(-shear_limit, shear_limit), mode='constant'), RandomBrightnessContrast(brightness_limit=brightness_limit, contrast_limit=contrast_limit), MotionBlur(p=blur_p), CLAHE(p=clahe_p), torch_custom.RandomCropThenScaleToOriginalSize(limit=scale_limit, p=1.0), norm, ]) eval_transform = Compose([norm]) return train_transform, eval_transform
def __init__(self, is_train: bool, to_pytorch: bool, preprocess: callable): if is_train: self._aug = Compose([ preprocess, OneOf([ Compose([ HorizontalFlip(p=0.5), GaussNoise(p=0.5), OneOf([ RandomBrightnessContrast(), RandomGamma(), ], p=0.5), Rotate(limit=20, border_mode=cv2.BORDER_CONSTANT), ImageCompression(), CLAHE(), Downscale(scale_min=0.2, scale_max=0.9, p=0.5), ISONoise(p=0.5), MotionBlur(p=0.5) ]), HorizontalFlip(p=0.5) ]) ], p=1) else: self._aug = preprocess self._need_to_pytorch = to_pytorch
def get_photometric(self): coeff = int(3 * self.strength) k = max(1, coeff if coeff % 2 else coeff - 1) return Compose([ OneOf([ CLAHE(clip_limit=2, p=.8), IAASharpen(p=.8), IAAEmboss(p=.8), ], p=0.6), OneOf([ IAAAdditiveGaussianNoise(p=.6), GaussNoise(p=.7), ], p=.5), OneOf([ MotionBlur(p=.5), MedianBlur(blur_limit=k, p=.3), Blur(blur_limit=k, p=.5), ], p=.5), OneOf([ RandomContrast(), RandomBrightness(), ], p=.8), ], p=0.95)
def aug_train(resolution, p=1): return Compose([Resize(resolution, resolution), OneOf([ HorizontalFlip(), VerticalFlip(), RandomRotate90(), Transpose()], p=0.5), OneOf([ IAAAdditiveGaussianNoise(), GaussNoise(), ], p=0.5), OneOf([ MotionBlur(p=.2), MedianBlur(blur_limit=3, p=0.1), Blur(blur_limit=3, p=0.1), ], p=0.5), ShiftScaleRotate(shift_limit=0.0625, scale_limit=0.2, rotate_limit=45, p=0.2), OneOf([ OpticalDistortion(p=0.3), GridDistortion(p=.1), IAAPiecewiseAffine(p=0.3), ], p=0.5), OneOf([ CLAHE(clip_limit=2), IAASharpen(), IAAEmboss(), RandomBrightnessContrast(), ], p=0.5), HueSaturationValue(p=0.3), Normalize() ], p=p)
def __init__(self, data, img_size=384, aug=True, mode='train'): self.data = data self.mode = mode if mode is 'train': self.images = data.ImageId.unique() self._aug = Compose([ HorizontalFlip(), VerticalFlip(), OneOf([ RandomRotate90(), ShiftScaleRotate(shift_limit=0.2, scale_limit=0.2, rotate_limit=0), ], p=1), OneOf([ CLAHE(), RandomBrightness(), RandomContrast(), RandomGamma() ], p=1), Normalize(), RandomCrop(img_size, img_size) # Resize(256, 256), # Resize(img_size, img_size), ]) elif mode is 'test' or mode is 'val': self.images = data.ImageId.unique() self._aug = Compose([ Normalize(), # Resize(256, 256), # Resize(img_size, img_size), # RandomCrop(img_size, img_size) # PadIfNeeded(768, 768) ]) else: raise RuntimeError()
def hard_transform(image_size=224, p=0.5): transforms = [ Cutout( num_holes=4, max_w_size=image_size // 4, max_h_size=image_size // 4, p=p ), ShiftScaleRotate( shift_limit=0.1, scale_limit=0.1, rotate_limit=15, border_mode=cv2.BORDER_REFLECT, p=p ), IAAPerspective(scale=(0.02, 0.05), p=p), OneOf( [ HueSaturationValue(p=p), ToGray(p=p), RGBShift(p=p), ChannelShuffle(p=p), ] ), RandomBrightnessContrast( brightness_limit=0.5, contrast_limit=0.5, p=p ), RandomGamma(p=p), CLAHE(p=p), JpegCompression(quality_lower=50, p=p), ] transforms = Compose(transforms) return transforms
def get_input_pair(self, image_info): dataset_path = self.dataset_path img_path = os.path.join(dataset_path, image_info["dataset_folder"], self.images_folder, image_info["name"] + '_' + image_info["position"] + '.' + self.image_type) mask_path = os.path.join(dataset_path, image_info["dataset_folder"], self.masks_folder, image_info["name"] + '_' + image_info["position"] + '.' + self.mask_type) img = Image.open(img_path) mask = Image.open(mask_path) img_array = np.array(img) mask_array = np.array(mask).astype(np.float32) aug = Compose([ RandomCrop(224, 224), RandomRotate90(), Flip(), OneOf([ RGBShift(), CLAHE(clip_limit=2) ], p=0.4), ToTensor() ], p=1) augmented = aug(image=img_array, mask=mask_array) augmented_img = augmented['image'] augmented_mask = augmented['mask'] augmented_mask = augmented_mask.squeeze().long() return {"features": augmented_img, "targets": augmented_mask}
def get_input_pair(self, image_info): dataset_path = self.dataset_path img_path = os.path.join( dataset_path, image_info["dataset_folder"], self.images_folder, image_info["name"] + '_' + image_info["position"] + '.' + self.image_type) img = Image.open(img_path) img_array = np.array(img) augm = Compose([ RandomCrop(224, 224), RandomRotate90(), Flip(), OneOf([RGBShift(), CLAHE(clip_limit=2)], p=0.4), ToTensor() ], p=1) augmented = augm(image=img_array) augmented_img = augmented['image'] return {"features": augmented_img, "targets": augmented_img}
def make(p=0.5): return Compose( [ OneOf([IAAAdditiveGaussianNoise(), GaussNoise(), ISONoise()], p=0.9), MotionBlur(p=0.3), ShiftScaleRotate(shift_limit=0.0925, scale_limit=0.4, rotate_limit=7, border_mode=cv2.BORDER_CONSTANT, value=0, p=0.6), # IAAPerspective(scale=(.055, .060), keep_size=False, p=.2), # OpticalDistortion(p=0.2), OneOf([ CLAHE(clip_limit=2), IAASharpen(), IAAEmboss(), RandomBrightnessContrast(), ], p=0.3), HueSaturationValue(p=0.3), RGBShift(40, 40, 40) ], p=p)
def strong_aug(p=.5): return Compose([ OneOf([ IAAAdditiveGaussianNoise(), GaussNoise(), ], p=0.2), OneOf([ MotionBlur(p=.2), MedianBlur(blur_limit=3, p=.1), Blur(blur_limit=3, p=.1), ], p=0.2), ShiftScaleRotate( shift_limit=0.0625, scale_limit=0.2, rotate_limit=45, p=.2), OneOf([ OpticalDistortion(p=0.3), GridDistortion(p=.1), IAAPiecewiseAffine(p=0.3), ], p=0.2), OneOf([ CLAHE(clip_limit=2), IAASharpen(), IAAEmboss(), ], p=0.3), HueSaturationValue(p=0.3), ], p=p)
def __next__(self): # while True: # shuffle image names x_batch = [] y_batch = [] indices = [] if self._totalcount >= self._n_samples: # self._index = 0 self._totalcount = 0 # self._shuffle_indices = np.random.permutation(self._shuffle_indices) raise StopIteration for i in range(self._batch_size): indices.append(self._index) self._index += 1 self._totalcount += 1 self._index = self._index % self._len if self._totalcount >= self._n_samples: break # if self._toprint: # print(indices) ids_train_batch = self._data.iloc[self._shuffle_indices[indices]] for _id in ids_train_batch.values: img_path, mask_path = self.get_image_paths(id=_id) img, mask = self.get_images_masks(img_path=img_path, mask_path=mask_path) if self._apply_aug: img, mask = ImageProcessor.augmentation( img, mask, noise=self._apply_noise, transform=self._apply_tranform) else: aug = Compose([CLAHE(always_apply=True)]) augmented = aug(image=img, mask=mask) img, mask = augmented["image"], augmented["mask"] mask = np.expand_dims(mask, axis=-1) assert mask.ndim == 3 x_batch.append(img) y_batch.append(mask) # min-max batch normalisation x_batch = np.array(x_batch, np.float32) / 255. if self._crop_size: x_batch = ImageProcessor.crop_volume(x_batch, crop_size=self._crop_size // 2) y_batch = ImageProcessor.crop_volume(np.array(y_batch), crop_size=self._crop_size // 2) if self._channel == "channel_first": x_batch = np.moveaxis(x_batch, -1, 1) y_batch = to_categorical(np.array(y_batch), num_classes=3) y_batch = np.moveaxis(y_batch, source=3, destination=1) return x_batch, y_batch
def get_rsna_train_aug(name): return Compose([ CLAHE(), ShiftScaleRotate(), Normalize(always_apply=True), ToTensorV2(always_apply=True), ], p=0.1)
class CLAHETTA(AbstractTTA): clahe = CLAHE(p=1) def preprocess(self, data: np.ndarray): return self.clahe(image=data)['image'] def postprocess(self, target: np.ndarray): return target