Большинству моделей требуется хороший объем данных для обучения, тестирования и проверки. Эти данные не всегда легко доступны для удовлетворения потребностей созданной вами модели. Расширение данных — это отличный способ получить больше от уже имеющихся данных.

Недавно мне нужно было создать модель оптического распознавания символов для сценария, который был необычным и над которым раньше особо не работали, поэтому мне нужно было получить рукописные образцы, но я не мог получить достаточное количество рукописных образцов, попросив друзей за помощь или аутсорсинг работы.

В дело вступает магия аугментации: вместо того, чтобы рисовать все возможные вариации персонажа в сценарии, вы рисуете несколько из них вручную и выполняете аугментацию. Мы сможем получить множество изображений из одного изображения, используя увеличение изображения.

PyTorch имеет доступный модуль под названием torchvision.transforms, который позволяет нам дополнять изображения различными способами, позволяя нам создавать несколько изображений из одного изображения, что, в свою очередь, помогает нам создавать более плотный набор данных. Во-первых, мы рассмотрим некоторые базовые дополнения с помощью torchvision.transforms, а в конце закончим скриптом, который позволит вам анализировать иерархические папки изображений, дополнять их, а затем сохранять в той же иерархической структуре. . Модуль torchvision.transforms делает выполнение аугментации очень плавным и простым.

Все это можно сделать и с библиотекой OpenCV, но мы ее использовать не будем.

Прежде чем двигаться дальше, убедитесь, что все эти библиотеки установлены, импортированы и готовы к работе. (используя блокнот ipython)

import PIL
import torch 
from PIL import Image
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
import sys
import torchvision.transforms as T

Очевидно, нам понадобится изображение для работы, иначе вся статья будет лишней. Поскольку я хотел бы думать, что у меня есть немного радости в жизни, я не буду использовать рукописное письмо или что-то скучное вместо этого, мы будем использовать изображение милого золотистого ретривера.

Давайте откроем изображение с помощью библиотеки PIL.Image и сохраним его в переменной с именем orig_img.

orig_img = PIL.Image.open(Path('dog.png'))

Теперь давайте покажем изображение, с которым мы будем работать, используя библиотеку matplotlib.pyplot (plt.imshow(path)).

np.asarray(orig_img).shape
plt.imshow(orig_img)
orig_img.show()

Теперь давайте повозимся и расчленим это изображение.

1. Измените размер изображения

Иногда изображения слишком велики для обработки, поэтому мы изменяем их размер, чтобы наши модели можно было эффективно обучать. Имейте в виду, что этот процесс необходимо выполнять для всех изображений, даже после увеличения, поскольку сверточные нейронные сети обучаются только на данных изображений одинакового размера. С другой стороны, рекуррентные нейронные сети — это то, с чем вы можете весело провести время, они будут обучаться на любом размере.

resize_transform = T.Resize((32,32))
resized_image=resize_transform(orig_img)
plt.imshow(resized_image)

2. Преобразование изображения в оттенки серого

Преобразование изображения в представление в градациях серого используется для извлечения дескрипторов из изображения, преобразование изображения в градации серого требует меньше вычислительных ресурсов, чем обработка изображения в цвете. В OpenCV также есть очень простой способ преобразования изображений в оттенки серого, я бы сказал, что это примерно столько же усилий, но это для другой статьи.

grayscale_transform = T.Grayscale(3)
grayscaled_image=grayscale_transform(orig_img)
plt.imshow(grayscaled_image)

3. Вращение изображения

Поворот изображения — это обычная процедура обработки изображений, которая дает модели различные функции для извлечения и сопоставления. Это также помогает увеличить размер обучающих данных за счет создания различных точек зрения для модели, на которой она будет обучаться. Я выполнил 3 поворота на 45°, 65° и 85° соответственно, вы можете установить его случайным образом или указать свои собственные углы поворота.

random_rotation_transformation_45 = T.RandomRotation(45)
random_rotation_transformation_85 = T.RandomRotation(85)
random_rotation_transformation_65 = T.RandomRotation(65)
plt.imshow(random_rotation_transformation_45(orig_img))

plt.imshow(random_rotation_transformation_85(orig_img))

plt.imshow(random_rotation_transformation_65(orig_img))

4 . Случайный урожай

В ситуациях реального времени объекты не всегда полностью видны на изображении или в том же масштабе, что и наши обучающие данные, поэтому, когда мы обучаем нашу модель, мы хотим добавить немного разнообразия в набор данных, просто обучая модель на части изображения, чтобы он мог сделать точный прогноз, даже когда весь объект не виден (да, я знаю, что не могу назвать собаку объектом, но сейчас не время быть политкорректным), поэтому мы обрезать изображение и создать новое изображение из обрезанной части.

size_of_crop = 560
random_crops = T.RandomCrop(size = size_of_crop)
required_image = random_crops(orig_img)

plt.imshow(required_image)

5. Размытие по Гауссу

Размытие по Гауссу используется для удаления шума и пятен с изображения. Размытие по Гауссу выполняется путем сглаживания вектора изображения с помощью функции Гаусса. Это помогает удалить высокочастотные компоненты, которые вызывают обучение ложных функций. Мы можем контролировать уровень сглаживания, изменяя значение сигмы при передаче параметра в функцию.

gausian_blur_transformation_13 = T.GaussianBlur(kernel_size = (7,13), sigma = (6 , 7))
gausian_blur_transformation_56 = T.GaussianBlur(kernel_size = (7,13), sigma = (2 , 9))
gausian_blurred_image_13 = gausian_blur_transformation_13(orig_img)
gausian_blurred_image_56 = gausian_blur_transformation_56(orig_img)
plt.imshow(gausian_blurred_image_13)

plt.imshow(gausian_blurred_image_56)

6. Гауссовский шум

Добавление гауссова шума к изображению поможет изображению иметь стратегические вариации результатов в обучающих данных. Функция шума Гаусса, предоставляемая torchvision.transforms, поможет создать шум с распределением Гаусса на изображении. Функция гауссовского шума в torchvision.transforms будет работать только с тензорами, поэтому, как вы можете видеть ниже, нам нужно создать небольшую функцию-оболочку для преобразования изображения в тензор и обратно. Мы можем изменить уровень шума, изменив значение параметра шума, переданного в функцию.

def addnoise(input_image, noise_factor = 0.3):
    inputs = T.ToTensor()(input_image)
    noise = inputs + torch.rand_like(inputs) * noise_factor
    noise = torch.clip (noise,0,1.)
    output_image = T.ToPILImage()
    image = output_image(noise)
    return image

gausian_image_3 = addnoise(orig_img)
gausian_image_6 = addnoise(orig_img,0.6)
gausian_image_9 = addnoise(orig_img,0.9)
plt.imshow(gausian_image_3)

plt.imshow(gausian_image_6)

plt.imshow(gausian_image_9)

7. Дрожание цвета

Функция цветового дрожания от torchvision.transforms помогает варьировать яркость, контрастность, оттенок и насыщенность изображения, создавая вариации в этих аспектах изображения, позволяя модели находить в нем больше функций. Это также позволяет распознавать объект в различном окружении. На этом изображении выполняются три итерации цветового дрожания, вы можете сделать больше, изменив значения, которые передаются в качестве параметров в функцию.

colour_jitter_transformation_1 = T.ColorJitter(brightness=(0.5,1.5),contrast=(3),saturation=(0.3,1.5),hue=(-0.1,0.1))

colour_jitter_transformation_2 = T.ColorJitter(brightness=(0.7),contrast=(6),saturation=(0.9),hue=(-0.1,0.1))

colour_jitter_transformation_3 = T.ColorJitter(brightness=(0.5,1.5),contrast=(2),saturation=(1.4),hue=(-0.1,0.5))



colour_jitter_image_1 = colour_jitter_transformation_1(orig_img)
colour_jitter_image_2 = colour_jitter_transformation_2(orig_img)
colour_jitter_image_3 = colour_jitter_transformation_3(orig_img)
plt.imshow(colour_jitter_image_1)

plt.imshow(colour_jitter_image_2)

plt.imshow(colour_jitter_image_3)

8. Случайное инвертирование

Функция случайного инвертирования инвертирует заданное изображение случайным образом с заданной вероятностью. Эта функция помогает внести разнообразие в набор данных.

transform = T.RandomInvert(p = 0.25)                                                                                                                                                                                                                  
inverted_img = transform(orig_img)
plt.imshow(inverted_img)

Скрипт для эффективной аугментации классифицированных изображений

Теперь мы видели все эти преобразования по отдельности, но не имеет смысла выполнять все эти аугментации по отдельности на каждом отдельном изображении, если вы не любите боль, оно того не стоит.

Приведенный ниже скрипт просматривает файлы с тренировочными изображениями, создает все дополнения изображений, а затем сохраняет их в другой папке в той же файловой структуре. Убедитесь, что у вас есть папка с тренировочными изображениями (с тренировочной меткой каждого типа в качестве имени папки). Создайте новую папку для дополненных изображений. Укажите путь к папке с изображениями для дополнения в переменной master_dataset и путь к папке, где будут храниться дополненные изображения в переменной augmented dataset. Затем запустите скрипт, и вуаля, у вас есть все дополненные изображения в новой папке.

Перед запуском скрипта указанная папка для дополненных изображений пуста:

Сценарий:

# This script aims to create augmented images from one image to create a larger dataset for our cnn model
# The augmentation this script will perform on each object is 
# orig_img,grayscaled_image,random_rotation_transformation_45_image,random_rotation_transformation_65_image,random_rotation_transformation_85_image,gausian_blurred_image_13_image,gausian_blurred_image_56_image,gausian_image_3,gausian_image_6,gausian_image_9,colour_jitter_image_1,colour_jitter_image_2,colour_jitter_image_3

#call the function creating file with augmented image give path of dataset and path of folder where you want the augmented images to be stored

import PIL
import torch 
from PIL import Image
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
import sys
import torchvision.transforms as T
import os

#torch.transforms

#grayscale
grayscale_transform = T.Grayscale(3)

#random rotation
random_rotation_transformation_45 = T.RandomRotation(45)
random_rotation_transformation_85 = T.RandomRotation(85)
random_rotation_transformation_65 = T.RandomRotation(65)

#Gausian Blur
gausian_blur_transformation_13 = T.GaussianBlur(kernel_size = (7,13), sigma = (6 , 9))
gausian_blur_transformation_56 = T.GaussianBlur(kernel_size = (7,13), sigma = (5 , 8))

#Gausian Noise

def addnoise(input_image, noise_factor = 0.3):
    inputs = T.ToTensor()(input_image)
    noisy = inputs + torch.rand_like(inputs) * noise_factor
    noisy = torch.clip (noisy,0,1.)
    output_image = T.ToPILImage()
    image = output_image(noisy)
    return image

#Colour Jitter

colour_jitter_transformation_1 = T.ColorJitter(brightness=(0.5,1.5),contrast=(3),saturation=(0.3,1.5),hue=(-0.1,0.1))

colour_jitter_transformation_2 = T.ColorJitter(brightness=(0.7),contrast=(6),saturation=(0.9),hue=(-0.1,0.1))

colour_jitter_transformation_3 = T.ColorJitter(brightness=(0.5,1.5),contrast=(2),saturation=(1.4),hue=(-0.1,0.5))

#Random invert

random_invert_transform = T.RandomInvert()

#Main function that calls all the above functions to create 11 augmented images from one image

def augment_image(img_path):

    #orig_image
    orig_img = Image.open(Path(img_path))

    #grayscale
    
    grayscaled_image=grayscale_transform(orig_img)
    #grayscaled_image.show()
    
    #random rotation
    random_rotation_transformation_45_image=random_rotation_transformation_45(orig_img)
    #random_rotation_transformation_45_image.show()
    
    random_rotation_transformation_85_image=random_rotation_transformation_85(orig_img)
    #random_rotation_transformation_85_image.show()
    
    random_rotation_transformation_65_image=random_rotation_transformation_65(orig_img)
    #random_rotation_transformation_65_image.show()
    
    #Gausian Blur
    
    gausian_blurred_image_13_image = gausian_blur_transformation_13(orig_img)
    #gausian_blurred_image_13_image.show()

    gausian_blurred_image_56_image = gausian_blur_transformation_56(orig_img)
    #gausian_blurred_image_56_image.show()
    
    #Gausian Noise

    gausian_image_3 = addnoise(orig_img)
    
    #gausian_image_3.show()

    gausian_image_6 = addnoise(orig_img,0.6)
    
    #gausian_image_6.show()
    
    gausian_image_9 = addnoise(orig_img,0.9)

    #gausian_image_9.show()

    #Color Jitter

    
    colour_jitter_image_1 = colour_jitter_transformation_1(orig_img)
    
    #colour_jitter_image_1.show()
    
    
    colour_jitter_image_2 = colour_jitter_transformation_2(orig_img)
    
    #colour_jitter_image_2.show()
    
    colour_jitter_image_3 = colour_jitter_transformation_3(orig_img)

    #colour_jitter_image_3.show()

    return [orig_img,grayscaled_image,random_rotation_transformation_45_image,random_rotation_transformation_65_image,random_rotation_transformation_85_image,gausian_blurred_image_13_image,gausian_blurred_image_56_image,gausian_image_3,gausian_image_6,gausian_image_9,colour_jitter_image_1,colour_jitter_image_2,colour_jitter_image_3]

#augmented_images = augment_image(orig_img_path)

def creating_file_with_augmented_images(file_path_master_dataset,file_path_augmented_images):
    
    master_dataset_folder = file_path_master_dataset
    files_in_master_dataset = os.listdir(file_path_master_dataset)
    augmented_images_folder = file_path_augmented_images
    
    counter=0
    
    for element in files_in_master_dataset:
        os.mkdir(f"{augmented_images_folder}/{element}")
        images_in_folder= os.listdir(f"{master_dataset_folder}/{element}")
        counter = counter+1
        counter2 = 0
        for image in images_in_folder:
            counter
            required_images = augment_image(f"{master_dataset_folder}/{element}/{image}")
            counter2=counter2+1
            counter3 = 0
            for augmented_image in required_images:
                counter3 = counter3 +1
                augmented_image = augmented_image.save(f"{augmented_images_folder}/{element}/{counter}_{counter2}_{counter3}_{image}")

"""images = augment_image("dog.png")

for element in images:
    element.show()"""

#augmented dataset path
augmented_dataset = "/Users/software/Desktop/sem_6/Hieroglyphics_nlp/Code_image_augmentation/augmented_images_dataset"

# master dataset path
master_dataset = "/Users/software/Desktop/sem_6/Hieroglyphics_nlp/Code_image_augmentation/Master_dataset"

# run the program

creating_file_with_augmented_images(master_dataset,augmented_dataset)

После запуска скрипта все дополненные изображения сохраняются в указанной папке с одинаковой файловой структурой:

Надеюсь, скрипт работал на вашем компьютере. Если у вас возникли проблемы, просмотрите комментарии к скрипту, а также убедитесь, что все библиотеки, используемые в скрипте, установлены и готовы к работе.

Счастливого увеличения... (морщится в тишине).

Использованная литература :