Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
matterport
GitHub Repository: matterport/Mask_RCNN
Path: blob/master/samples/shapes/shapes.py
240 views
1
"""
2
Mask R-CNN
3
Configurations and data loading code for the synthetic Shapes dataset.
4
This is a duplicate of the code in the noteobook train_shapes.ipynb for easy
5
import into other notebooks, such as inspect_model.ipynb.
6
7
Copyright (c) 2017 Matterport, Inc.
8
Licensed under the MIT License (see LICENSE for details)
9
Written by Waleed Abdulla
10
"""
11
12
import os
13
import sys
14
import math
15
import random
16
import numpy as np
17
import cv2
18
19
# Root directory of the project
20
ROOT_DIR = os.path.abspath("../../")
21
22
# Import Mask RCNN
23
sys.path.append(ROOT_DIR) # To find local version of the library
24
from mrcnn.config import Config
25
from mrcnn import utils
26
27
28
class ShapesConfig(Config):
29
"""Configuration for training on the toy shapes dataset.
30
Derives from the base Config class and overrides values specific
31
to the toy shapes dataset.
32
"""
33
# Give the configuration a recognizable name
34
NAME = "shapes"
35
36
# Train on 1 GPU and 8 images per GPU. We can put multiple images on each
37
# GPU because the images are small. Batch size is 8 (GPUs * images/GPU).
38
GPU_COUNT = 1
39
IMAGES_PER_GPU = 8
40
41
# Number of classes (including background)
42
NUM_CLASSES = 1 + 3 # background + 3 shapes
43
44
# Use small images for faster training. Set the limits of the small side
45
# the large side, and that determines the image shape.
46
IMAGE_MIN_DIM = 128
47
IMAGE_MAX_DIM = 128
48
49
# Use smaller anchors because our image and objects are small
50
RPN_ANCHOR_SCALES = (8, 16, 32, 64, 128) # anchor side in pixels
51
52
# Reduce training ROIs per image because the images are small and have
53
# few objects. Aim to allow ROI sampling to pick 33% positive ROIs.
54
TRAIN_ROIS_PER_IMAGE = 32
55
56
# Use a small epoch since the data is simple
57
STEPS_PER_EPOCH = 100
58
59
# use small validation steps since the epoch is small
60
VALIDATION_STEPS = 5
61
62
63
class ShapesDataset(utils.Dataset):
64
"""Generates the shapes synthetic dataset. The dataset consists of simple
65
shapes (triangles, squares, circles) placed randomly on a blank surface.
66
The images are generated on the fly. No file access required.
67
"""
68
69
def load_shapes(self, count, height, width):
70
"""Generate the requested number of synthetic images.
71
count: number of images to generate.
72
height, width: the size of the generated images.
73
"""
74
# Add classes
75
self.add_class("shapes", 1, "square")
76
self.add_class("shapes", 2, "circle")
77
self.add_class("shapes", 3, "triangle")
78
79
# Add images
80
# Generate random specifications of images (i.e. color and
81
# list of shapes sizes and locations). This is more compact than
82
# actual images. Images are generated on the fly in load_image().
83
for i in range(count):
84
bg_color, shapes = self.random_image(height, width)
85
self.add_image("shapes", image_id=i, path=None,
86
width=width, height=height,
87
bg_color=bg_color, shapes=shapes)
88
89
def load_image(self, image_id):
90
"""Generate an image from the specs of the given image ID.
91
Typically this function loads the image from a file, but
92
in this case it generates the image on the fly from the
93
specs in image_info.
94
"""
95
info = self.image_info[image_id]
96
bg_color = np.array(info['bg_color']).reshape([1, 1, 3])
97
image = np.ones([info['height'], info['width'], 3], dtype=np.uint8)
98
image = image * bg_color.astype(np.uint8)
99
for shape, color, dims in info['shapes']:
100
image = self.draw_shape(image, shape, dims, color)
101
return image
102
103
def image_reference(self, image_id):
104
"""Return the shapes data of the image."""
105
info = self.image_info[image_id]
106
if info["source"] == "shapes":
107
return info["shapes"]
108
else:
109
super(self.__class__).image_reference(self, image_id)
110
111
def load_mask(self, image_id):
112
"""Generate instance masks for shapes of the given image ID.
113
"""
114
info = self.image_info[image_id]
115
shapes = info['shapes']
116
count = len(shapes)
117
mask = np.zeros([info['height'], info['width'], count], dtype=np.uint8)
118
for i, (shape, _, dims) in enumerate(info['shapes']):
119
mask[:, :, i:i + 1] = self.draw_shape(mask[:, :, i:i + 1].copy(),
120
shape, dims, 1)
121
# Handle occlusions
122
occlusion = np.logical_not(mask[:, :, -1]).astype(np.uint8)
123
for i in range(count - 2, -1, -1):
124
mask[:, :, i] = mask[:, :, i] * occlusion
125
occlusion = np.logical_and(
126
occlusion, np.logical_not(mask[:, :, i]))
127
# Map class names to class IDs.
128
class_ids = np.array([self.class_names.index(s[0]) for s in shapes])
129
return mask, class_ids.astype(np.int32)
130
131
def draw_shape(self, image, shape, dims, color):
132
"""Draws a shape from the given specs."""
133
# Get the center x, y and the size s
134
x, y, s = dims
135
if shape == 'square':
136
image = cv2.rectangle(image, (x - s, y - s),
137
(x + s, y + s), color, -1)
138
elif shape == "circle":
139
image = cv2.circle(image, (x, y), s, color, -1)
140
elif shape == "triangle":
141
points = np.array([[(x, y - s),
142
(x - s / math.sin(math.radians(60)), y + s),
143
(x + s / math.sin(math.radians(60)), y + s),
144
]], dtype=np.int32)
145
image = cv2.fillPoly(image, points, color)
146
return image
147
148
def random_shape(self, height, width):
149
"""Generates specifications of a random shape that lies within
150
the given height and width boundaries.
151
Returns a tuple of three valus:
152
* The shape name (square, circle, ...)
153
* Shape color: a tuple of 3 values, RGB.
154
* Shape dimensions: A tuple of values that define the shape size
155
and location. Differs per shape type.
156
"""
157
# Shape
158
shape = random.choice(["square", "circle", "triangle"])
159
# Color
160
color = tuple([random.randint(0, 255) for _ in range(3)])
161
# Center x, y
162
buffer = 20
163
y = random.randint(buffer, height - buffer - 1)
164
x = random.randint(buffer, width - buffer - 1)
165
# Size
166
s = random.randint(buffer, height // 4)
167
return shape, color, (x, y, s)
168
169
def random_image(self, height, width):
170
"""Creates random specifications of an image with multiple shapes.
171
Returns the background color of the image and a list of shape
172
specifications that can be used to draw the image.
173
"""
174
# Pick random background color
175
bg_color = np.array([random.randint(0, 255) for _ in range(3)])
176
# Generate a few random shapes and record their
177
# bounding boxes
178
shapes = []
179
boxes = []
180
N = random.randint(1, 4)
181
for _ in range(N):
182
shape, color, dims = self.random_shape(height, width)
183
shapes.append((shape, color, dims))
184
x, y, s = dims
185
boxes.append([y - s, x - s, y + s, x + s])
186
# Apply non-max suppression wit 0.3 threshold to avoid
187
# shapes covering each other
188
keep_ixs = utils.non_max_suppression(
189
np.array(boxes), np.arange(N), 0.3)
190
shapes = [s for i, s in enumerate(shapes) if i in keep_ixs]
191
return bg_color, shapes
192
193