forked from kapil-varshney/esri_retinanet
-
Notifications
You must be signed in to change notification settings - Fork 0
/
build_dataset.py
110 lines (93 loc) · 3.85 KB
/
build_dataset.py
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
# import the necessary packages
from config import esri_retinanet_config as config
from bs4 import BeautifulSoup
from imutils import paths
import argparse
import random
import os
# Construct the argument parser and parse the arguments
ap = argparse.ArgumentParser()
ap.add_argument("-a", "--annotations", default=config.ANNOT_PATH,
help='path to annotations')
ap.add_argument("-i", "--images", default=config.IMAGES_PATH,
help="path to images")
ap.add_argument("-t", "--train", default=config.TRAIN_CSV,
help="path to output training CSV file")
ap.add_argument("-e", "--test", default=config.TEST_CSV,
help="path to output test CSV file")
ap.add_argument("-c", "--classes", default=config.CLASSES_CSV,
help="path to output classes CSV file")
ap.add_argument("-s", "--split", type=float, default=config.TRAIN_TEST_SPLIT,
help="train and test split")
args = vars(ap.parse_args())
# Create easy variable names for all the arguments
annot_path = args["annotations"]
images_path = args["images"]
train_csv = args["train"]
test_csv = args["test"]
classes_csv = args["classes"]
train_test_split = args["split"]
# grab all image paths then construct the training and testing split
imagePaths = list(paths.list_files(images_path))
random.shuffle(imagePaths)
i = int(len(imagePaths) * train_test_split)
trainImagePaths = imagePaths[:i]
testImagePaths = imagePaths[i:]
# create the list of datasets to build
dataset = [ ("train", trainImagePaths, train_csv),
("test", testImagePaths, test_csv)]
# initialize the set of classes we have
CLASSES = set()
# loop over the datasets
for (dType, imagePaths, outputCSV) in dataset:
# load the contents
print ("[INFO] creating '{}' set...".format(dType))
print ("[INFO] {} total images in '{}' set".format(len(imagePaths), dType))
# open the output CSV file
csv = open(outputCSV, "w")
# loop over the image paths
for imagePath in imagePaths:
# build the corresponding annotation path
fname = imagePath.split(os.path.sep)[-1]
fname = "{}.xml".format(fname[:fname.rfind(".")])
annotPath = os.path.sep.join([annot_path, fname])
# load the contents of the annotation file and buid the soup
contents = open(annotPath).read()
soup = BeautifulSoup(contents, "html.parser")
# extract the image dimensions
w = int(soup.find("width").string)
h = int(soup.find("height").string)
# loop over all object elements
for o in soup.find_all("object"):
#extract the label and bounding box coordinates
label = o.find("name").string
xMin = int(float(o.find("xmin").string))
yMin = int(float(o.find("ymin").string))
xMax = int(float(o.find("xmax").string))
yMax = int(float(o.find("ymax").string))
# truncate any bounding box coordinates that fall outside
# the boundaries of the image
xMin = max(0, xMin)
yMin = max(0, yMin)
xMax = min(w, xMax)
yMax = min(h, yMax)
# ignore the bounding boxes where the minimum values are larger
# than the maximum values and vice-versa due to annotation errors
if xMin >= xMax or yMin >= yMax:
continue
elif xMax <= xMin or yMax <= yMin:
continue
# write the image path, bb coordinates, label to the output CSV
row = [os.path.abspath(imagePath),str(xMin), str(yMin), str(xMax),
str(yMax), str(label)]
csv.write("{}\n".format(",".join(row)))
# update the set of unique class labels
CLASSES.add(label)
# close the CSV file
csv.close()
# write the classes to file
print("[INFO] writing classes...")
csv = open(classes_csv, "w")
rows = [",".join([c, str(i)]) for (i,c) in enumerate(CLASSES)]
csv.write("\n".join(rows))
csv.close()