|
|
|
""" |
|
Created on Mon Apr 19 16:11:11 2021 |
|
|
|
Código utilizado para diminuir a quantidade de imagens do dataset. A ideia foi limitar em termos do tamanho do crop e da data. |
|
@author: Gabriel |
|
""" |
|
|
|
import os |
|
import datetime |
|
import pandas as pd |
|
import random |
|
from shutil import copy2 |
|
from keras.preprocessing.image import ImageDataGenerator, array_to_img,img_to_array, load_img |
|
|
|
|
|
img_path = 'C:\\Users\\Gabriel\\OneDrive - Universidade de Tras-os-Montes e Alto Douro\\UTAD\\2020-2021\\Pesquisa\\Dataset\\Gerado\\dataset_versao_manual - ga' |
|
|
|
teste_path = os.path.join(img_path, 'test') |
|
validacao_path = os.path.join(img_path, 'validation') |
|
treino_path = os.path.join(img_path, 'train') |
|
|
|
|
|
outpath = 'C:\\Users\\Gabriel\\Downloads\\ga' |
|
|
|
sep = os.path.sep |
|
teste_path_out = os.path.join(outpath, 'test') |
|
validacao_path_out = os.path.join(outpath, 'validation') |
|
treino_path_out = os.path.join(outpath, 'train') |
|
|
|
|
|
|
|
paths = [outpath, teste_path_out, validacao_path_out, treino_path_out] |
|
|
|
for path in paths: |
|
if not os.path.lexists(path): |
|
os.mkdir(path) |
|
|
|
|
|
def directory_from_df_with_class(df, directory): |
|
""" |
|
Método responsável por transformar as imagens de um dataset num dataframe. |
|
Parameters |
|
---------- |
|
df : Dataframe pandas |
|
dataframe que será utilizado para povoar com os elementos. O dataframe será preenchido com os seguintes campos: |
|
['path', 'class', 'date', 'zoom'] |
|
directory : String |
|
diretório de onde as imagens serão retiradas. |
|
|
|
Returns |
|
------- |
|
df : dataframe pandas |
|
O dataframe povoado. |
|
""" |
|
for r, d, f in os.walk(directory): |
|
for file in f: |
|
row = {} |
|
row['path'] = os.path.join(r, file) |
|
row['class'] = row['path'].split(os.path.sep)[-2] |
|
date_info = file.split('_')[0].split('-') |
|
|
|
row['date'] = datetime.datetime(int(date_info[0]), int(date_info[1]), int(date_info[2])) |
|
row['zoom'] = int(file.split('_')[1].split('-')[2]) |
|
|
|
|
|
|
|
df= df.append(row, ignore_index=True) |
|
return df |
|
|
|
|
|
def directory_from_df_with_class2(df, directory): |
|
""" |
|
Método responsável por transformar as imagens de um dataset num dataframe. |
|
Parameters |
|
---------- |
|
df : Dataframe pandas |
|
dataframe que será utilizado para povoar com os elementos. O dataframe será preenchido com os seguintes campos: |
|
['path', 'class', 'date', 'zoom'] |
|
directory : String |
|
diretório de onde as imagens serão retiradas. |
|
|
|
Returns |
|
------- |
|
df : dataframe pandas |
|
O dataframe povoado. |
|
""" |
|
for r, d, f in os.walk(directory): |
|
for file in f: |
|
row = {} |
|
row['path'] = os.path.join(r, file) |
|
row['class'] = row['path'].split(os.path.sep)[-2] |
|
|
|
|
|
|
|
df= df.append(row, ignore_index=True) |
|
return df |
|
|
|
def rand_images_from_df(df, coluna_classe, quantidade=20, zooms = [0, 1, 2]): |
|
""" |
|
Método responsável por sortear aliatoriamente uma quantidade de imagens definidas, por zoom, por data e por classe. |
|
Isso implica que a quantidade de imagens retornadas é: QUANTIDADE DE CLASSES * QUANTIDADE DATAS DE AQUISIÇÃO * QUANTIDADE DE ZOOMS * QUANTIDADE DE IMAGENS PASSADAS POR PARÂMETRO. |
|
|
|
Parameters |
|
---------- |
|
df : dataframe pandas |
|
Dataframe contendo as seguintes colunas: ['path', 'class', 'date', 'zoom']. |
|
coluna_classe : string |
|
Nome da coluna que representa a classe no dataset. |
|
quantidade : integer, optional |
|
DESCRIPTION. The default is 20. Quantidade de imagens que serão sorteadas, por zoom, por data e por tipo |
|
|
|
Returns |
|
------- |
|
df_result : dataframe pandas |
|
Dataframe contendo as seguintes colunas: ['path', 'class', 'date', 'zoom'] com as imagens sorteadas. |
|
|
|
""" |
|
|
|
classes = df[coluna_classe].unique() |
|
columns_df = ['path', 'class', 'date', 'zoom'] |
|
df_result = pd.DataFrame(columns=columns_df) |
|
|
|
|
|
|
|
for classe in classes: |
|
df_classe = df[df[coluna_classe] == classe] |
|
|
|
dates = df_classe['date'].unique() |
|
|
|
|
|
for date in dates: |
|
df_date = df_classe[df_classe['date'] == date] |
|
|
|
for zoom in zooms: |
|
df_zoom = df_date[df_date['zoom'] == zoom] |
|
|
|
if len(df_zoom) > quantidade: |
|
|
|
for i in range(quantidade): |
|
indice = random.randint(0, len(df_zoom)-1) |
|
df_result = df_result.append(df_zoom.iloc[[indice]]) |
|
|
|
df_zoom.drop(df_zoom.index[[indice]], inplace=True) |
|
else: |
|
df_result = df_result.append(df_zoom, ignore_index=True) |
|
|
|
return df_result |
|
|
|
|
|
def save_images_from_df(df, class_column, path_column, outpath): |
|
""" |
|
Método responsável por copiar as imagens para o novo diretório |
|
|
|
Parameters |
|
---------- |
|
df : dataframe pandas |
|
Dataframe contendo as imagens que serão copiadas. |
|
class_column : string |
|
nome da coluna que representa a classe no dataframe. |
|
path_column : string |
|
nome da coluna que representa a path par a imagem no dataframe. |
|
outpath : string |
|
path para onde serão copiadas as novas imagens. |
|
|
|
Returns |
|
------- |
|
None. |
|
|
|
""" |
|
for i, row in df.iterrows(): |
|
if not row[path_column] is None: |
|
nome = row[path_column].split(os.path.sep)[-1] |
|
path_destino = os.path.join(outpath, row[class_column]) |
|
if not os.path.lexists(path_destino): |
|
os.mkdir(path_destino) |
|
arquivo_path = os.path.join(path_destino, nome) |
|
copy2(row[path_column], arquivo_path) |
|
|
|
def augment_dataset(df, path_output, path_column='path', quantity=10): |
|
|
|
filenames=df[path_column].values |
|
for img in filenames: |
|
src_fname, ext = os.path.splitext(img) |
|
|
|
datagen = ImageDataGenerator(rotation_range=50, |
|
width_shift_range=0.2, |
|
height_shift_range=0.2, |
|
horizontal_flip=True, |
|
brightness_range=[0.6,1.0], |
|
vertical_flip=True) |
|
|
|
|
|
img = load_img(img) |
|
|
|
x = img_to_array(img) |
|
x = x.reshape((1,) + x.shape) |
|
|
|
img_name = src_fname.split(os.path.sep)[-1] |
|
class_name = src_fname.split(os.path.sep)[-2] |
|
new_dir = os.path.join(path_output, class_name) |
|
if not os.path.lexists(new_dir): |
|
os.mkdir(new_dir) |
|
|
|
|
|
i = 0 |
|
for batch in datagen.flow (x, batch_size=1, save_to_dir = new_dir, |
|
save_prefix = img_name, save_format='jpg'): |
|
i+=1 |
|
if i>quantity: |
|
break |
|
|
|
|
|
columns_df = ['path', 'class', 'date', 'zoom'] |
|
df = pd.DataFrame(columns=columns_df) |
|
|
|
|
|
df_train = directory_from_df_with_class(df, treino_path) |
|
print('finalizada a análise do diretório de treino') |
|
|
|
df_train_random = rand_images_from_df(df_train, 'class', quantidade=10, zooms = [1,2]) |
|
print('finalizado o sorteio do diretório de treino') |
|
|
|
|
|
df = pd.DataFrame(columns=columns_df) |
|
df_val = directory_from_df_with_class(df, validacao_path) |
|
print('finalizada a análise do diretório de validação') |
|
df_val_random = rand_images_from_df(df_val, 'class', quantidade=5, zooms = [1,2]) |
|
print('finalizado o sorteio do diretório de validação') |
|
|
|
|
|
|
|
df = pd.DataFrame(columns=columns_df) |
|
df_test = directory_from_df_with_class(df, teste_path) |
|
print('finalizada a análise do diretório de teste') |
|
df_test_random = rand_images_from_df(df_test, 'class', quantidade=5, zooms = [1,2]) |
|
print('finalizado o sorteio do diretório de teste') |
|
|
|
|
|
save_images_from_df(df=df_train_random, class_column='class', path_column='path', outpath=treino_path_out) |
|
save_images_from_df(df=df_val_random, class_column='class', path_column='path', outpath=validacao_path_out) |
|
save_images_from_df(df=df_test_random, class_column='class', path_column='path', outpath=teste_path_out) |
|
|
|
df_train_random = directory_from_df_with_class2(df, treino_path) |
|
augment_dataset(df_train_random, treino_path_out, quantity=10) |
|
|
|
|
|
|