forked from guichristmann/edge-tpu-tiny-yolo
-
Notifications
You must be signed in to change notification settings - Fork 0
/
utils.py
155 lines (128 loc) · 5.16 KB
/
utils.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
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
import numpy as np
import os
import cv2
# Maximum number of boxes. Only the top scoring ones will be considered.
MAX_BOXES = 30
def sigmoid(x):
return 1. / (1 + np.exp(-x))
def letterbox_image(image, size):
'''resize image with unchanged aspect ratio using padding'''
iw, ih = image.shape[0:2][::-1]
w, h = size
scale = min(w/iw, h/ih)
nw = int(iw*scale)
nh = int(ih*scale)
image = cv2.resize(image, (nw,nh), interpolation=cv2.INTER_CUBIC)
new_image = np.zeros((size[1], size[0], 3), np.uint8)
new_image.fill(128)
dx = (w-nw)//2
dy = (h-nh)//2
new_image[dy:dy+nh, dx:dx+nw,:] = image
return new_image
def featuresToBoxes(outputs, anchors, n_classes, net_input_shape,
img_orig_shape, threshold):
grid_shape = outputs.shape[1:3]
n_anchors = len(anchors)
# Numpy screwaround to get the boxes in reasonable amount of time
grid_y = np.tile(np.arange(grid_shape[0]).reshape(-1, 1), grid_shape[0]).reshape(1, grid_shape[0], grid_shape[0], 1).astype(np.float32)
grid_x = grid_y.copy().T.reshape(1, grid_shape[0], grid_shape[1], 1).astype(np.float32)
outputs = outputs.reshape(1, grid_shape[0], grid_shape[1], n_anchors, -1)
_anchors = anchors.reshape(1, 1, 3, 2).astype(np.float32)
# Get box parameters from network output and apply transformations
bx = (sigmoid(outputs[..., 0]) + grid_x) / grid_shape[0]
by = (sigmoid(outputs[..., 1]) + grid_y) / grid_shape[1]
# Should these be inverted?
bw = np.multiply(_anchors[..., 0] / net_input_shape[1], np.exp(outputs[..., 2]))
bh = np.multiply(_anchors[..., 1] / net_input_shape[2], np.exp(outputs[..., 3]))
# Get the scores
scores = sigmoid(np.expand_dims(outputs[..., 4], -1)) * \
sigmoid(outputs[..., 5:])
scores = scores.reshape(-1, n_classes)
# Reshape boxes and scale back to original image size
ratio = net_input_shape[2] / img_orig_shape[1]
letterboxed_height = ratio * img_orig_shape[0]
scale = net_input_shape[1] / letterboxed_height
offset = (net_input_shape[1] - letterboxed_height) / 2 / net_input_shape[1]
bx = bx.flatten()
by = (by.flatten() - offset) * scale
bw = bw.flatten()
bh = bh.flatten() * scale
half_bw = bw / 2.
half_bh = bh / 2.
tl_x = np.multiply(bx - half_bw, img_orig_shape[1])
tl_y = np.multiply(by - half_bh, img_orig_shape[0])
br_x = np.multiply(bx + half_bw, img_orig_shape[1])
br_y = np.multiply(by + half_bh, img_orig_shape[0])
# Get indices of boxes with score higher than threshold
indices = np.argwhere(scores >= threshold)
selected_boxes = []
selected_scores = []
for i in indices:
i = tuple(i)
selected_boxes.append( ((tl_x[i[0]], tl_y[i[0]]), (br_x[i[0]], br_y[i[0]])) )
selected_scores.append(scores[i])
selected_boxes = np.array(selected_boxes)
selected_scores = np.array(selected_scores)
selected_classes = indices[:, 1]
return selected_boxes, selected_scores, selected_classes
def get_anchors(path):
anchors_path = os.path.expanduser(path)
with open(anchors_path) as f:
anchors = f.readline()
anchors = [float(x) for x in anchors.split(',')]
return np.array(anchors).reshape(-1, 2)
def get_classes(path):
classes_path = os.path.expanduser(path)
with open(classes_path) as f:
classes = [line.strip('\n') for line in f.readlines()]
return classes
def nms_boxes(boxes, scores, classes):
present_classes = np.unique(classes)
assert(boxes.shape[0] == scores.shape[0])
assert(boxes.shape[0] == classes.shape[0])
# Sort based on score
indices = np.arange(len(scores))
scores, sorted_is = (list(l) for l in zip(*sorted(zip(scores, indices), reverse=True)))
boxes = list(boxes[sorted_is])
classes = list(classes[sorted_is])
# Run nms for each class
i = 0
while True:
if len(boxes) == 1 or i >= len(boxes) or i == MAX_BOXES:
break
# Get box with highest score
best_box = boxes[i]
best_cl = classes[i]
# Iterate over other boxes
to_remove = []
for j in range(i+1, len(boxes)):
other_cl = classes[j]
#if other_cl != best_cl:
# continue
other_box = boxes[j]
box_iou = iou(best_box, other_box)
if box_iou > 0.15:
to_remove.append(j)
if len(to_remove) == 0:
break
else:
# Remove boxes
for r in to_remove[::-1]:
del boxes[r]
del scores[r]
del classes[r]
i += 1
return boxes[:MAX_BOXES], scores[:MAX_BOXES], classes[:MAX_BOXES]
def iou(box1, box2):
xi1 = max(box1[0][0], box2[0][0])
yi1 = max(box1[0][1], box2[0][1])
xi2 = min(box1[1][0], box2[1][0])
yi2 = min(box1[1][1], box2[1][1])
inter_area = (xi2 - xi1)*(yi2 - yi1)
# Formula: Union(A,B) = A + B - Inter(A,B)
box1_area = (box1[1][1] - box1[0][1])*(box1[1][0]- box1[0][0])
box2_area = (box2[1][1] - box2[0][1])*(box2[1][0]- box2[0][0])
union_area = (box1_area + box2_area) - inter_area
# compute the IoU
IoU = inter_area / union_area
return IoU