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,281 @@
|
|
|
1
|
+
import numpy as np
|
|
2
|
+
from PIL import Image, ImageDraw, ImageFont
|
|
3
|
+
|
|
4
|
+
from edgefirst.validator.datasets import SegmentationInstance
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Colors:
|
|
8
|
+
"""
|
|
9
|
+
Ultralytics color palette for visualization and plotting.
|
|
10
|
+
Source: https://github.com/ultralytics/ultralytics/blob/main/ultralytics/utils/plotting.py#L19
|
|
11
|
+
|
|
12
|
+
This class provides methods to work with the Ultralytics color palette,
|
|
13
|
+
including converting hex color codes to RGB values and accessing predefined
|
|
14
|
+
color schemes for object detection and pose estimation.
|
|
15
|
+
|
|
16
|
+
Attributes
|
|
17
|
+
----------
|
|
18
|
+
palette: List[tuple]
|
|
19
|
+
List of RGB color tuples for general use.
|
|
20
|
+
n: int
|
|
21
|
+
The number of colors in the palette.
|
|
22
|
+
pose_palette: np.ndarray
|
|
23
|
+
A specific color palette array for pose estimation with dtype np.uint8.
|
|
24
|
+
|
|
25
|
+
Examples
|
|
26
|
+
--------
|
|
27
|
+
>>> from ultralytics.utils.plotting import Colors
|
|
28
|
+
>>> colors = Colors()
|
|
29
|
+
>>> colors(5, True) # Returns BGR format: (221, 111, 255)
|
|
30
|
+
>>> colors(5, False) # Returns RGB format: (255, 111, 221)
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
def __init__(self):
|
|
34
|
+
"""
|
|
35
|
+
Initialize colors as hex = matplotlib.colors.TABLEAU_COLORS.values().
|
|
36
|
+
"""
|
|
37
|
+
hexs = (
|
|
38
|
+
"042AFF",
|
|
39
|
+
"0BDBEB",
|
|
40
|
+
"F3F3F3",
|
|
41
|
+
"00DFB7",
|
|
42
|
+
"111F68",
|
|
43
|
+
"FF6FDD",
|
|
44
|
+
"FF444F",
|
|
45
|
+
"CCED00",
|
|
46
|
+
"00F344",
|
|
47
|
+
"BD00FF",
|
|
48
|
+
"00B4FF",
|
|
49
|
+
"DD00BA",
|
|
50
|
+
"00FFFF",
|
|
51
|
+
"26C000",
|
|
52
|
+
"01FFB3",
|
|
53
|
+
"7D24FF",
|
|
54
|
+
"7B0068",
|
|
55
|
+
"FF1B6C",
|
|
56
|
+
"FC6D2F",
|
|
57
|
+
"A2FF0B",
|
|
58
|
+
)
|
|
59
|
+
self.palette = [self.hex2rgb(f"#{c}") for c in hexs]
|
|
60
|
+
self.n = len(self.palette)
|
|
61
|
+
self.pose_palette = np.array(
|
|
62
|
+
[
|
|
63
|
+
[255, 128, 0],
|
|
64
|
+
[255, 153, 51],
|
|
65
|
+
[255, 178, 102],
|
|
66
|
+
[230, 230, 0],
|
|
67
|
+
[255, 153, 255],
|
|
68
|
+
[153, 204, 255],
|
|
69
|
+
[255, 102, 255],
|
|
70
|
+
[255, 51, 255],
|
|
71
|
+
[102, 178, 255],
|
|
72
|
+
[51, 153, 255],
|
|
73
|
+
[255, 153, 153],
|
|
74
|
+
[255, 102, 102],
|
|
75
|
+
[255, 51, 51],
|
|
76
|
+
[153, 255, 153],
|
|
77
|
+
[102, 255, 102],
|
|
78
|
+
[51, 255, 51],
|
|
79
|
+
[0, 255, 0],
|
|
80
|
+
[0, 0, 255],
|
|
81
|
+
[255, 0, 0],
|
|
82
|
+
[255, 255, 255],
|
|
83
|
+
],
|
|
84
|
+
dtype=np.uint8,
|
|
85
|
+
)
|
|
86
|
+
|
|
87
|
+
def __call__(self, i: int, bgr: bool = False) -> tuple:
|
|
88
|
+
"""
|
|
89
|
+
Convert hex color codes to RGB values.
|
|
90
|
+
|
|
91
|
+
Parameters
|
|
92
|
+
----------
|
|
93
|
+
i : int
|
|
94
|
+
Index of the color in the palette.
|
|
95
|
+
bgr : bool, optional
|
|
96
|
+
If True, return color in BGR format. Default is False.
|
|
97
|
+
|
|
98
|
+
Returns
|
|
99
|
+
-------
|
|
100
|
+
tuple
|
|
101
|
+
A 3-element tuple representing the RGB or BGR color.
|
|
102
|
+
"""
|
|
103
|
+
c = self.palette[int(i) % self.n]
|
|
104
|
+
return (c[2], c[1], c[0]) if bgr else c
|
|
105
|
+
|
|
106
|
+
@staticmethod
|
|
107
|
+
def hex2rgb(h: str) -> tuple:
|
|
108
|
+
"""
|
|
109
|
+
Convert hex color codes to RGB values (i.e. default PIL order).
|
|
110
|
+
|
|
111
|
+
Parameters
|
|
112
|
+
----------
|
|
113
|
+
h : str
|
|
114
|
+
Hex color string (e.g. "#FF00AA").
|
|
115
|
+
|
|
116
|
+
Returns
|
|
117
|
+
-------
|
|
118
|
+
tuple
|
|
119
|
+
A 3-element tuple representing the RGB color.
|
|
120
|
+
"""
|
|
121
|
+
return tuple(int(h[1 + i: 1 + i + 2], 16) for i in (0, 2, 4))
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class SegmentationDrawer:
|
|
125
|
+
"""
|
|
126
|
+
This class draws segmentation masks from the ground truth and
|
|
127
|
+
model predictions on the image.
|
|
128
|
+
"""
|
|
129
|
+
|
|
130
|
+
def __init__(self):
|
|
131
|
+
self.font = ImageFont.load_default()
|
|
132
|
+
self.colors = Colors()
|
|
133
|
+
|
|
134
|
+
def mask2maskimage(
|
|
135
|
+
self,
|
|
136
|
+
gt_instance: SegmentationInstance,
|
|
137
|
+
dt_instance: SegmentationInstance,
|
|
138
|
+
semantic: bool = True
|
|
139
|
+
) -> Image.Image:
|
|
140
|
+
"""
|
|
141
|
+
Masks the original image and returns the original image
|
|
142
|
+
with mask prediction on the left and mask ground truth on the right.
|
|
143
|
+
This method is used for drawing semantic segmentation masks as
|
|
144
|
+
the input.
|
|
145
|
+
|
|
146
|
+
Parameters
|
|
147
|
+
----------
|
|
148
|
+
gt_instance: SegmentationInstance
|
|
149
|
+
This object contains the ground truth mask.
|
|
150
|
+
dt_instance: SegmentationInstance
|
|
151
|
+
This object contains the predictions mask.
|
|
152
|
+
semantic: bool
|
|
153
|
+
The condition that specifies whether or not the
|
|
154
|
+
segmentation masks are semantic or instance.
|
|
155
|
+
|
|
156
|
+
Returns
|
|
157
|
+
-------
|
|
158
|
+
Image.Image
|
|
159
|
+
The image with drawn masks where on the right pane
|
|
160
|
+
shows the ground truth mask and on the left pane shows
|
|
161
|
+
the prediction mask.
|
|
162
|
+
"""
|
|
163
|
+
|
|
164
|
+
gt_image = Image.fromarray(np.uint8(gt_instance.visual_image))
|
|
165
|
+
if dt_instance.visual_image is not None:
|
|
166
|
+
dt_image = Image.fromarray(np.uint8(dt_instance.visual_image))
|
|
167
|
+
else:
|
|
168
|
+
dt_image = gt_image
|
|
169
|
+
|
|
170
|
+
gt_mask = gt_instance.mask
|
|
171
|
+
dt_mask = dt_instance.mask
|
|
172
|
+
|
|
173
|
+
# Create image from numpy masks.
|
|
174
|
+
mask_gt = self.mask2image(gt_mask,
|
|
175
|
+
labels=gt_instance.labels,
|
|
176
|
+
semantic=semantic)
|
|
177
|
+
mask_dt = self.mask2image(dt_mask,
|
|
178
|
+
labels=dt_instance.labels,
|
|
179
|
+
semantic=semantic)
|
|
180
|
+
|
|
181
|
+
image_gt = gt_image.convert("RGBA")
|
|
182
|
+
image_dt = dt_image.convert("RGBA")
|
|
183
|
+
mask_image_gt = Image.alpha_composite(image_gt, mask_gt).convert("RGB")
|
|
184
|
+
mask_image_dt = Image.alpha_composite(image_dt, mask_dt).convert("RGB")
|
|
185
|
+
|
|
186
|
+
dst = Image.new(
|
|
187
|
+
'RGB',
|
|
188
|
+
(mask_image_dt.width + mask_image_gt.width, mask_image_dt.height))
|
|
189
|
+
dst.paste(mask_image_gt, (0, 0))
|
|
190
|
+
dst.paste(mask_image_dt, (mask_image_dt.width, 0))
|
|
191
|
+
|
|
192
|
+
draw_text = ImageDraw.Draw(dst)
|
|
193
|
+
draw_text.text(
|
|
194
|
+
(0, 0),
|
|
195
|
+
"GROUND TRUTH",
|
|
196
|
+
font=self.font,
|
|
197
|
+
align='left',
|
|
198
|
+
fill=(0, 0, 0)
|
|
199
|
+
)
|
|
200
|
+
draw_text.text(
|
|
201
|
+
(mask_image_dt.width, 0),
|
|
202
|
+
"MODEL PREDICTION",
|
|
203
|
+
font=self.font,
|
|
204
|
+
align='left',
|
|
205
|
+
fill=(0, 0, 0)
|
|
206
|
+
)
|
|
207
|
+
return dst
|
|
208
|
+
|
|
209
|
+
def mask2image(
|
|
210
|
+
self,
|
|
211
|
+
mask: np.ndarray,
|
|
212
|
+
labels: list = [],
|
|
213
|
+
constant: int = None,
|
|
214
|
+
semantic: bool = True,
|
|
215
|
+
alpha: int = 130
|
|
216
|
+
) -> Image.Image:
|
|
217
|
+
"""
|
|
218
|
+
Transform a NumPy array of mask into an RGBA image.
|
|
219
|
+
|
|
220
|
+
Parameter
|
|
221
|
+
---------
|
|
222
|
+
mask: np.ndarray
|
|
223
|
+
Array (height, width) representing the mask.
|
|
224
|
+
labels: list
|
|
225
|
+
For instance segmentation, provides the integer label
|
|
226
|
+
for each mask.
|
|
227
|
+
constant: int
|
|
228
|
+
Specify a constant to color the mask with a single color
|
|
229
|
+
based on the constant specified which is the index to the
|
|
230
|
+
list of colors. By default, None is provided and colors
|
|
231
|
+
the masks based on the unique values in the mask.
|
|
232
|
+
semantic: bool
|
|
233
|
+
The condition that specifies whether or not the
|
|
234
|
+
segmentation masks are semantic or instance.
|
|
235
|
+
alpha: int
|
|
236
|
+
The constant value for the alpha channel.
|
|
237
|
+
|
|
238
|
+
Returns
|
|
239
|
+
-------
|
|
240
|
+
Image.Image
|
|
241
|
+
The masked image.
|
|
242
|
+
"""
|
|
243
|
+
# Transform dimension of masks from a 2D numpy array to 4D into RGBA.
|
|
244
|
+
if len(mask.shape) > 2:
|
|
245
|
+
_, height, width = mask.shape
|
|
246
|
+
else:
|
|
247
|
+
height, width = mask.shape
|
|
248
|
+
mask_4_channels = np.zeros((height, width, 4), dtype=np.uint8)
|
|
249
|
+
|
|
250
|
+
# Used for drawing an instance segmentation mask on the image
|
|
251
|
+
# based on the constance assigned for the mask label.
|
|
252
|
+
if constant:
|
|
253
|
+
# Assign all classes with color white. An instance segmentation
|
|
254
|
+
# mask is binary which has 0 and 1 values.
|
|
255
|
+
mask_4_channels[mask > 0] = 255
|
|
256
|
+
# Temporarily unpack the bands for readability.
|
|
257
|
+
red, green, blue, _ = mask_4_channels.T
|
|
258
|
+
# Areas of all classes.
|
|
259
|
+
u_areas = (red == 255) & (blue == 255) & (green == 255)
|
|
260
|
+
# Color all classes with the constant value.
|
|
261
|
+
mask_4_channels[..., :][u_areas.T] = np.append(
|
|
262
|
+
self.colors(constant), alpha)
|
|
263
|
+
else:
|
|
264
|
+
# For instance segmentation, the labels should be provided.
|
|
265
|
+
# Otherwise, the labels are taken from the unique values
|
|
266
|
+
# in the mask for semantic segmentation.
|
|
267
|
+
if semantic:
|
|
268
|
+
labels = np.sort(np.unique(mask))
|
|
269
|
+
for label in labels:
|
|
270
|
+
if label != 0:
|
|
271
|
+
# Designate a color for each class.
|
|
272
|
+
mask_4_channels[mask == label] = \
|
|
273
|
+
np.append(self.colors(label), alpha)
|
|
274
|
+
else:
|
|
275
|
+
for label, m in zip(labels, mask):
|
|
276
|
+
# Designate a color for each class.
|
|
277
|
+
mask_4_channels[m > 0] = np.append(
|
|
278
|
+
self.colors(label), alpha)
|
|
279
|
+
|
|
280
|
+
# Convert array to image object for image processing.
|
|
281
|
+
return Image.fromarray(mask_4_channels.astype(np.uint8))
|