Image Augmentation with Python
By: Siddhant Sadangi
Tags: Python, Artificial Intelligence, Code, Computer Vision, Programming

Augmenting the Images

Now we can finally get started with the image augmentation. We will use PIL’s ImageEnhance method for this.

ImageEnhance’s Contrast() , Brightness() , Sharpness() , and Color() all load the image; then, we can use their enhance() methods to enhance those properties by any factor we choose. We will use np.linspace to choose factors between 0 and 1.5, and np.random.choice to randomize those factors.

The one-liner for doing this for contrast is:

contrast = [np.asarray(ImageEnhance.Contrast(Image.fromarray(img, 'RGB')).enhance(np.random.choice(np.linspace(0.5, 1.5, 5)))) for img in orig]

For each img in orig , we first load the image from the img array (specifying the color channel as “RGB”. Then, enhance the contrast by a random value from [0, 0.5, 1, 1.25, 1.5] ( np.linspace(0.5, 1.5, 5) will choose five linearly spaced values between 0 and 1.5). Finally, we save this image as an array within the contrast list.

Let us see how the images look with their contrast tweaked:

plt.figure(figsize=(9,9))

i = 0

for img in contrast[0:16]:

plt.subplot(4, 4, i+1)

plt.xticks([])

plt.yticks([])

plt.grid(False)

plt.imshow(img)

i += 1

plt.show()

Contrast tweaked by a factor of 0.5 to 1.5

Images with an enhancement factor < 1 look greyer, while those with a factor > 1 are more saturated. Those with a factor = 1 won’t be any different from the original.

To amplify the effect of randomness, we sequentially process the images for brightness, sharpness, and color, i.e., the output of one is the input of the other:

brightness = [np.asarray(ImageEnhance.Contrast(Image.fromarray(img, 'RGB')).enhance(np.random.choice(np.linspace(0.5, 1.5, 5)))) for img in contrast] sharpness = [np.asarray(ImageEnhance.Contrast(Image.fromarray(img, 'RGB')).enhance(np.random.choice(np.linspace(0.5, 1.5, 5)))) for img in brightness] color = [np.asarray(ImageEnhance.Contrast(Image.fromarray(img, 'RGB')).enhance(np.random.choice(np.linspace(0.5, 1.5, 5)))) for img in sharpness]

After all these operations, the images look like:

After tweaking brightness, sharpness, and color

We are just left with two more operations — flip and rotate.

For flip, we will use cv2.flip() . It takes the image and a value between 0, 1 and -1. For 0, it flips vertically; for 1, it flips horizontally; and for -1, it flips both horizontally and vertically. We can randomize these values to randomize the flip, and we can also randomize choosing if the image will be flipped or not. The one-liner for this is:

flip = [cv2.flip(img, np.random.choice([0, 1, -1])) if np.random.choice([0, 1]) else img for img in color]

If np.random.choice([0, 1]) is 0, we don’t flip and return the input; otherwise, we flip depending on np.random.choice([0, 1, -1]) .

Rotating is straightforward. We load the image from the image array and rotate it by as many degrees as we want. To avoid having to fill, we’ll be randomly rotating the images by 0 (no rotation), 90, 180, or 270 degrees:

rotate = [Image.fromarray(img, 'RGB').rotate(np.random.choice([0, 90, 180, 270])) for img in flip]

The final output after all these operations (along with the original images) looks like:

We can then save these images in a separate “augmented” folder:

import os

for i, image in tqdm(enumerate(rotate)):

directory = paths[i].rsplit('/', 3)[0] + '/augmented/' + paths[i].rsplit('/', 2)[1]+ '/'

os.makedirs(directory, exist_ok = True)

image.save(directory + paths[i].rsplit('/', 2)[2])

In addition to the steps we discussed, you can also add noise and blur to your image as a part of augmentation. These are described in my article on generating text CAPTCHAs in Python: