-
Notifications
You must be signed in to change notification settings - Fork 212
/
person_blocker.py
148 lines (117 loc) · 5 KB
/
person_blocker.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
import os
import sys
import argparse
import numpy as np
import coco
import utils
import model as modellib
from classes import get_class_names, InferenceConfig
from ast import literal_eval as make_tuple
import imageio
import visualize
# Creates a color layer and adds Gaussian noise.
# For each pixel, the same noise value is added to each channel
# to mitigate hue shfting.
def create_noisy_color(image, color):
color_mask = np.full(shape=(image.shape[0], image.shape[1], 3),
fill_value=color)
noise = np.random.normal(0, 25, (image.shape[0], image.shape[1]))
noise = np.repeat(np.expand_dims(noise, axis=2), repeats=3, axis=2)
mask_noise = np.clip(color_mask + noise, 0., 255.)
return mask_noise
# Helper function to allow both RGB triplet + hex CL input
def string_to_rgb_triplet(triplet):
if '#' in triplet:
# http://stackoverflow.com/a/4296727
triplet = triplet.lstrip('#')
_NUMERALS = '0123456789abcdefABCDEF'
_HEXDEC = {v: int(v, 16)
for v in (x + y for x in _NUMERALS for y in _NUMERALS)}
return (_HEXDEC[triplet[0:2]], _HEXDEC[triplet[2:4]],
_HEXDEC[triplet[4:6]])
else:
# https://stackoverflow.com/a/9763133
triplet = make_tuple(triplet)
return triplet
def person_blocker(args):
# Required to load model, but otherwise unused
ROOT_DIR = os.getcwd()
COCO_MODEL_PATH = args.model or os.path.join(ROOT_DIR, "mask_rcnn_coco.h5")
MODEL_DIR = os.path.join(ROOT_DIR, "logs") # Required to load model
if not os.path.exists(COCO_MODEL_PATH):
utils.download_trained_weights(COCO_MODEL_PATH)
# Load model and config
config = InferenceConfig()
model = modellib.MaskRCNN(mode="inference",
model_dir=MODEL_DIR, config=config)
model.load_weights(COCO_MODEL_PATH, by_name=True)
image = imageio.imread(args.image)
# Create masks for all objects
results = model.detect([image], verbose=0)
r = results[0]
if args.labeled:
position_ids = ['[{}]'.format(x)
for x in range(r['class_ids'].shape[0])]
visualize.display_instances(image, r['rois'],
r['masks'], r['class_ids'],
get_class_names(), position_ids)
sys.exit()
# Filter masks to only the selected objects
objects = np.array(args.objects)
# Object IDs:
if np.all(np.chararray.isnumeric(objects)):
object_indices = objects.astype(int)
# Types of objects:
else:
selected_class_ids = np.flatnonzero(np.in1d(get_class_names(),
objects))
object_indices = np.flatnonzero(
np.in1d(r['class_ids'], selected_class_ids))
mask_selected = np.sum(r['masks'][:, :, object_indices], axis=2)
# Replace object masks with noise
mask_color = string_to_rgb_triplet(args.color)
image_masked = image.copy()
noisy_color = create_noisy_color(image, mask_color)
image_masked[mask_selected > 0] = noisy_color[mask_selected > 0]
imageio.imwrite('person_blocked.png', image_masked)
# Create GIF. The noise will be random for each frame,
# which creates a "static" effect
images = [image_masked]
num_images = 10 # should be a divisor of 30
for _ in range(num_images - 1):
new_image = image.copy()
noisy_color = create_noisy_color(image, mask_color)
new_image[mask_selected > 0] = noisy_color[mask_selected > 0]
images.append(new_image)
imageio.mimsave('person_blocked.gif', images, fps=30., subrectangles=True)
if __name__ == '__main__':
parser = argparse.ArgumentParser(
description='Person Blocker - Automatically "block" people '
'in images using a neural network.')
parser.add_argument('-i', '--image', help='Image file name.',
required=False)
parser.add_argument(
'-m', '--model', help='path to COCO model', default=None)
parser.add_argument('-o',
'--objects', nargs='+',
help='object(s)/object ID(s) to block. ' +
'Use the -names flag to print a list of ' +
'valid objects',
default='person')
parser.add_argument('-c',
'--color', nargs='?', default='(255, 255, 255)',
help='color of the "block"')
parser.add_argument('-l',
'--labeled', dest='labeled',
action='store_true',
help='generate labeled image instead')
parser.add_argument('-n',
'--names', dest='names',
action='store_true',
help='prints class names and exits.')
parser.set_defaults(labeled=False, names=False)
args = parser.parse_args()
if args.names:
print(get_class_names())
sys.exit()
person_blocker(args)