Время прочтения: 5 мин.
Компьютерное зрение большая область машинного обучения. Если вы решили попробовать свои силы в детектирование объектов, то сегодня я покажу, как, не прибегая к обучению GAN-моделей для генерации изображений быстро подготовить генератор используя библиотеки 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 числа координаты объекта, остальные — кодировка класса.
Изображения, которые мы загрузили:
Объекты, которые мы загрузили:
Изображения, которые получили. Объект на изображении поворачивается от 0 до 360, зеркально отражается, обрезает углы, меняет свой размер, местоположение и яркость, а также добавляет шум. У второго объекта был фон, но на итоговом изображении его не будет. В этом вы можете убедиться, посмотрев ниже.
Как и обещал — добавлю код, который Вы можете использовать для обучения моделей.
model.fit(gen_image(),validation_data=gen_image(),steps_per_epoch=60,validation_steps=10 ,epochs=10)
На выходе я получил изображение и аннотацию к нему. С данным кодом Вам не придется искать изображения и заниматься разметкой — достаточно найти пару изображений, и можно тестировать свою модель.