File size: 9,118 Bytes
e6b3e35
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
# -*- coding: utf-8 -*-
"""
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'
#img_path = 'C:\\Users\\Gabriel\\Downloads\\imagens_geradas_menor_zoom800-800-v3'
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')


#verifica se as paths de saida existem
paths = [outpath, teste_path_out, validacao_path_out, treino_path_out]

for path in paths:
  if not os.path.lexists(path):
          os.mkdir(path)
  
#exemplo de nome de arquivo: 2017-05-09_1-0-0-13-300,600_600,900.jpg
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('-')
          #captura a data, 
          row['date'] = datetime.datetime(int(date_info[0]), int(date_info[1]), int(date_info[2]))
          row['zoom'] = int(file.split('_')[1].split('-')[2])
          
          
          #print(row['class'])
          df= df.append(row, ignore_index=True)
    return df

#exemplo de nome de arquivo: 2017-05-09_1-0-0-13-300,600_600,900.jpg
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]
          
          
          #print(row['class'])
          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.

    """
    #captura as classes
    classes = df[coluna_classe].unique()
    columns_df = ['path', 'class', 'date', 'zoom']
    df_result = pd.DataFrame(columns=columns_df)
    
    
    #itera sobre as classes
    for classe in classes:
        df_classe = df[df[coluna_classe] == classe]
        #captura a as datas presentes para essa classe
        dates = df_classe['date'].unique()
        
        #itera sobre as datas
        for date in dates:
            df_date = df_classe[df_classe['date'] == date]
            #itera sobre os zooms
            for zoom in zooms:
                df_zoom = df_date[df_date['zoom'] == zoom]
                #se o dataset for menor que a quantidade, pula o sorteio adicionando todo ele ao dataset resultante
                if len(df_zoom) > quantidade:
                    #sorteia aleatoriamente
                    for i in range(quantidade):
                        indice = random.randint(0, len(df_zoom)-1)
                        df_result = df_result.append(df_zoom.iloc[[indice]])
                        #lista_imagens.append(df_classe.iloc[[indice]][path_classe].values[0])
                        df_zoom.drop(df_zoom.index[[indice]], inplace=True)
                else:
                    df_result = df_result.append(df_zoom, ignore_index=True)
    #retorna o dataset
    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)
            #save_fname = os.path.join(new_dir, os.path.basename(img_name))
    
        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

#criacao da dataframe
columns_df = ['path', 'class', 'date', 'zoom']
df = pd.DataFrame(columns=columns_df)

#faz dataset para treino
df_train = directory_from_df_with_class(df, treino_path)
print('finalizada a análise do diretório de treino')
#no conjunto de treino se captura 2.5x mais imagens
df_train_random = rand_images_from_df(df_train, 'class', quantidade=10, zooms = [1,2])
print('finalizado o sorteio do diretório de treino')

#faz dataset para validacao
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')


#faz dataset para teste
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')

#salva as imagens
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)