albumentations icon indicating copy to clipboard operation
albumentations copied to clipboard

how to add custom data aug operation

Open gentlebreeze1 opened this issue 3 years ago • 7 comments

how to add custom data aug operation to albumentations.Compose?any example?

gentlebreeze1 avatar Jul 01 '21 06:07 gentlebreeze1

Hey @gentlebreeze1

We have plans to add a step-by-step tutorial for creating a new augmentation. For now, I think the best option is to check PRs that implement new augmentations as a reference, e.g., #843, #490

creafz avatar Jul 04 '21 11:07 creafz

Has there been an update on this issue?

nsriniva03 avatar Jul 18 '22 21:07 nsriniva03

  • aslo here for updates

kondratevakate avatar Oct 28 '22 14:10 kondratevakate

Though one should ideally do something like https://github.com/albumentations-team/albumentations/pull/490/files ie modify functional.py, test_transforms.py and transforms but if you already have a long albumentation augmentations pipeline and just want to add aug in between than one can use something like:

Depending upon the use case one can inherit ImageOnlyTransform, DualTransform etc There are a lot of other methods that one can too use like apply_to_keypoints etc

class MyCustomAug(DualTransform):
   def __init__(self, parameter_1, parameter_2, always_apply=True, p=1.0):
       super().__init__(always_apply, p)
       self.parameter_1 = parameter_1
       self.parameter_2 = parameter_2
   def apply(self, img, **params):
       #apply augmentation to images
   def apply_to_mask(self, mask, **params):
       #apply augmentation to masks

Himanshunitrr avatar Apr 14 '23 06:04 Himanshunitrr

to give somebody a hint based on my own experiments, for image only argumentations. Key to use custom transforms is based on it's interface https://github.com/albumentations-team/albumentations/blob/master/albumentations/core/transforms_interface.py

see following pipline examples

import cv2
from albumentations.core.transforms_interface import ImageOnlyTransform
import albumentations as A

class RandomA(ImageOnlyTransform):
    """
    RamdomA transformation
    """
    def __init__(self, safe_db_lists=[], prob =0.5) -> None:
        super(RandomA, self).__init__()
        self.safe_db_lists = safe_db_lists
        self.prob = prob

    def apply(self, img, copy=True, **params):
        if np.random.uniform(0, 1) > self.prob:
            return img
        if copy:
            img = img.copy()
        # some of your logic here
        return img


class RandomB(ImageOnlyTransform):
    """
    RandomB transformation
    """
    def __init__(self, safe_db_lists=[], prob =0.5) -> None:
        super(RandomB, self).__init__()
        self.safe_db_lists = safe_db_lists
        self.prob = prob

    def apply(self, img, copy=True, **params):
        if np.random.uniform(0, 1) > self.prob:
            return img
        if copy:
            img = img.copy()
        # some of your logic here
        return img


# test compose pipeline
image = cv2.imread('test.jpg')
transforms = A.Compose(transforms=[
    RrandomA(prob=1.0),
    RandomB(prob=1.0),
])


# and new_image is the target image dict
new_image_dict = transforms(image=image)
new_image = new_image_dict['image']

PeterAdam2015 avatar Jun 29 '23 07:06 PeterAdam2015

Any updates?

ogencoglu avatar Oct 04 '23 21:10 ogencoglu

to give somebody a hint based on my own experiments, for image only argumentations. Key to use custom transforms is based on it's interface https://github.com/albumentations-team/albumentations/blob/master/albumentations/core/transforms_interface.py

see following pipline examples

import cv2
from albumentations.core.transforms_interface import ImageOnlyTransform
import albumentations as A

class RandomA(ImageOnlyTransform):
    """
    RamdomA transformation
    """
    def __init__(self, safe_db_lists=[], prob =0.5) -> None:
        super(RandomA, self).__init__()
        self.safe_db_lists = safe_db_lists
        self.prob = prob

    def apply(self, img, copy=True, **params):
        if np.random.uniform(0, 1) > self.prob:
            return img
        if copy:
            img = img.copy()
        # some of your logic here
        return img


class RandomB(ImageOnlyTransform):
    """
    RandomB transformation
    """
    def __init__(self, safe_db_lists=[], prob =0.5) -> None:
        super(RandomB, self).__init__()
        self.safe_db_lists = safe_db_lists
        self.prob = prob

    def apply(self, img, copy=True, **params):
        if np.random.uniform(0, 1) > self.prob:
            return img
        if copy:
            img = img.copy()
        # some of your logic here
        return img


# test compose pipeline
image = cv2.imread('test.jpg')
transforms = A.Compose(transforms=[
    RrandomA(prob=1.0),
    RandomB(prob=1.0),
])


# and new_image is the target image dict
new_image_dict = transforms(image=image)
new_image = new_image_dict['image']

This works but note that ImageOnlyTransform extends BasicTransform which does not get applied to every image. To apply to every input you need to pass always_apply=True to super(...).__init__()

ianbenlolo avatar Nov 06 '23 21:11 ianbenlolo