Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
inovisao
crossvalidation-repetition-object-detection
Commits
1e0f81f2
Commit
1e0f81f2
authored
Mar 25, 2021
by
Gilberto Astolfi
Browse files
melhorando oversampling para gerar menos imagens
parent
b7aa0d6b
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
151 additions
and
16 deletions
+151
-16
augmentation.py
augmentation.py
+110
-13
main.py
main.py
+1
-1
transformation_image.py
transformation_image.py
+40
-2
No files found.
augmentation.py
View file @
1e0f81f2
...
...
@@ -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
main.py
View file @
1e0f81f2
...
...
@@ -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'
)
...
...
transformation_image.py
View file @
1e0f81f2
...
...
@@ -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
)
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment