CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
amanchadha

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place. Commercial Alternative to JupyterHub.

GitHub Repository: amanchadha/coursera-deep-learning-specialization
Path: blob/master/C4 - Convolutional Neural Networks/Week 3/Car detection for Autonomous Driving/yad2k/utils/utils.py
Views: 4822
1
"""Draw predicted or ground truth boxes on input image."""
2
import imghdr
3
import colorsys
4
import random
5
6
import numpy as np
7
from PIL import Image, ImageDraw, ImageFont
8
from tensorflow.keras import backend as K
9
10
from functools import reduce
11
12
def preprocess_image(img_path, model_image_size):
13
image_type = imghdr.what(img_path)
14
image = Image.open(img_path)
15
resized_image = image.resize(tuple(reversed(model_image_size)), Image.BICUBIC)
16
image_data = np.array(resized_image, dtype='float32')
17
image_data /= 255.
18
image_data = np.expand_dims(image_data, 0) # Add batch dimension.
19
return image, image_data
20
21
def compose(*funcs):
22
"""Compose arbitrarily many functions, evaluated left to right.
23
24
Reference: https://mathieularose.com/function-composition-in-python/
25
"""
26
# return lambda x: reduce(lambda v, f: f(v), funcs, x)
27
if funcs:
28
return reduce(lambda f, g: lambda *a, **kw: g(f(*a, **kw)), funcs)
29
else:
30
raise ValueError('Composition of empty sequence not supported.')
31
32
def read_classes(classes_path):
33
with open(classes_path) as f:
34
class_names = f.readlines()
35
class_names = [c.strip() for c in class_names]
36
return class_names
37
38
def read_anchors(anchors_path):
39
with open(anchors_path) as f:
40
anchors = f.readline()
41
anchors = [float(x) for x in anchors.split(',')]
42
anchors = np.array(anchors).reshape(-1, 2)
43
return anchors
44
45
def scale_boxes(boxes, image_shape):
46
""" Scales the predicted boxes in order to be drawable on the image"""
47
height = image_shape[0] * 1.0
48
width = image_shape[1] * 1.0
49
image_dims = K.stack([height, width, height, width])
50
image_dims = K.reshape(image_dims, [1, 4])
51
boxes = boxes * image_dims
52
return boxes
53
54
def get_colors_for_classes(num_classes):
55
"""Return list of random colors for number of classes given."""
56
# Use previously generated colors if num_classes is the same.
57
if (hasattr(get_colors_for_classes, "colors") and
58
len(get_colors_for_classes.colors) == num_classes):
59
return get_colors_for_classes.colors
60
61
hsv_tuples = [(x / num_classes, 1., 1.) for x in range(num_classes)]
62
colors = list(map(lambda x: colorsys.hsv_to_rgb(*x), hsv_tuples))
63
colors = list(
64
map(lambda x: (int(x[0] * 255), int(x[1] * 255), int(x[2] * 255)),
65
colors))
66
random.seed(10101) # Fixed seed for consistent colors across runs.
67
random.shuffle(colors) # Shuffle colors to decorrelate adjacent classes.
68
random.seed(None) # Reset seed to default.
69
get_colors_for_classes.colors = colors # Save colors for future calls.
70
return colors
71
72
def textsize(text, font):
73
im = Image.new(mode="P", size=(0, 0))
74
draw = ImageDraw.Draw(im)
75
_, _, width, height = draw.textbbox((0, 0), text=text, font=font)
76
return width, height
77
78
def draw_boxes(image, boxes, box_classes, class_names, scores=None):
79
"""Draw bounding boxes on image.
80
81
Draw bounding boxes with class name and optional box score on image.
82
83
Args:
84
image: An `array` of shape (width, height, 3) with values in [0, 1].
85
boxes: An `array` of shape (num_boxes, 4) containing box corners as
86
(y_min, x_min, y_max, x_max).
87
box_classes: A `list` of indicies into `class_names`.
88
class_names: A `list` of `string` class names.
89
`scores`: A `list` of scores for each box.
90
91
Returns:
92
A copy of `image` modified with given bounding boxes.
93
"""
94
#image = Image.fromarray(np.floor(image * 255 + 0.5).astype('uint8'))
95
96
font = ImageFont.truetype(
97
font='font/FiraMono-Medium.otf',
98
size=np.floor(3e-2 * image.size[1] + 0.5).astype('int32'))
99
thickness = (image.size[0] + image.size[1]) // 300
100
101
colors = get_colors_for_classes(len(class_names))
102
103
for i, c in list(enumerate(box_classes)):
104
box_class = class_names[c]
105
box = boxes[i]
106
107
if isinstance(scores.numpy(), np.ndarray):
108
score = scores.numpy()[i]
109
label = '{} {:.2f}'.format(box_class, score)
110
else:
111
label = '{}'.format(box_class)
112
113
draw = ImageDraw.Draw(image)
114
label_size = textsize(label, font)
115
116
top, left, bottom, right = box
117
top = max(0, np.floor(top + 0.5).astype('int32'))
118
left = max(0, np.floor(left + 0.5).astype('int32'))
119
bottom = min(image.size[1], np.floor(bottom + 0.5).astype('int32'))
120
right = min(image.size[0], np.floor(right + 0.5).astype('int32'))
121
print(label, (left, top), (right, bottom))
122
123
if top - label_size[1] >= 0:
124
text_origin = np.array([left, top - label_size[1]])
125
else:
126
text_origin = np.array([left, top + 1])
127
128
# My kingdom for a good redistributable image drawing library.
129
for i in range(thickness):
130
draw.rectangle(
131
[left + i, top + i, right - i, bottom - i], outline=colors[c])
132
draw.rectangle(
133
[tuple(text_origin), tuple(text_origin + label_size)],
134
fill=colors[c])
135
draw.text(text_origin, label, fill=(0, 0, 0), font=font)
136
del draw
137
138
return np.array(image)
139
140