edgefirst-validator 4.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- deepview/modelpack/utils/argmax.py +16 -0
- edgefirst/validator/__init__.py +1 -0
- edgefirst/validator/__main__.py +375 -0
- edgefirst/validator/datasets/__init__.py +118 -0
- edgefirst/validator/datasets/cache.py +296 -0
- edgefirst/validator/datasets/core.py +250 -0
- edgefirst/validator/datasets/darknet.py +446 -0
- edgefirst/validator/datasets/database.py +1067 -0
- edgefirst/validator/datasets/instance/__init__.py +4 -0
- edgefirst/validator/datasets/instance/core.py +222 -0
- edgefirst/validator/datasets/instance/detection.py +145 -0
- edgefirst/validator/datasets/instance/multitask.py +80 -0
- edgefirst/validator/datasets/instance/segmentation.py +120 -0
- edgefirst/validator/datasets/utils/fetch.py +682 -0
- edgefirst/validator/datasets/utils/readers.py +425 -0
- edgefirst/validator/datasets/utils/transformations.py +1695 -0
- edgefirst/validator/evaluators/__init__.py +17 -0
- edgefirst/validator/evaluators/callbacks/__init__.py +3 -0
- edgefirst/validator/evaluators/callbacks/core.py +192 -0
- edgefirst/validator/evaluators/callbacks/plots.py +900 -0
- edgefirst/validator/evaluators/callbacks/studio.py +234 -0
- edgefirst/validator/evaluators/core.py +257 -0
- edgefirst/validator/evaluators/detection.py +749 -0
- edgefirst/validator/evaluators/multitask.py +270 -0
- edgefirst/validator/evaluators/parameters/__init__.py +53 -0
- edgefirst/validator/evaluators/parameters/core.py +554 -0
- edgefirst/validator/evaluators/parameters/dataset.py +239 -0
- edgefirst/validator/evaluators/parameters/model.py +338 -0
- edgefirst/validator/evaluators/parameters/validation.py +528 -0
- edgefirst/validator/evaluators/segmentation.py +729 -0
- edgefirst/validator/evaluators/utils/__init__.py +3 -0
- edgefirst/validator/evaluators/utils/classify.py +292 -0
- edgefirst/validator/evaluators/utils/match.py +262 -0
- edgefirst/validator/evaluators/utils/timer.py +132 -0
- edgefirst/validator/metrics/__init__.py +9 -0
- edgefirst/validator/metrics/data/__init__.py +7 -0
- edgefirst/validator/metrics/data/label.py +668 -0
- edgefirst/validator/metrics/data/metrics.py +759 -0
- edgefirst/validator/metrics/data/plots.py +476 -0
- edgefirst/validator/metrics/data/stats.py +507 -0
- edgefirst/validator/metrics/detection.py +595 -0
- edgefirst/validator/metrics/segmentation.py +173 -0
- edgefirst/validator/metrics/utils/math.py +717 -0
- edgefirst/validator/publishers/__init__.py +3 -0
- edgefirst/validator/publishers/console.py +147 -0
- edgefirst/validator/publishers/studio.py +128 -0
- edgefirst/validator/publishers/tensorboard.py +119 -0
- edgefirst/validator/publishers/utils/logger.py +111 -0
- edgefirst/validator/publishers/utils/table.py +403 -0
- edgefirst/validator/runners/__init__.py +8 -0
- edgefirst/validator/runners/core.py +727 -0
- edgefirst/validator/runners/deepviewrt.py +177 -0
- edgefirst/validator/runners/hailo.py +263 -0
- edgefirst/validator/runners/keras.py +150 -0
- edgefirst/validator/runners/kinara.py +265 -0
- edgefirst/validator/runners/offline.py +228 -0
- edgefirst/validator/runners/onnx.py +241 -0
- edgefirst/validator/runners/processing/decode.py +320 -0
- edgefirst/validator/runners/processing/dvapi.py +4192 -0
- edgefirst/validator/runners/processing/nms.py +637 -0
- edgefirst/validator/runners/processing/outputs.py +507 -0
- edgefirst/validator/runners/tensorrt.py +321 -0
- edgefirst/validator/runners/tflite.py +221 -0
- edgefirst/validator/validate.py +843 -0
- edgefirst/validator/visualize/__init__.py +3 -0
- edgefirst/validator/visualize/detection.py +623 -0
- edgefirst/validator/visualize/segmentation.py +281 -0
- edgefirst/validator/visualize/utils/plots.py +635 -0
- edgefirst_validator-4.2.1.dist-info/METADATA +111 -0
- edgefirst_validator-4.2.1.dist-info/RECORD +73 -0
- edgefirst_validator-4.2.1.dist-info/WHEEL +5 -0
- edgefirst_validator-4.2.1.dist-info/entry_points.txt +2 -0
- edgefirst_validator-4.2.1.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
from edgefirst.validator.metrics.data.label import (DetectionLabelData,
|
|
2
|
+
SegmentationLabelData)
|
|
3
|
+
from edgefirst.validator.metrics.data.stats import (YOLOStats,
|
|
4
|
+
DetectionStats,
|
|
5
|
+
SegmentationStats)
|
|
6
|
+
from edgefirst.validator.metrics.data.metrics import Metrics, MultitaskMetrics
|
|
7
|
+
from edgefirst.validator.metrics.data.plots import Plots, MultitaskPlots
|
|
@@ -0,0 +1,668 @@
|
|
|
1
|
+
from typing import Union, List, Tuple
|
|
2
|
+
|
|
3
|
+
import numpy as np
|
|
4
|
+
|
|
5
|
+
from edgefirst.validator.datasets.utils.transformations import clamp
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class LabelData:
|
|
9
|
+
"""
|
|
10
|
+
Base class for the LabelData class that stores the pre-metric
|
|
11
|
+
computations of a specific label in validation.
|
|
12
|
+
|
|
13
|
+
Parameters
|
|
14
|
+
----------
|
|
15
|
+
label: Union[str, int, np.integer]
|
|
16
|
+
The unique string or integer index label to base the container.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
def __init__(self, label: Union[str, int, np.integer]):
|
|
20
|
+
# The label being represented in this class.
|
|
21
|
+
self.__label = label
|
|
22
|
+
# Total number of ground truths of the label.
|
|
23
|
+
self.__ground_truths = 0
|
|
24
|
+
# Total number of predictions of the label.
|
|
25
|
+
self.__predictions = 0
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def label(self) -> Union[str, int, np.integer]:
|
|
29
|
+
"""
|
|
30
|
+
Attribute to access the label stored.
|
|
31
|
+
|
|
32
|
+
Returns
|
|
33
|
+
-------
|
|
34
|
+
Union[str, int, np.integer]
|
|
35
|
+
The label stored.
|
|
36
|
+
"""
|
|
37
|
+
return self.__label
|
|
38
|
+
|
|
39
|
+
@label.setter
|
|
40
|
+
def label(self, this_label: Union[str, int, np.integer]):
|
|
41
|
+
"""
|
|
42
|
+
Sets the label.
|
|
43
|
+
|
|
44
|
+
Parameters
|
|
45
|
+
----------
|
|
46
|
+
this_label: Union[str, int, np.integer]
|
|
47
|
+
The label being represented in this container.
|
|
48
|
+
"""
|
|
49
|
+
self.__label = this_label
|
|
50
|
+
|
|
51
|
+
@property
|
|
52
|
+
def ground_truths(self) -> int:
|
|
53
|
+
"""
|
|
54
|
+
Attribute to access the number of ground truths.
|
|
55
|
+
|
|
56
|
+
Returns
|
|
57
|
+
-------
|
|
58
|
+
int
|
|
59
|
+
The number of ground truths for this label.
|
|
60
|
+
"""
|
|
61
|
+
return self.__ground_truths
|
|
62
|
+
|
|
63
|
+
@ground_truths.setter
|
|
64
|
+
def ground_truths(self, gts: int):
|
|
65
|
+
"""
|
|
66
|
+
Sets the number of ground truths for this label.
|
|
67
|
+
|
|
68
|
+
Parameters
|
|
69
|
+
----------
|
|
70
|
+
int
|
|
71
|
+
This is the number of ground truths for this label.
|
|
72
|
+
"""
|
|
73
|
+
self.__ground_truths = gts
|
|
74
|
+
|
|
75
|
+
def add_ground_truths(self, gts: int = 1):
|
|
76
|
+
"""
|
|
77
|
+
Adds the number of existing ground truths.
|
|
78
|
+
|
|
79
|
+
Parameters
|
|
80
|
+
----------
|
|
81
|
+
int
|
|
82
|
+
The number of ground truths to add.
|
|
83
|
+
"""
|
|
84
|
+
self.__ground_truths += gts
|
|
85
|
+
|
|
86
|
+
@property
|
|
87
|
+
def predictions(self) -> int:
|
|
88
|
+
"""
|
|
89
|
+
Attribute to access the number of predictions.
|
|
90
|
+
|
|
91
|
+
Returns
|
|
92
|
+
-------
|
|
93
|
+
int
|
|
94
|
+
The number of predictions for this label.
|
|
95
|
+
"""
|
|
96
|
+
return self.__predictions
|
|
97
|
+
|
|
98
|
+
@predictions.setter
|
|
99
|
+
def predictions(self, prd: int):
|
|
100
|
+
"""
|
|
101
|
+
Sets the number of predictions for this label.
|
|
102
|
+
|
|
103
|
+
Parameters
|
|
104
|
+
----------
|
|
105
|
+
prd: int
|
|
106
|
+
This is the number of predictions for this label.
|
|
107
|
+
"""
|
|
108
|
+
self.__predictions = prd
|
|
109
|
+
|
|
110
|
+
def add_predictions(self, prd: int = 1):
|
|
111
|
+
"""
|
|
112
|
+
Adds the number of existing predictions.
|
|
113
|
+
|
|
114
|
+
Parameters
|
|
115
|
+
----------
|
|
116
|
+
prd: int
|
|
117
|
+
The number of predictions to add.
|
|
118
|
+
"""
|
|
119
|
+
self.__predictions += prd
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
class DetectionLabelData(LabelData):
|
|
123
|
+
"""
|
|
124
|
+
Acts a container that stores the total number of true positives,
|
|
125
|
+
false positives, false negatives per label.
|
|
126
|
+
|
|
127
|
+
Parameters
|
|
128
|
+
----------
|
|
129
|
+
label: Union[str, int, np.integer]
|
|
130
|
+
The unique string or integer index label to base the container.
|
|
131
|
+
"""
|
|
132
|
+
|
|
133
|
+
def __init__(self, label: Union[str, int, np.integer]):
|
|
134
|
+
super(DetectionLabelData, self).__init__(label)
|
|
135
|
+
|
|
136
|
+
# Contains (IoU, score) values for predictions
|
|
137
|
+
# marked as true positives.
|
|
138
|
+
self.__tps = list()
|
|
139
|
+
# Contains (IoU, score) values for predictions marked as
|
|
140
|
+
# classification false positives.
|
|
141
|
+
self.__class_fps = list()
|
|
142
|
+
# Contains score values for predictions captured as
|
|
143
|
+
# localization false positives.
|
|
144
|
+
self.__local_fps = list()
|
|
145
|
+
|
|
146
|
+
@property
|
|
147
|
+
def tps(self) -> List[Tuple[float, float]]:
|
|
148
|
+
"""
|
|
149
|
+
Attribute to access the true positives data.
|
|
150
|
+
|
|
151
|
+
Returns
|
|
152
|
+
-------
|
|
153
|
+
List[Tuple[float, float]]
|
|
154
|
+
This contains the (IoU, score) of each
|
|
155
|
+
true positive for this label.
|
|
156
|
+
"""
|
|
157
|
+
return self.__tps
|
|
158
|
+
|
|
159
|
+
@tps.setter
|
|
160
|
+
def tps(self, this_tps: List[Tuple[float, float]]):
|
|
161
|
+
"""
|
|
162
|
+
Sets the true positives data to a new value.
|
|
163
|
+
|
|
164
|
+
Parameters
|
|
165
|
+
----------
|
|
166
|
+
this_tps: List[Tuple[float, float]]
|
|
167
|
+
These are the true positives data to set.
|
|
168
|
+
"""
|
|
169
|
+
self.__tps = this_tps
|
|
170
|
+
|
|
171
|
+
def add_tp(self, iou: float, score: float):
|
|
172
|
+
"""
|
|
173
|
+
Adds the true positive prediction IoU and confidence score.
|
|
174
|
+
A true positive is when the prediction and the ground truth
|
|
175
|
+
label matches and the IoU is greater than the set IoU threshold.
|
|
176
|
+
|
|
177
|
+
Parameters
|
|
178
|
+
----------
|
|
179
|
+
iou: float
|
|
180
|
+
The IoU of the true positive prediction.
|
|
181
|
+
score: float
|
|
182
|
+
The confidence score of the true positive prediction.
|
|
183
|
+
"""
|
|
184
|
+
self.__tps.append((clamp(iou), clamp(score)))
|
|
185
|
+
|
|
186
|
+
def get_tp_scores(self, iou_threshold: float) -> np.ndarray:
|
|
187
|
+
"""
|
|
188
|
+
Grabs the prediction scores marked as true positives.
|
|
189
|
+
|
|
190
|
+
Parameters
|
|
191
|
+
----------
|
|
192
|
+
iou_threshold: float
|
|
193
|
+
The IoU threshold to consider true positives.
|
|
194
|
+
|
|
195
|
+
Returns
|
|
196
|
+
-------
|
|
197
|
+
np.ndarray
|
|
198
|
+
The true positive confidence scores.
|
|
199
|
+
"""
|
|
200
|
+
if len(self.tps):
|
|
201
|
+
tp_iou = np.array(self.tps)[:, 0] >= iou_threshold
|
|
202
|
+
tp_scores = np.array(self.tps)[:, 1] * tp_iou
|
|
203
|
+
return tp_scores[tp_scores != 0]
|
|
204
|
+
return np.array([])
|
|
205
|
+
|
|
206
|
+
def get_tp_iou(self, iou_threshold: float) -> np.ndarray:
|
|
207
|
+
"""
|
|
208
|
+
Grabs the prediction IoUs marked as true positives.
|
|
209
|
+
|
|
210
|
+
Parameters
|
|
211
|
+
----------
|
|
212
|
+
iou_threshold: float
|
|
213
|
+
The IoU threshold to consider true positives.
|
|
214
|
+
|
|
215
|
+
Returns
|
|
216
|
+
-------
|
|
217
|
+
np.ndarray
|
|
218
|
+
The true positive IoU values.
|
|
219
|
+
"""
|
|
220
|
+
if len(self.tps):
|
|
221
|
+
tp_iou = np.array(self.tps)[:, 0] >= iou_threshold
|
|
222
|
+
tp_ious = np.array(self.tps)[:, 0] * tp_iou
|
|
223
|
+
return tp_ious[tp_ious != 0]
|
|
224
|
+
return np.array([])
|
|
225
|
+
|
|
226
|
+
def get_tp_count(
|
|
227
|
+
self,
|
|
228
|
+
iou_threshold: float,
|
|
229
|
+
score_threshold: float = 0.0
|
|
230
|
+
) -> int:
|
|
231
|
+
"""
|
|
232
|
+
Grabs the number of true positives at the
|
|
233
|
+
specified IoU threshold and score threshold.
|
|
234
|
+
|
|
235
|
+
Parameters
|
|
236
|
+
----------
|
|
237
|
+
iou_threshold: float
|
|
238
|
+
The IoU threshold to filter the true positives.
|
|
239
|
+
score_threshold: float
|
|
240
|
+
The score threshold to filter the true positives.
|
|
241
|
+
|
|
242
|
+
Returns
|
|
243
|
+
-------
|
|
244
|
+
int
|
|
245
|
+
The number of true positives at the specified
|
|
246
|
+
IoU and score threshold.
|
|
247
|
+
"""
|
|
248
|
+
if len(self.tps):
|
|
249
|
+
tp_iou = np.array(self.tps)[:, 0] >= iou_threshold
|
|
250
|
+
tp_score = np.array(self.tps)[:, 1] >= score_threshold
|
|
251
|
+
return np.count_nonzero(tp_iou * tp_score)
|
|
252
|
+
return 0
|
|
253
|
+
|
|
254
|
+
@property
|
|
255
|
+
def class_fps(self) -> List[Tuple[float, float]]:
|
|
256
|
+
"""
|
|
257
|
+
Attribute to access the classification false positives data.
|
|
258
|
+
|
|
259
|
+
Returns
|
|
260
|
+
-------
|
|
261
|
+
List[Tuple[float, float]]
|
|
262
|
+
This contains the (IoU, score) of each classification
|
|
263
|
+
false positive for this label.
|
|
264
|
+
"""
|
|
265
|
+
return self.__class_fps
|
|
266
|
+
|
|
267
|
+
@class_fps.setter
|
|
268
|
+
def class_fps(self, this_class_fps: List[Tuple[float, float]]):
|
|
269
|
+
"""
|
|
270
|
+
Sets the classification false positives data to a new value.
|
|
271
|
+
|
|
272
|
+
Parameters
|
|
273
|
+
----------
|
|
274
|
+
this_class_fp: List[Tuple[float, float]]
|
|
275
|
+
These are the classification false positives data to set.
|
|
276
|
+
"""
|
|
277
|
+
self.__class_fps = this_class_fps
|
|
278
|
+
|
|
279
|
+
def add_cfp(self, iou: float, score: float):
|
|
280
|
+
"""
|
|
281
|
+
Adds the false positive (classification) prediction IoU
|
|
282
|
+
and confidence score. A false positive (classification) is when
|
|
283
|
+
the prediction and the ground truth labels don't match and the
|
|
284
|
+
IoU is greater than the set IoU threshold.
|
|
285
|
+
|
|
286
|
+
Parameters
|
|
287
|
+
----------
|
|
288
|
+
iou: float
|
|
289
|
+
The IoU of the classification false positive prediction.
|
|
290
|
+
score: float
|
|
291
|
+
The confidence score of the classification false
|
|
292
|
+
positive prediction.
|
|
293
|
+
"""
|
|
294
|
+
self.class_fps.append((clamp(iou), clamp(score)))
|
|
295
|
+
|
|
296
|
+
def get_cfp_scores(self, iou_threshold: float) -> np.ndarray:
|
|
297
|
+
"""
|
|
298
|
+
Grabs the prediction scores marked as classification false positives.
|
|
299
|
+
|
|
300
|
+
Parameters
|
|
301
|
+
----------
|
|
302
|
+
iou_threshold: float
|
|
303
|
+
The IoU threshold to consider as classification
|
|
304
|
+
false positives.
|
|
305
|
+
|
|
306
|
+
Returns
|
|
307
|
+
-------
|
|
308
|
+
np.ndarray
|
|
309
|
+
The classification false positive scores.
|
|
310
|
+
"""
|
|
311
|
+
if len(self.class_fps):
|
|
312
|
+
cfp_iou = np.array(self.class_fps)[:, 0] >= iou_threshold
|
|
313
|
+
cfp_scores = np.array(self.class_fps)[:, 1] * cfp_iou
|
|
314
|
+
return cfp_scores[cfp_scores != 0]
|
|
315
|
+
return np.array([])
|
|
316
|
+
|
|
317
|
+
def get_cfp_iou(self, iou_threshold: float) -> np.ndarray:
|
|
318
|
+
"""
|
|
319
|
+
Grabs the prediction IoUs marked as classification false positives.
|
|
320
|
+
|
|
321
|
+
Parameters
|
|
322
|
+
----------
|
|
323
|
+
iou_threshold: float
|
|
324
|
+
The IoU threshold to consider as classification
|
|
325
|
+
false positives.
|
|
326
|
+
|
|
327
|
+
Returns
|
|
328
|
+
-------
|
|
329
|
+
np.ndarray
|
|
330
|
+
The classification false positive IoUs.
|
|
331
|
+
"""
|
|
332
|
+
if len(self.class_fps):
|
|
333
|
+
cfp_iou = np.array(self.class_fps)[:, 0] >= iou_threshold
|
|
334
|
+
cfp_ious = np.array(self.class_fps)[:, 0] * cfp_iou
|
|
335
|
+
return cfp_ious[cfp_ious != 0]
|
|
336
|
+
return np.array([])
|
|
337
|
+
|
|
338
|
+
def get_cfp_count(
|
|
339
|
+
self,
|
|
340
|
+
iou_threshold: float,
|
|
341
|
+
score_threshold: float = 0.0
|
|
342
|
+
) -> int:
|
|
343
|
+
"""
|
|
344
|
+
Grabs the number of classification false positives at
|
|
345
|
+
the specified IoU and score threshold.
|
|
346
|
+
|
|
347
|
+
Parameters
|
|
348
|
+
----------
|
|
349
|
+
iou_threshold: float
|
|
350
|
+
The IoU threshold to filter classification false positives.
|
|
351
|
+
score_threshold: float
|
|
352
|
+
The score threshold to filter classification false positives.
|
|
353
|
+
|
|
354
|
+
Returns
|
|
355
|
+
-------
|
|
356
|
+
int
|
|
357
|
+
The number of classification false positives at the
|
|
358
|
+
specified IoU and score threshold.
|
|
359
|
+
"""
|
|
360
|
+
if len(self.class_fps):
|
|
361
|
+
fp_iou = np.array(self.class_fps)[:, 0] >= iou_threshold
|
|
362
|
+
fp_score = np.array(self.class_fps)[:, 1] >= score_threshold
|
|
363
|
+
return np.count_nonzero(fp_iou * fp_score)
|
|
364
|
+
return 0
|
|
365
|
+
|
|
366
|
+
@property
|
|
367
|
+
def local_fps(self) -> List[float]:
|
|
368
|
+
"""
|
|
369
|
+
Attribute to access the localization false positives data.
|
|
370
|
+
|
|
371
|
+
Returns
|
|
372
|
+
-------
|
|
373
|
+
List[float]
|
|
374
|
+
This contains the score of each localization
|
|
375
|
+
false positive for this label.
|
|
376
|
+
"""
|
|
377
|
+
return self.__local_fps
|
|
378
|
+
|
|
379
|
+
@local_fps.setter
|
|
380
|
+
def local_fps(self, this_local_fps: List[float]):
|
|
381
|
+
"""
|
|
382
|
+
Sets the localization false positives data to a new value.
|
|
383
|
+
|
|
384
|
+
Parameters
|
|
385
|
+
----------
|
|
386
|
+
this_local_fps: List[float]
|
|
387
|
+
These are localization false positives data to set.
|
|
388
|
+
"""
|
|
389
|
+
self.__local_fps = this_local_fps
|
|
390
|
+
|
|
391
|
+
def add_lfp(self, score: float):
|
|
392
|
+
"""
|
|
393
|
+
Adds the number of localization false positive captured.
|
|
394
|
+
A localization false positive is when there is a
|
|
395
|
+
prediction but no ground truth.
|
|
396
|
+
|
|
397
|
+
Parameters
|
|
398
|
+
----------
|
|
399
|
+
score: float
|
|
400
|
+
The confidence score of the localization
|
|
401
|
+
false positive prediction.
|
|
402
|
+
"""
|
|
403
|
+
self.local_fps.append(clamp(score))
|
|
404
|
+
|
|
405
|
+
def get_lfp_iou(self, iou_threshold: float) -> np.ndarray:
|
|
406
|
+
"""
|
|
407
|
+
Grabs the prediction IoUs marked as localization false positives.
|
|
408
|
+
|
|
409
|
+
Parameters
|
|
410
|
+
----------
|
|
411
|
+
iou_threshold: float
|
|
412
|
+
The IoU threshold to consider as false positives.
|
|
413
|
+
|
|
414
|
+
Returns
|
|
415
|
+
-------
|
|
416
|
+
np.ndarray
|
|
417
|
+
The false positive IoU values.
|
|
418
|
+
"""
|
|
419
|
+
local_fps = []
|
|
420
|
+
if len(self.tps):
|
|
421
|
+
# Any predictions that are below the IoU thresholds are
|
|
422
|
+
# localization false positives.
|
|
423
|
+
fp_iou = np.array(self.tps)[:, 0] < iou_threshold
|
|
424
|
+
local_fps = np.array(self.tps)[:, 0] * fp_iou
|
|
425
|
+
local_fps = local_fps[local_fps != 0]
|
|
426
|
+
local_fps = local_fps.tolist()
|
|
427
|
+
|
|
428
|
+
if len(self.class_fps):
|
|
429
|
+
class_fp_iou = np.array(self.class_fps)[:, 0] < iou_threshold
|
|
430
|
+
local_cfps = np.array(self.class_fps)[:, 0] * class_fp_iou
|
|
431
|
+
local_cfps = local_cfps[local_cfps != 0]
|
|
432
|
+
local_cfps = local_cfps.tolist()
|
|
433
|
+
local_fps += local_cfps
|
|
434
|
+
return np.array(local_fps)
|
|
435
|
+
|
|
436
|
+
def get_lfp_scores(self, iou_threshold: float) -> np.ndarray:
|
|
437
|
+
"""
|
|
438
|
+
Grabs the prediction scores marked as localization false positives.
|
|
439
|
+
|
|
440
|
+
Parameters
|
|
441
|
+
----------
|
|
442
|
+
iou_threshold: float
|
|
443
|
+
The IoU threshold to consider true positives as
|
|
444
|
+
localization false positives.
|
|
445
|
+
|
|
446
|
+
Returns
|
|
447
|
+
-------
|
|
448
|
+
np.ndarray
|
|
449
|
+
The localization false positive scores.
|
|
450
|
+
"""
|
|
451
|
+
local_fps = []
|
|
452
|
+
if len(self.tps):
|
|
453
|
+
# Any predictions that are below the IoU thresholds are
|
|
454
|
+
# localization false positives.
|
|
455
|
+
fp_iou = np.array(self.tps)[:, 0] < iou_threshold
|
|
456
|
+
local_fps = np.array(self.tps)[:, 1] * fp_iou
|
|
457
|
+
local_fps = local_fps[local_fps != 0]
|
|
458
|
+
local_fps = local_fps.tolist()
|
|
459
|
+
|
|
460
|
+
if len(self.class_fps):
|
|
461
|
+
class_fp_iou = np.array(self.class_fps)[:, 0] < iou_threshold
|
|
462
|
+
local_cfps = np.array(self.class_fps)[:, 1] * class_fp_iou
|
|
463
|
+
local_cfps = local_cfps[local_cfps != 0]
|
|
464
|
+
local_cfps = local_cfps.tolist()
|
|
465
|
+
local_fps += local_cfps
|
|
466
|
+
|
|
467
|
+
if len(self.local_fps):
|
|
468
|
+
local_fps += self.local_fps
|
|
469
|
+
|
|
470
|
+
return np.array(local_fps)
|
|
471
|
+
|
|
472
|
+
def get_lfp_count(
|
|
473
|
+
self,
|
|
474
|
+
iou_threshold: float,
|
|
475
|
+
score_threshold: float = 0.0
|
|
476
|
+
) -> int:
|
|
477
|
+
"""
|
|
478
|
+
Grabs the number of localization false positives at the specified IoU
|
|
479
|
+
and score threshold. The IoU threshold is needed because true positives
|
|
480
|
+
that have an IoU less than the set IoU threshold will be considered as
|
|
481
|
+
localization false positives.
|
|
482
|
+
|
|
483
|
+
Parameters
|
|
484
|
+
----------
|
|
485
|
+
iou_threshold: float
|
|
486
|
+
The IoU threshold to consider true positives as local
|
|
487
|
+
false positives.
|
|
488
|
+
score_threshold: float
|
|
489
|
+
The score threshold to consider predictions.
|
|
490
|
+
|
|
491
|
+
Returns
|
|
492
|
+
-------
|
|
493
|
+
int
|
|
494
|
+
The number of localization false positives at the
|
|
495
|
+
specified IoU and score threshold.
|
|
496
|
+
"""
|
|
497
|
+
local_fp = 0
|
|
498
|
+
if len(self.tps):
|
|
499
|
+
# Any predictions that are below the IoU thresholds are
|
|
500
|
+
# localization false positives.
|
|
501
|
+
fp_iou = np.array(self.tps)[:, 0] < iou_threshold
|
|
502
|
+
tp_score = np.array(self.tps)[:, 1] >= score_threshold
|
|
503
|
+
local_fp += np.count_nonzero(fp_iou * tp_score)
|
|
504
|
+
|
|
505
|
+
if len(self.class_fps):
|
|
506
|
+
class_fp_iou = np.array(self.class_fps)[:, 0] < iou_threshold
|
|
507
|
+
class_fp_score = np.array(self.class_fps)[:, 1] >= score_threshold
|
|
508
|
+
local_fp += np.count_nonzero(class_fp_iou * class_fp_score)
|
|
509
|
+
|
|
510
|
+
local_fp += np.count_nonzero(np.array(self.local_fps)
|
|
511
|
+
>= score_threshold)
|
|
512
|
+
return local_fp
|
|
513
|
+
|
|
514
|
+
def get_fn_count(
|
|
515
|
+
self,
|
|
516
|
+
iou_threshold: float,
|
|
517
|
+
score_threshold: float = 0.0
|
|
518
|
+
) -> int:
|
|
519
|
+
"""
|
|
520
|
+
Grabs the number of false negatives at the specified IoU threshold
|
|
521
|
+
and score threshold. Score threshold is needed because by principle
|
|
522
|
+
fp = gt - tp, and score and IoU threshold is required to find the
|
|
523
|
+
number of true positives.
|
|
524
|
+
|
|
525
|
+
Parameters
|
|
526
|
+
----------
|
|
527
|
+
iou_threshold: float
|
|
528
|
+
The IoU threshold to consider true positives.
|
|
529
|
+
score_threshold: float
|
|
530
|
+
The score threshold to consider predictions.
|
|
531
|
+
|
|
532
|
+
Returns
|
|
533
|
+
-------
|
|
534
|
+
int
|
|
535
|
+
The number of false negatives at the specified
|
|
536
|
+
IoU and score threshold.
|
|
537
|
+
"""
|
|
538
|
+
return self.ground_truths - self.get_tp_count(
|
|
539
|
+
iou_threshold, score_threshold)
|
|
540
|
+
|
|
541
|
+
|
|
542
|
+
class SegmentationLabelData(LabelData):
|
|
543
|
+
"""
|
|
544
|
+
Acts a container that stores the total number of true predictions and
|
|
545
|
+
false predictions for a specific label.
|
|
546
|
+
|
|
547
|
+
Parameters
|
|
548
|
+
----------
|
|
549
|
+
label: Union[str, int, np.integer]
|
|
550
|
+
The unique string or integer index label to base the container.
|
|
551
|
+
"""
|
|
552
|
+
|
|
553
|
+
def __init__(self, label: Union[str, int, np.integer]):
|
|
554
|
+
super(SegmentationLabelData, self).__init__(label)
|
|
555
|
+
|
|
556
|
+
# Total number of both ground truths and predictions of this label.
|
|
557
|
+
self.__union = 0
|
|
558
|
+
# Total number of true prediction pixels.
|
|
559
|
+
self.__true_predictions = 0
|
|
560
|
+
# Total number of false prediction pixels.
|
|
561
|
+
self.__false_predictions = 0
|
|
562
|
+
|
|
563
|
+
@property
|
|
564
|
+
def union(self) -> int:
|
|
565
|
+
"""
|
|
566
|
+
Attribute to access the number of union pixels.
|
|
567
|
+
|
|
568
|
+
Returns
|
|
569
|
+
-------
|
|
570
|
+
int
|
|
571
|
+
The number of union pixels for this label.
|
|
572
|
+
"""
|
|
573
|
+
return self.__union
|
|
574
|
+
|
|
575
|
+
@union.setter
|
|
576
|
+
def union(self, uni: int):
|
|
577
|
+
"""
|
|
578
|
+
Sets the number of union pixels for this label.
|
|
579
|
+
Union pixels is the sum total of both ground truths and
|
|
580
|
+
predictions for this label.
|
|
581
|
+
|
|
582
|
+
Parameters
|
|
583
|
+
----------
|
|
584
|
+
uni: int
|
|
585
|
+
This is the number of union pixels for this label.
|
|
586
|
+
"""
|
|
587
|
+
self.__union = uni
|
|
588
|
+
|
|
589
|
+
def add_union(self, uni: int = 1):
|
|
590
|
+
"""
|
|
591
|
+
Adds the number of existing union pixels.
|
|
592
|
+
|
|
593
|
+
Parameters
|
|
594
|
+
----------
|
|
595
|
+
uni: int
|
|
596
|
+
The number of union pixels to add.
|
|
597
|
+
"""
|
|
598
|
+
self.__union += uni
|
|
599
|
+
|
|
600
|
+
@property
|
|
601
|
+
def true_predictions(self) -> int:
|
|
602
|
+
"""
|
|
603
|
+
Attribute to access the number of true predictions.
|
|
604
|
+
|
|
605
|
+
Returns
|
|
606
|
+
-------
|
|
607
|
+
int
|
|
608
|
+
The number of true predictions for this label.
|
|
609
|
+
"""
|
|
610
|
+
return self.__true_predictions
|
|
611
|
+
|
|
612
|
+
@true_predictions.setter
|
|
613
|
+
def true_predictions(self, tps: int):
|
|
614
|
+
"""
|
|
615
|
+
Sets the number of true predictions for this label.
|
|
616
|
+
|
|
617
|
+
Parameters
|
|
618
|
+
----------
|
|
619
|
+
tps: int
|
|
620
|
+
This is the number of true predictions for this label.
|
|
621
|
+
"""
|
|
622
|
+
self.__true_predictions = tps
|
|
623
|
+
|
|
624
|
+
def add_true_predictions(self, tps: int = 1):
|
|
625
|
+
"""
|
|
626
|
+
Adds the number of existing true predictions.
|
|
627
|
+
|
|
628
|
+
Parameters
|
|
629
|
+
----------
|
|
630
|
+
tps: int
|
|
631
|
+
The number of true predictions to add.
|
|
632
|
+
"""
|
|
633
|
+
self.__true_predictions += tps
|
|
634
|
+
|
|
635
|
+
@property
|
|
636
|
+
def false_predictions(self) -> int:
|
|
637
|
+
"""
|
|
638
|
+
Attribute to access the number of false predictions.
|
|
639
|
+
|
|
640
|
+
Returns
|
|
641
|
+
-------
|
|
642
|
+
int
|
|
643
|
+
The number of false predictions for this label.
|
|
644
|
+
"""
|
|
645
|
+
return self.__false_predictions
|
|
646
|
+
|
|
647
|
+
@false_predictions.setter
|
|
648
|
+
def false_predictions(self, fps: int):
|
|
649
|
+
"""
|
|
650
|
+
Sets the number of false predictions for this label.
|
|
651
|
+
|
|
652
|
+
Parameters
|
|
653
|
+
----------
|
|
654
|
+
fps: int
|
|
655
|
+
This is the number of false predictions for this label.
|
|
656
|
+
"""
|
|
657
|
+
self.__false_predictions = fps
|
|
658
|
+
|
|
659
|
+
def add_false_predictions(self, fps: int = 1):
|
|
660
|
+
"""
|
|
661
|
+
Adds the number of existing false predictions.
|
|
662
|
+
|
|
663
|
+
Parameters
|
|
664
|
+
----------
|
|
665
|
+
fps: int
|
|
666
|
+
The number of false predictions to add.
|
|
667
|
+
"""
|
|
668
|
+
self.__false_predictions += fps
|