Numpy и Pillow для генерации изображений

Необходимо сгенерировать изображения, не затрачивая при этом много времени? Предлагаю обратить внимание на две библиотеки, которые помогут это сделать - Pillow и Numpy.

Компьютерное зрение большая область машинного обучения. Если вы решили попробовать свои силы в детектирование объектов, то сегодня я покажу, как, не прибегая к обучению GAN-моделей для генерации изображений быстро подготовить генератор используя библиотеки Numpy и Pillow.

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

Спойлер: в конце поста покажу как его использовать при обучении моделей для детекции объектов.

Суть алгоритма:

Numpy и Pillow для генерации изображений

*Объект меняет свое местоположение на изображении, размер и угол от 0 до 360.

Перед началом работы я подготовил две папки:

1 – для фоновых изображений.

2 – для объектов.

Импортирую необходимые библиотеки:

import numpy as np import os import matplotlib.pyplot as plt from PIL import Image,ImageEnhance

Перейду к более детальному рассмотрению.

Вспомогательная функция для случайного распределения выбора класса объекта:

def flip_coin(): if np.random.uniform()>0.5: return 'class1' return 'class2'

Еще одна вспомогательная функция для добавления шума на объекты.

def salt(image): koef = np.random.randint(5) koef = koef/10 img = np.copy(np.array(image)) salt = np.ceil(koef * img.size * 0.5) coords = [np.random.randint(0, i - 1, int(salt)) for i in img.shape] img[coords] = 1 pepper = np.ceil(koef* img.size * 0.5) coords = [np.random.randint(0, i - 1, int(pepper)) for i in img.shape] img[coords] = 0 return Image.fromarray(img)

Основная функция.

Создам массив из 0. X-основа для изображения, Y-основа для объекта.

Аргументы функции:

batch_size – сколько изображений будет сгенерировано за один вызов функции,

size_img – размер изображений.

get_image(batch_size=5,size_img=128): X = np.zeros((batch_size, size_img, size_img, 3)) Y = np.zeros((batch_size, 6))

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

size = np.random.randint(int(size_img/10),int(size_img/5)) file_obj = os.listdir('/content/obj') rand = np.random.randint(len(file_obj)) cat_pil = Image.open('/content/obj'+'/'+file_obj[rand-1]) temp_cat = cat_pil.thumbnail((size,size)) temp_cat = temp_cat.rotate(np.random.randint(360), expand=True) cat = np.asarray(temp_cat) / 255. try: cat_x, cat_y,_ = cat.shape except ValueError: cat_x, cat_y = cat.shape

Если Вы разделили объекты по классам, то следует их разделить по папкам, которые будут означать отдельный класс, и использовать для обработки код ниже. Количество условий должно равняться количеству классов.

Также не забудьте исправить функцию flip_coin.

size = np.random.randint(int(size_img/10),int(size_img/5)) #Размер объекта задается случайным образом class_ = flip_coin() #Случайный выбор класса # Обработка объекта if (class_ == 'class1'): file_obj = os.listdir('/content/obj/1') rand = np.random.randint(len(file_obj)) pil = Image.open('/content/obj/1'+'/'+file_obj[rand-1]) #Случайным образом выбираем объект из папки class1 = 1.0 else: file_obj = os.listdir('/content/obj/2') rand = np.random.randint(len(file_obj)) pil = Image.open('/content/obj/2'+'/'+file_obj[rand-1]) class2 = 1.0 pil = salt(pil) temp = pil.thumbnail((size,size)) #Меняем размер объекта на случайно выбранный size = np.random.randint(8) size_ = np.random.randint(8) temp = temp.rotate(np.random.randint(360),translate=(size,size_), expand=True) #Поворачиваем объект на случайное значение color = np.random.randint(5,25) enhancer = ImageEnhance.Brightness(temp) temp = enhancer.enhancer(color/10) #изменяем яркость объекта flip = np.random.randint(2) if flip==1: #Условие для зеркального отражения temp = np.fliplr(temp) temp = Image.fromarray(temp) obj = np.asarray(temp) / 255. #Конвертируем входные данные в массив try: animal_x, animal_y, _ = obj.shape except ValueError: animal_x, animal_y = obj.shape

Создам пустое изображение, которое нам пригодится для конкатенации изображения и объекта:

bg = Image.new('RGB', (size_img, size_img))

Обработаю фон:

# Обработка фона изображения path = '/content/Fon' files = os.listdir(path) rand = np.random.randint(0, len(files)) img = Image.open(path+'/'+files[rand-1]) img = img.resize((size_img,size_img)) bg.paste(img)

На данный момент у меня подготовлен объект и фон.

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

x1 = np.random.randint(1,size_img - animal_x) #Задаем координаты для объекта y1 = np.random.randint(1,size_img - animal_y) h = animal_x w = animal_y animal_appear = 1.0 bg.paste(temp, (x1, y1), mask=temp) pic = np.asarray(bg) / 255. X[i] = pic #Вместо раннее созданного нулевого массива, подставляем собранное изображение Y[i,0] = x1/float(size_img) #Определяем положение объекта относительно размеров изображения Y[i,1] = y1/float(size_img) Y[i,2] = animal_x / float(size_img) Y[i,3] = animal_appear * class1 // 1 # is_class1 Y[i,4] = animal_appear * class2 // 1 # is_class2 yield X,Y x,y = next(gen_image(size_img=360)) plt.imshow(x[0])#Вывод нового изображения

Аннотация: первые 3 числа координаты объекта, остальные - кодировка класса.

Numpy и Pillow для генерации изображений

Изображения, которые мы загрузили.

Numpy и Pillow для генерации изображений

Объекты, которые мы загрузили.

Numpy и Pillow для генерации изображений

Изображения, которые получили. Объект на изображении поворачивается от 0 до 360, зеркально отражается, обрезает углы, меняет свой размер, местоположение и яркость, а также добавляет шум. У второго объекта был фон, но на итоговом изображении его не будет. В этом вы можете убедиться, посмотрев ниже.

Numpy и Pillow для генерации изображений

Как и обещал - добавлю код, который Вы можете использовать для обучения моделей.

model.fit(gen_image(),validation_data=gen_image(),steps_per_epoch=60,validation_steps=10 ,epochs=10)

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

44
Начать дискуссию