|
21 | 21 |
|
22 | 22 |
|
23 | 23 | class SSD(Model):
|
24 |
| - class SingleOutputParser: |
25 |
| - def __init__(self, all_outputs): |
26 |
| - if len(all_outputs) != 1: |
27 |
| - raise ValueError('Network must have only one output.') |
28 |
| - self.output_name, output_data = next(iter(all_outputs.items())) |
29 |
| - last_dim = np.shape(output_data)[-1] |
30 |
| - if last_dim != 7: |
31 |
| - raise ValueError('The last dimension of the output blob must be equal to 7, ' |
32 |
| - 'got {} instead.'.format(last_dim)) |
33 |
| - |
34 |
| - def __call__(self, outputs): |
35 |
| - return [Detection(xmin, ymin, xmax, ymax, score, label) |
36 |
| - for _, label, score, xmin, ymin, xmax, ymax in outputs[self.output_name][0][0]] |
37 |
| - |
38 |
| - class MultipleOutputParser: |
39 |
| - def __init__(self, layers, bboxes_layer='bboxes', scores_layer='scores', labels_layer='labels'): |
40 |
| - def find_layer_by_name(name, layers): |
41 |
| - suitable_layers = [layer_name for layer_name in layers if name in layer_name] |
42 |
| - if not suitable_layers: |
43 |
| - raise ValueError('Suitable layer for "{}" output is not found'.format(name)) |
44 |
| - |
45 |
| - if len(suitable_layers) > 1: |
46 |
| - raise ValueError('More than 1 layer matched to "{}" output'.format(name)) |
47 |
| - |
48 |
| - return suitable_layers[0] |
49 |
| - self.labels_layer = find_layer_by_name(labels_layer, layers) |
50 |
| - self.scores_layer = find_layer_by_name(scores_layer, layers) |
51 |
| - self.bboxes_layer = find_layer_by_name(bboxes_layer, layers) |
52 |
| - |
53 |
| - def __call__(self, outputs): |
54 |
| - bboxes = outputs[self.bboxes_layer][0] |
55 |
| - scores = outputs[self.scores_layer][0] |
56 |
| - labels = outputs[self.labels_layer][0] |
57 |
| - return [Detection(*bbox, score, label) for label, score, bbox in zip(labels, scores, bboxes)] |
58 |
| - |
59 |
| - class BoxesLabelsParser: |
60 |
| - def __init__(self, input_size, all_outputs, labels_layer='labels', default_label=1): |
61 |
| - try: |
62 |
| - self.labels_layer = find_layer_by_name(labels_layer, all_outputs) # ? |
63 |
| - self.logger.info('Use output "{}" as the one containing labels of detected objects.' |
64 |
| - .format(self.labels_layer)) |
65 |
| - except ValueError: |
66 |
| - self.logger.warning('Suitable layer for "{}" output is not found. ' |
67 |
| - 'Treating detector as class agnostic with output label {}' |
68 |
| - .format(labels_layer, default_label)) |
69 |
| - self.labels_layer = None |
70 |
| - self.default_label = default_label |
71 |
| - |
72 |
| - self.input_size = input_size |
73 |
| - self.bboxes_layer = self.find_layer_bboxes_output(all_outputs) |
74 |
| - self.logger.info('Use auto-detected output "{}" as the one containing detected bounding boxes.' |
75 |
| - .format(self.bboxes_layer)) |
76 |
| - |
77 |
| - @staticmethod |
78 |
| - def find_layer_bboxes_output(all_outputs): |
79 |
| - filter_outputs = [ |
80 |
| - output_name for output_name, out_data in all_outputs.items() |
81 |
| - if len(np.shape(out_data)) == 2 and np.shape(out_data)[-1] == 5 |
82 |
| - ] |
83 |
| - if not filter_outputs: |
84 |
| - raise ValueError('Suitable output with bounding boxes is not found') |
85 |
| - if len(filter_outputs) > 1: |
86 |
| - raise ValueError('More than 1 candidate for output with bounding boxes.') |
87 |
| - return filter_outputs[0] |
88 |
| - |
89 |
| - def __call__(self, outputs): |
90 |
| - bboxes = outputs[self.bboxes_layer] |
91 |
| - scores = bboxes[:, 4] |
92 |
| - bboxes = bboxes[:, :4] |
93 |
| - bboxes[:, 0::2] /= self.input_size[0] |
94 |
| - bboxes[:, 1::2] /= self.input_size[1] |
95 |
| - if self.labels_layer: |
96 |
| - labels = outputs[self.labels_layer] + 1 |
97 |
| - else: |
98 |
| - labels = np.full(len(bboxes), self.default_label, dtype=bboxes.dtype) |
99 |
| - |
100 |
| - detections = [Detection(*bbox, score, label) for label, score, bbox in zip(labels, scores, bboxes)] |
101 |
| - return detections |
102 |
| - |
103 | 24 | def __init__(self, ie, model_path, labels=None, keep_aspect_ratio_resize=False):
|
104 | 25 | super().__init__(ie, model_path)
|
105 | 26 |
|
@@ -131,22 +52,21 @@ def _get_inputs(self):
|
131 | 52 |
|
132 | 53 | def _get_output_parser(self, net, image_blob_name, bboxes='bboxes', labels='labels', scores='scores'):
|
133 | 54 | try:
|
134 |
| - parser = self.SingleOutputParser(net.outputs) |
| 55 | + parser = SingleOutputParser(net.outputs) |
135 | 56 | self.logger.info('Use SingleOutputParser')
|
136 | 57 | return parser
|
137 | 58 | except ValueError:
|
138 | 59 | pass
|
139 | 60 |
|
140 | 61 | try:
|
141 |
| - parser = self.MultipleOutputParser(net.outputs, bboxes, scores, labels) |
| 62 | + parser = MultipleOutputParser(net.outputs, bboxes, scores, labels) |
142 | 63 | self.logger.info('Use MultipleOutputParser')
|
143 | 64 | return parser
|
144 | 65 | except ValueError:
|
145 | 66 | pass
|
146 | 67 |
|
147 | 68 | try:
|
148 |
| - h, w = net.input_info[image_blob_name].input_data.shape[2:] |
149 |
| - parser = self.BoxesLabelsParser([w, h], net.outputs) |
| 69 | + parser = BoxesLabelsParser(net.outputs, net.input_info[image_blob_name].input_data.shape[2:]) |
150 | 70 | self.logger.info('Use BoxesLabelsParser')
|
151 | 71 | return parser
|
152 | 72 | except ValueError:
|
@@ -184,3 +104,77 @@ def postprocess(self, outputs, meta):
|
184 | 104 | detection.ymin *= scale_y
|
185 | 105 | detection.ymax *= scale_y
|
186 | 106 | return detections
|
| 107 | + |
| 108 | + |
| 109 | +def find_layer_by_name(name, layers): |
| 110 | + suitable_layers = [layer_name for layer_name in layers if name in layer_name] |
| 111 | + if not suitable_layers: |
| 112 | + raise ValueError('Suitable layer for "{}" output is not found'.format(name)) |
| 113 | + |
| 114 | + if len(suitable_layers) > 1: |
| 115 | + raise ValueError('More than 1 layer matched to "{}" output'.format(name)) |
| 116 | + |
| 117 | + return suitable_layers[0] |
| 118 | + |
| 119 | + |
| 120 | +class SingleOutputParser: |
| 121 | + def __init__(self, all_outputs): |
| 122 | + if len(all_outputs) != 1: |
| 123 | + raise ValueError('Network must have only one output.') |
| 124 | + self.output_name, output_data = next(iter(all_outputs.items())) |
| 125 | + last_dim = np.shape(output_data)[-1] |
| 126 | + if last_dim != 7: |
| 127 | + raise ValueError('The last dimension of the output blob must be equal to 7, ' |
| 128 | + 'got {} instead.'.format(last_dim)) |
| 129 | + |
| 130 | + def __call__(self, outputs): |
| 131 | + return [Detection(xmin, ymin, xmax, ymax, score, label) |
| 132 | + for _, label, score, xmin, ymin, xmax, ymax in outputs[self.output_name][0][0]] |
| 133 | + |
| 134 | + |
| 135 | +class MultipleOutputParser: |
| 136 | + def __init__(self, layers, bboxes_layer='bboxes', scores_layer='scores', labels_layer='labels'): |
| 137 | + self.labels_layer = find_layer_by_name(labels_layer, layers) |
| 138 | + self.scores_layer = find_layer_by_name(scores_layer, layers) |
| 139 | + self.bboxes_layer = find_layer_by_name(bboxes_layer, layers) |
| 140 | + |
| 141 | + def __call__(self, outputs): |
| 142 | + bboxes = outputs[self.bboxes_layer][0] |
| 143 | + scores = outputs[self.scores_layer][0] |
| 144 | + labels = outputs[self.labels_layer][0] |
| 145 | + return [Detection(*bbox, score, label) for label, score, bbox in zip(labels, scores, bboxes)] |
| 146 | + |
| 147 | + |
| 148 | +class BoxesLabelsParser: |
| 149 | + def __init__(self, layers, input_size, labels_layer='labels', default_label=0): |
| 150 | + try: |
| 151 | + self.labels_layer = find_layer_by_name(labels_layer, layers) |
| 152 | + except ValueError: |
| 153 | + self.labels_layer = None |
| 154 | + self.default_label = default_label |
| 155 | + |
| 156 | + self.bboxes_layer = self.find_layer_bboxes_output(layers) |
| 157 | + self.input_size = input_size |
| 158 | + |
| 159 | + @staticmethod |
| 160 | + def find_layer_bboxes_output(layers): |
| 161 | + filter_outputs = [name for name, data in layers.items() if len(np.shape(data)) == 2 and np.shape(data)[-1] == 5] |
| 162 | + if not filter_outputs: |
| 163 | + raise ValueError('Suitable output with bounding boxes is not found') |
| 164 | + if len(filter_outputs) > 1: |
| 165 | + raise ValueError('More than 1 candidate for output with bounding boxes.') |
| 166 | + return filter_outputs[0] |
| 167 | + |
| 168 | + def __call__(self, outputs): |
| 169 | + bboxes = outputs[self.bboxes_layer] |
| 170 | + scores = bboxes[:, 4] |
| 171 | + bboxes = bboxes[:, :4] |
| 172 | + bboxes[:, 0::2] /= self.input_size[0] |
| 173 | + bboxes[:, 1::2] /= self.input_size[1] |
| 174 | + if self.labels_layer: |
| 175 | + labels = outputs[self.labels_layer] |
| 176 | + else: |
| 177 | + labels = np.full(len(bboxes), self.default_label, dtype=bboxes.dtype) |
| 178 | + |
| 179 | + detections = [Detection(*bbox, score, label) for label, score, bbox in zip(labels, scores, bboxes)] |
| 180 | + return detections |
0 commit comments