Commit 1e0f81f2 authored by Gilberto Astolfi's avatar Gilberto Astolfi
Browse files

melhorando oversampling para gerar menos imagens

parent b7aa0d6b
......@@ -5,6 +5,7 @@ import xml.etree.ElementTree as et
import cv2
from transformation_image import Transformation
import argparse
import glob
class DataAugmentation:
def __init__(self, path_folds, percentage):
......@@ -12,6 +13,7 @@ class DataAugmentation:
self.percentage = percentage
self.transformation = Transformation()
self.idx_continue = 0
self.augmentation_class = None
def readImage(self, xml_file ):
root = et.parse(xml_file).getroot()
......@@ -244,20 +246,118 @@ class DataAugmentation:
self.idx_continue += 1
self.saveImageAnnotation(trans_images, path_image,label)
def overResidue(self, path):
for cl, num_anot in self.augmentation_class.items():
if num_anot > 0:
self.applyOversamplingInClass(path, num_anot, cl)
def applyOversamplingInSet(self, path, classes):
num_classes = self.countClassDir(path)
max_value = max(num_classes.values()) # indica a classe que tem maior número de anotações
#percorre as classes e obtem o numero de anotações que cada uma passui
aug_class = {}
for cl, num_anot in num_classes.items():
num_gerar = max_value - num_anot # número de imagens a serem geradas
#print(cl,' ---> ',num_gerar, ' -- ', num_gerar+num_anot)
if num_gerar == 0:
continue
else:
# gerar num_gerar de imagens para a classe cl
self.applyOversamplingInClass(path, num_gerar, cl)
aug_class[cl] = num_gerar
self.augmentation_class = aug_class
list_xml = self.listXmlsSet(path)
while len(self.augmentation_class) > 0:
for xml_file in list_xml:
bbs = self.listBoundingBoxImage(xml_file)
new_bbs = self.noOversampling(bbs)
if len(new_bbs) > 0:
original_image = self.readImage(xml_file)
rotated_images, bb_list = self.transformation.applyTransformationVariusBB(original_image, new_bbs, "rotationVarius")
label = '_over_'+str(self.idx_continue)+'_'
self.idx_continue += 1
self.saveImageAnnotationVariusBB(rotated_images, bb_list, xml_file, label)
self.reductionNumClass(bb_list)
self.augmentation_class = {key:val for key, val in self.augmentation_class.items() if val > 0}
self.overResidue(path) # gerar imagens para classes que ainda possui inferioridade no número
def reductionNumClass(self, bb_list):
for bb in bb_list:
cl = bb[1]
if cl in self.augmentation_class:
if self.augmentation_class[cl] > 0:
self.augmentation_class[cl] -= 1
def createFileXmlVariusBB(self, filename, size, objects, path_xml, path):
out_xml = '<annotation>\n'
out_xml += '\t<folder>img</folder>\n'
out_xml += '\t<filename>'+filename+'</filename>\n'
out_xml += '\t<path>'+path+'</path>\n'
out_xml += '\t<source>\n'
out_xml += '\t\t<database>Unknown</database>\n'
out_xml += '\t</source>\n'
out_xml += '\t<size>\n'
out_xml += '\t\t<width>'+str(size[1])+'</width>\n'
out_xml += '\t\t<height>'+str(size[0])+'</height>\n'
out_xml += '\t\t<depth>'+str(size[2])+'</depth>\n'
out_xml += '\t</size>\n'
out_xml += '\t<segmented>0</segmented>\n'
for obj in objects:
classe = obj[1]
bndbox = obj[0]
out_xml += '\t<object>\n'
out_xml += '\t\t<name>'+classe+'</name>\n'
out_xml += '\t\t<pose>Unspecified</pose>\n'
out_xml += '\t\t<truncated>0</truncated>\n'
out_xml += '\t\t<difficult>0</difficult>\n'
out_xml += '\t\t<bndbox>\n'
out_xml += '\t\t\t<xmin>'+str(bndbox[0])+'</xmin>\n'
out_xml += '\t\t\t<ymin>'+str(bndbox[1])+'</ymin>\n'
out_xml += '\t\t\t<xmax>'+str(bndbox[2])+'</xmax>\n'
out_xml += '\t\t\t<ymax>'+str(bndbox[3])+'</ymax>\n'
out_xml += '\t\t</bndbox>\n'
out_xml += '\t</object>\n'
out_xml += '</annotation>'
fo = open(path_xml, "w")
fo.write(out_xml)
fo.close()
def saveImageAnnotationVariusBB(self, rotated_image, bb_list, src, label):
file_name, _ = os.path.splitext(src)# path do arquivo original sem extensão. Exemplo: path/path/inseto1
num_images = 1
path_image = file_name + label +str(num_images)+'.jpg' # tag path e para salvar o arquivo jpg
path_xml = file_name + label +str(num_images)+'.xml' # para salvar o arquivo xml
if os.path.isfile(path_xml):
print ("-----------------> File exist")
name_splited = path_image.split('/')
filename = name_splited[len(name_splited)-1] #tag filename. Exemplo: inseto1.jpg
size = rotated_image.shape
self.createFileXmlVariusBB(filename, size, bb_list, path_xml, path_image)
img = cv2.cvtColor(rotated_image, cv2.COLOR_BGR2RGB)
cv2.imwrite(path_image, img)
def noOversampling(self, bbs):
only_bbs = []
for bb in bbs:
cl = bb[4]
if cl in self.augmentation_class:
if self.augmentation_class[cl] > 0:
only_bbs.append(bb)
return only_bbs
def listXmlsSet(self, path):
list_xml = []
for classe in os.listdir(path):
new_path = path + '/'+classe
xmls = glob.glob(new_path+"/*.xml")
for xml_file in xmls:
basename = os.path.basename(xml_file)
name, extension = os.path.splitext(basename)
if '_aug_' not in name and '_over_' not in name:
list_xml.append(xml_file)
return list_xml
def oversampling(self):
print('Iniciando oversampling...')
......@@ -267,19 +367,16 @@ class DataAugmentation:
path_validation = self.root_path + '/' + fold + '/validation'
classes_train = os.listdir(path_train)
classes_validation = os.listdir(path_validation)
#print(10*'**',fold)
#print(self.countClassDir(path_train))
self.applyOversamplingInSet(path_train, classes_train)
#print(self.countClassDir(path_train))
#print(15*'--')
#print(self.countClassDir(path_validation))
self.applyOversamplingInSet(path_validation, classes_validation)
#print(self.countClassDir(path_validation))
print('Fim oversampling...')
if __name__ == '__main__':
path_out = './data/folds'
dt = DataAugmentation(path_out, .3)
dt.augmentation()
dt.oversampling()
\ No newline at end of file
dt = DataAugmentation(path_out, 0)
#dt.augmentation()
#dt.oversampling()
path = './data/repetition/repetition2/train'
num_classes = dt.countClassDir(path)
print(num_classes)
\ No newline at end of file
......@@ -6,7 +6,7 @@ import argparse
if __name__ == '__main__':
# python3 main.py ./data/annotated_pests_v2 ./data/folds repetition 30 True .3 True
# python3 main.py ./data/Pests3C1P ./data/folds repetition 30 True 0 True
parser = argparse.ArgumentParser()
parser.add_argument('path_in', metavar='path_in', type=str, help='A root directory where are annotated images.')
parser.add_argument('path_out', metavar='path_out', type=str, help='Path where the output will be created')
......
......@@ -4,8 +4,8 @@ import cv2
class Transformation:
def __init__(self):
self.t_dic = { "rotation": self.rotateImage}
self.f_dic = { "rotation":(0, 90), "width_shift":(0, 0.5), "height_shift":(0, 0.5), "scale": (0.5, 1.5)}
self.t_dic = { "rotation": self.rotateImage, "rotationVarius": self.rotateImageVariusBB}
self.f_dic = { "rotation":(0, 90), "rotationVarius":(0, 90), "width_shift":(0, 0.5), "height_shift":(0, 0.5), "scale": (0.5, 1.5)}
def positive(self, x):
......@@ -44,6 +44,39 @@ class Transformation:
return rotated_image, new_boundingbox
def rotateImageVariusBB(self, image, angle, bounding_boxes ):
# get image dimension
img_height, img_width = image.shape[:2]
# get rotation matrix
rotation_matrix = cv2.getRotationMatrix2D( center = (img_width // 2, img_height // 2), angle = angle, scale = 1.0 )
# apply transformation (ratate image)
rotated_image = cv2.warpAffine( image, rotation_matrix, (img_width, img_height) )
# --- compute new bounding boxes ---
new_boundingboxes = []
for bb_ in bounding_boxes:
bounding_box = bb_[0:4] # bb
cl = bb_[4] # classe
# Apply same transformation to the four bounding box corners
rotated_point_A = np.matmul( rotation_matrix, np.array( [bounding_box[0], bounding_box[1], 1] ).T )
rotated_point_B = np.matmul( rotation_matrix, np.array( [bounding_box[2], bounding_box[1], 1] ).T )
rotated_point_C = np.matmul( rotation_matrix, np.array( [bounding_box[2], bounding_box[3], 1] ).T )
rotated_point_D = np.matmul( rotation_matrix, np.array( [bounding_box[0], bounding_box[3], 1] ).T )
# Compute new bounding box, that is, the bounding box for rotated object
x = np.array( [ rotated_point_A[0], rotated_point_B[0], rotated_point_C[0], rotated_point_D[0] ] )
y = np.array( [ rotated_point_A[1], rotated_point_B[1], rotated_point_C[1], rotated_point_D[1] ] )
#x = positive(np.min( x ).astype(int))
new_boundingbox = [self.positive(np.min(x).astype(int)), self.positive(np.min( y ).astype(int)),
self.positive(np.max( x ).astype(int)), self.positive(np.max( y ).astype(int))]
bb_cl = (new_boundingbox, cl)
new_boundingboxes.append(bb_cl)
return rotated_image, new_boundingboxes
def applyTransformation(self, image, bounding_box, transformation, n ):
t_images_list = []
......@@ -53,3 +86,8 @@ class Transformation:
img, bb = self.t_dic[transformation]( image, factor, bounding_box )
t_images_list.append((img, bb, factor))
return t_images_list
def applyTransformationVariusBB(self, image, bounding_box_list, transformation):
interval = self.f_dic[transformation]
factor = random.uniform(interval[0], interval[1])
return self.t_dic[transformation]( image, factor, bounding_box_list )
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment