Proposal to add "np.rot90" to data aug

Open Issue: https://github.com/fastai/fastai/issues/1653

Basically would like a data aug transform thats like np.rot90(…) A discrete rotation only transform resulting in 0, 90, 180, 270.

Motivation:
I don’t want to use dihedral for some images because the reflected version is not valid. This applies to text in quite a few languages. And even if it is harmless, it may still be wasteful since you are diluting the training set with unrealistic samples. You may have to use TTA to take advantage but that drag down the inference side.

Please give me any feedback to if this will be general useful enough to be added the library. And also if the name “rot90_affine” is appropriate.

Note
Code sample how to add this yourself is at

1 Like

Here’s for shear, not sure if this is widely desired.

def _shear(degrees:uniform):
    "Shear image by `degrees`."
    shear = degrees * math.pi / 180
    return [[1., -sin(shear), 0.],
            [0., cos(shear), 0.],
            [0., 0., 1.]]

shear = TfmAffine(_shear)

tfms = [shear(degrees=(-20., 20.))]
[get_sample_image().apply_tfms(tfms, size=224, padding_mode='zeros').show(ax=ax) 
 for i, ax in enumerate(plt.subplots(rows, cols, figsize = (width, height))[1].flatten())
];

39%20PM

Oh shear isn’t in our affine transforms? Then that’s because I forgot, I had implemented it.
You can definitely put it in a PR!

Sorry, not clear what you said. Did you say you have already implemented? I could have missed this from reading the docs.

Note: depending on your image, a gaussian blur + shear can be a pretty good approx with out of focus motion blurring.

Yes I had, but apparently I forgot to package it because it’s not in fastai.

I know this thread is quite old, but I ran into the same issue and wanted to share my solution. Below is a batch transform that does a random 0,90,180 or 270 rotation to TensorImage and TensorMask. This is useful when performing segmentation on datasets where lossless rotations are required, such as satellite imagery. You can simply use it like this batch_tfms=[BatchRot90()] . As it is a batch transform it happens on the GPU and is very fast.

class BatchRot90(RandTransform):
    "Rotate image and mask by 0, 90, 180, or 270 degrees"
    split_idx,order = None, 2
    def __init__(self, p=1): 
        super().__init__(p=p)
        self.rots = 0

    def before_call(self, b, split_idx):
        if random.random() < self.p:
            self.rot = random.choice([0,1,2,3])
        else:
            self.rot = 0
                    
    def encodes(self, x:(TensorImage, TensorMask)):
        return x.rot90(self.rot, [-2, -1])