The standard form of using imgaug
is in a deferred way, i.e. you first "build" your augmentation sequence and then apply it many times to augment data. imgaug
then handles the augmentation almost entirely on its own. This form of using the library is similar to e.g. tensorflow. In the case of imgaug
it has a few advantages:
Sequential(..., random_order=True)
instance). This greatly increases the space of possible augmentations. Implementing such a random order oneself will likely end up with yet another architecture that lacks control flow.Sometimes(...)
or SomeOf(...)
. This is easier to implement oneself than random order, but still leads to quite some repeated code between projects.imgaug
the method Augmenter.pool()
is such an entry point. It starts a wrapper around multiprocessing.Pool
that is optimized for augmentation (e.g. uses different random states between child processes to guarantee that each CPU core generates different augmentations).It does however also have disadvantages, with the main one being that errors can be quite a bit harder to debug. If you don't need the above mentioned advantages, it is possible to execute imgaug
in a non-deferred way, similar to e.g. pytorch. The implementation of this is very similar to the standard way in imgaug
, except that you instantiate each augmenter on its own and later on also apply it on its own. The below code block shows an example:
import numpy as np
import imgaug as ia
from imgaug import augmenters as iaa
%matplotlib inline
ia.seed(3)
class AugSequence:
def __init__(self):
# instantiate each augmenter and save it to its own variable
self.affine = iaa.Affine(rotate=(-20, 20), translate_px={"x": (-10, 10), "y": (-5, 5)})
self.multiply = iaa.Multiply((0.9, 1.1))
self.contrast = iaa.LinearContrast((0.8, 1.2))
self.gray = iaa.Grayscale((0.0, 1.0))
def augment_images(self, x):
# apply each augmenter on its own, one by one
x = self.affine(images=x)
x = self.multiply(images=x)
x = self.contrast(images=x)
x = self.gray(images=x)
return x
aug = AugSequence()
image = ia.quokka_square(size=(256, 256)) # uint8 array of shape (256, 256, 3)
images_aug = aug.augment_images([image, image])
print("Before:")
ia.imshow(np.hstack([image, image]))
print("After:")
ia.imshow(np.hstack(images_aug))
Before:
After:
It is also possible to re-instantiate augmenters each time they are used for augmentation. In theory, this incurs a tiny performance penalty (as e.g. parameters have to be parsed each time). The below code block shows an example.
ia.seed(3)
def augment_images(x):
x = iaa.Affine(rotate=(-20, 20))(images=x)
x = iaa.Multiply((0.9, 1.1))(images=x)
x = iaa.LinearContrast((0.8, 1.2))(images=x)
x = iaa.Grayscale((0.0, 1.0))(images=x)
return x
images_aug = augment_images([image, image])
print("Before:")
ia.imshow(np.hstack([image, image]))
print("After:")
ia.imshow(np.hstack(images_aug))
Before: