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,425 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module contains functions for reading various dataset files.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import json
|
|
7
|
+
import warnings
|
|
8
|
+
|
|
9
|
+
import numpy as np
|
|
10
|
+
from PIL import Image, ImageFile
|
|
11
|
+
|
|
12
|
+
from edgefirst.validator.publishers.utils.logger import logger
|
|
13
|
+
|
|
14
|
+
ImageFile.LOAD_TRUNCATED_IMAGES = True
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def read_image(image_path: str, rotate: bool = False) -> np.ndarray:
|
|
18
|
+
"""
|
|
19
|
+
Opens the image using pillow.Image and if the image is neither in the
|
|
20
|
+
format: [RGB, RGBA, CMYK, YCVCr] then the image will be converted to RGB.
|
|
21
|
+
|
|
22
|
+
Parameters
|
|
23
|
+
----------
|
|
24
|
+
image_path: str
|
|
25
|
+
The path to the image to read.
|
|
26
|
+
rotate: bool
|
|
27
|
+
If set to True, read from the image EXIF and
|
|
28
|
+
apply the rotation specified.
|
|
29
|
+
|
|
30
|
+
Returns
|
|
31
|
+
-------
|
|
32
|
+
np.ndarray
|
|
33
|
+
The image represented as a numpy array.
|
|
34
|
+
"""
|
|
35
|
+
if rotate:
|
|
36
|
+
from edgefirst.validator.datasets.utils.transformations import rotate_image
|
|
37
|
+
image = rotate_image(image_path)
|
|
38
|
+
else:
|
|
39
|
+
image = Image.open(image_path)
|
|
40
|
+
if image.mode in ["RGB", "RGBA", "CMYK", "YCbCr"]:
|
|
41
|
+
image = np.asarray(image)
|
|
42
|
+
else:
|
|
43
|
+
image.convert("RGB")
|
|
44
|
+
image = np.asarray(image, dtype=np.uint8)
|
|
45
|
+
image = np.stack((image,) * 3, axis=-1)
|
|
46
|
+
return image
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def read_labels_file(file_path: str) -> list:
|
|
50
|
+
"""
|
|
51
|
+
Opens a text file containing the string labels from
|
|
52
|
+
either the dataset or the model. It returns the list of string labels,
|
|
53
|
+
as the contents in the text file.
|
|
54
|
+
|
|
55
|
+
Parameters
|
|
56
|
+
----------
|
|
57
|
+
file_path: str
|
|
58
|
+
The path to the labels.txt file.
|
|
59
|
+
|
|
60
|
+
Returns
|
|
61
|
+
-------
|
|
62
|
+
list
|
|
63
|
+
The list of string labels as the contents of the text
|
|
64
|
+
file with a string label per line.
|
|
65
|
+
"""
|
|
66
|
+
with open(file_path) as file:
|
|
67
|
+
labels = [line.rstrip()
|
|
68
|
+
for line in file.readlines()
|
|
69
|
+
if line not in ["\n", "", "\t"]]
|
|
70
|
+
return labels
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def read_yaml_file(file_path: str) -> dict:
|
|
74
|
+
"""
|
|
75
|
+
Reads YAML files with Au-Zone specific format
|
|
76
|
+
for collecting dataset information.
|
|
77
|
+
|
|
78
|
+
Parameters
|
|
79
|
+
----------
|
|
80
|
+
file_path: str
|
|
81
|
+
The path to the YAML file.
|
|
82
|
+
|
|
83
|
+
Returns
|
|
84
|
+
-------
|
|
85
|
+
dict
|
|
86
|
+
Stores the YAML file contents.
|
|
87
|
+
|
|
88
|
+
Raises
|
|
89
|
+
------
|
|
90
|
+
FileNotFoundError
|
|
91
|
+
Raised if the path to the file does not exist.
|
|
92
|
+
"""
|
|
93
|
+
import yaml
|
|
94
|
+
if not os.path.exists(file_path):
|
|
95
|
+
raise FileNotFoundError(f"YAML file not found: '{file_path}'")
|
|
96
|
+
with open(file_path) as file:
|
|
97
|
+
return yaml.full_load(file)
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def read_toml_file(file_path: str) -> dict:
|
|
101
|
+
"""
|
|
102
|
+
Reads TOML files using tomli.
|
|
103
|
+
|
|
104
|
+
Parameters
|
|
105
|
+
----------
|
|
106
|
+
file_path: str
|
|
107
|
+
The path to the TOML file.
|
|
108
|
+
|
|
109
|
+
Returns
|
|
110
|
+
-------
|
|
111
|
+
dict
|
|
112
|
+
The contents of the TOML file.
|
|
113
|
+
"""
|
|
114
|
+
import tomli
|
|
115
|
+
if not os.path.exists(file_path):
|
|
116
|
+
raise FileNotFoundError(f"TOML file not found: '{file_path}'")
|
|
117
|
+
with open(file_path, "rb") as f:
|
|
118
|
+
return tomli.load(f)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def read_npy_file(annotation_path: str) -> np.ndarray:
|
|
122
|
+
"""
|
|
123
|
+
Reads NumPy files which typically contains radar data.
|
|
124
|
+
|
|
125
|
+
Parameters
|
|
126
|
+
----------
|
|
127
|
+
annotation_path: str
|
|
128
|
+
The path to the NumPy file.
|
|
129
|
+
|
|
130
|
+
Returns
|
|
131
|
+
-------
|
|
132
|
+
np.ndarray
|
|
133
|
+
Radar cube with shape (seq, range, rx, doppler, complex).
|
|
134
|
+
"""
|
|
135
|
+
try:
|
|
136
|
+
return np.load(annotation_path)
|
|
137
|
+
except (FileNotFoundError, TypeError):
|
|
138
|
+
return np.array([])
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def read_detection_text_file(
|
|
142
|
+
annotation_path: str,
|
|
143
|
+
label_offset: int = 0,
|
|
144
|
+
shape: tuple = None,
|
|
145
|
+
normalizer=None,
|
|
146
|
+
transformer=None
|
|
147
|
+
) -> dict:
|
|
148
|
+
"""
|
|
149
|
+
Reads the text file annotation to retrieve the
|
|
150
|
+
ground truth bounding boxes and the labels.
|
|
151
|
+
|
|
152
|
+
Parameters
|
|
153
|
+
----------
|
|
154
|
+
annotation_path: str
|
|
155
|
+
This is the path to the text file annotation.
|
|
156
|
+
label_offset: int
|
|
157
|
+
Used to offset the label indices by a specified amount.
|
|
158
|
+
shape: tuple
|
|
159
|
+
The (height, width) image dimensions for
|
|
160
|
+
normalizing the bounding boxes (optional).
|
|
161
|
+
normalizer: Function
|
|
162
|
+
Normalizes bounding boxes.
|
|
163
|
+
transformer: Function
|
|
164
|
+
Transforms bounding boxes to a different format.
|
|
165
|
+
|
|
166
|
+
Returns
|
|
167
|
+
-------
|
|
168
|
+
dict
|
|
169
|
+
This contains information such as boxes and labels.
|
|
170
|
+
|
|
171
|
+
.. code-block:: python
|
|
172
|
+
|
|
173
|
+
{
|
|
174
|
+
'boxes': list of bounding boxes,
|
|
175
|
+
'labels': list of labels
|
|
176
|
+
}
|
|
177
|
+
"""
|
|
178
|
+
annotations = {
|
|
179
|
+
"boxes": np.array([], dtype=np.float32),
|
|
180
|
+
"labels": np.array([]).astype(np.int32)
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
try:
|
|
184
|
+
with warnings.catch_warnings():
|
|
185
|
+
warnings.simplefilter("ignore")
|
|
186
|
+
annotation = np.genfromtxt(annotation_path)
|
|
187
|
+
except (FileNotFoundError, TypeError):
|
|
188
|
+
return annotations
|
|
189
|
+
|
|
190
|
+
if len(annotation) > 0:
|
|
191
|
+
annotation = annotation.reshape(-1, 5)
|
|
192
|
+
boxes = annotation[:, 1:5]
|
|
193
|
+
boxes = normalizer(boxes, shape) if normalizer else boxes
|
|
194
|
+
boxes = transformer(boxes) if transformer else boxes
|
|
195
|
+
annotations["boxes"] = boxes
|
|
196
|
+
else:
|
|
197
|
+
return annotations
|
|
198
|
+
|
|
199
|
+
labels = annotation[:, 0:1].flatten().astype(np.int32) + label_offset
|
|
200
|
+
annotations["labels"] = labels
|
|
201
|
+
return annotations
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def read_segmentation_text_file(
|
|
205
|
+
annotation_path: str,
|
|
206
|
+
label_offset: int = 0,
|
|
207
|
+
shape: tuple = None,
|
|
208
|
+
normalizer=None,
|
|
209
|
+
transformer=None,
|
|
210
|
+
resample: int = 1000
|
|
211
|
+
) -> dict:
|
|
212
|
+
"""
|
|
213
|
+
Reads a segmentation annotation file and converts it to bounding boxes.
|
|
214
|
+
Source: https://github.com/ultralytics/ultralytics/blob/main/ultralytics/data/utils.py#L180
|
|
215
|
+
|
|
216
|
+
Parameters
|
|
217
|
+
----------
|
|
218
|
+
annotation_path : str
|
|
219
|
+
Path to the segmentation annotation text file.
|
|
220
|
+
Assumes annotation file is in Ultralytics YOLO segment format.
|
|
221
|
+
label_offset: int
|
|
222
|
+
Used to offset the label indices by a specified amount.
|
|
223
|
+
shape: tuple
|
|
224
|
+
The (height, width) image dimensions for
|
|
225
|
+
normalizing the bounding boxes (optional).
|
|
226
|
+
normalizer: Function
|
|
227
|
+
Normalizes bounding boxes.
|
|
228
|
+
transformer: Function
|
|
229
|
+
Transforms bounding boxes to a different format.
|
|
230
|
+
resample: int
|
|
231
|
+
The number of points to resample the segments.
|
|
232
|
+
|
|
233
|
+
Returns
|
|
234
|
+
-------
|
|
235
|
+
dict
|
|
236
|
+
A dictionary with the keys "boxes", "labels", "segments"
|
|
237
|
+
storing the boxes in the shape (n, 4) -> [x, y, x, y], the labels
|
|
238
|
+
of each box, and the segment coordinates (n, 2) -> [x, y].
|
|
239
|
+
"""
|
|
240
|
+
from edgefirst.validator.datasets.utils.transformations import (segments2boxes,
|
|
241
|
+
resample_segments)
|
|
242
|
+
annotations = {
|
|
243
|
+
"boxes": np.array([], dtype=np.float32),
|
|
244
|
+
"labels": np.array([], dtype=np.int32),
|
|
245
|
+
"segments": np.array([], dtype=np.float32)
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
if annotation_path is None:
|
|
249
|
+
return annotations
|
|
250
|
+
|
|
251
|
+
segments = []
|
|
252
|
+
|
|
253
|
+
with open(annotation_path, encoding="utf-8") as f:
|
|
254
|
+
lb = [x.split() for x in f.read().strip().splitlines() if len(x)]
|
|
255
|
+
if any(len(x) > 6 for x in lb): # is segment
|
|
256
|
+
classes = np.array([x[0] for x in lb], dtype=np.float32)
|
|
257
|
+
segments = [np.array(x[1:], dtype=np.float32).reshape(-1, 2)
|
|
258
|
+
for x in lb] # (cls, xy1...)
|
|
259
|
+
lb = np.concatenate(
|
|
260
|
+
(classes.reshape(-1, 1), segments2boxes(segments)), 1) # (cls, xywh)
|
|
261
|
+
lb = np.array(lb, dtype=np.float32)
|
|
262
|
+
lb[..., 1:] = normalizer(
|
|
263
|
+
lb[..., 1:], shape) if normalizer else lb[..., 1:]
|
|
264
|
+
lb[..., 1:] = transformer(lb[..., 1:]) if transformer else lb[..., 1:]
|
|
265
|
+
|
|
266
|
+
# Segments are being resampled.
|
|
267
|
+
# https://github.com/ultralytics/ultralytics/blob/main/ultralytics/data/dataset.py#L274
|
|
268
|
+
# NOTE: do NOT resample oriented boxes.
|
|
269
|
+
if len(segments) > 0:
|
|
270
|
+
# make sure segments interpolate correctly if
|
|
271
|
+
# original length is greater than resample.
|
|
272
|
+
max_len = max(len(s) for s in segments)
|
|
273
|
+
resample = (max_len + 1) if resample < max_len else resample
|
|
274
|
+
# list[np.array(resample, 2)] * num_samples
|
|
275
|
+
segments = np.stack(resample_segments(segments, n=resample), axis=0)
|
|
276
|
+
# Denormalize segments.
|
|
277
|
+
segments[..., 0] *= shape[1]
|
|
278
|
+
segments[..., 1] *= shape[0]
|
|
279
|
+
else:
|
|
280
|
+
segments = np.zeros((0, resample, 2), dtype=np.float32)
|
|
281
|
+
|
|
282
|
+
annotations["boxes"] = lb[..., 1:]
|
|
283
|
+
annotations["labels"] = lb[..., 0] + label_offset
|
|
284
|
+
annotations["segments"] = segments
|
|
285
|
+
return annotations
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def read_detection_json_file(
|
|
289
|
+
annotation_path: str,
|
|
290
|
+
label_offset: int = 0,
|
|
291
|
+
shape: tuple = None,
|
|
292
|
+
normalizer=None,
|
|
293
|
+
transformer=None
|
|
294
|
+
) -> dict:
|
|
295
|
+
"""
|
|
296
|
+
Reads from the JSON annotation to retrieve the
|
|
297
|
+
ground truth detection bounding boxes and labels.
|
|
298
|
+
|
|
299
|
+
Parameters
|
|
300
|
+
----------
|
|
301
|
+
annotation_path: str
|
|
302
|
+
This is the path to the JSON annotation.
|
|
303
|
+
label_offset: int
|
|
304
|
+
Used to offset the label indices by a specified amount.
|
|
305
|
+
shape: tuple
|
|
306
|
+
The (height, width) image dimensions for
|
|
307
|
+
normalizing the bounding boxes (optional).
|
|
308
|
+
normalizer: Function
|
|
309
|
+
Normalizes bounding boxes.
|
|
310
|
+
transformer: Function
|
|
311
|
+
Transforms bounding boxes to a different format.
|
|
312
|
+
|
|
313
|
+
Returns
|
|
314
|
+
-------
|
|
315
|
+
dict
|
|
316
|
+
This contains information such as boxes and labels.
|
|
317
|
+
|
|
318
|
+
.. code-block:: python
|
|
319
|
+
|
|
320
|
+
{
|
|
321
|
+
'boxes': list of bounding boxes,
|
|
322
|
+
'labels': list of labels
|
|
323
|
+
}
|
|
324
|
+
"""
|
|
325
|
+
annotations = {
|
|
326
|
+
"boxes": np.array([]),
|
|
327
|
+
"labels": np.array([]).astype(np.int32)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
try:
|
|
331
|
+
with open(annotation_path) as file:
|
|
332
|
+
data: dict = json.load(file)
|
|
333
|
+
|
|
334
|
+
annotation = np.array(data.get("boxes"))
|
|
335
|
+
annotation = normalizer(
|
|
336
|
+
annotation, shape) if normalizer else annotation
|
|
337
|
+
boxes = transformer(
|
|
338
|
+
annotation[:, 0:5]) if transformer else annotation[:, 0:5]
|
|
339
|
+
labels = data.get("labels") + label_offset
|
|
340
|
+
|
|
341
|
+
# TypeError is due to the annotation path being None.
|
|
342
|
+
except (FileNotFoundError, TypeError, KeyError):
|
|
343
|
+
return annotations
|
|
344
|
+
|
|
345
|
+
annotations["boxes"] = boxes
|
|
346
|
+
annotations["labels"] = labels
|
|
347
|
+
return annotations
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def read_segmentation_json_file(
|
|
351
|
+
annotation_path: str,
|
|
352
|
+
shape: tuple,
|
|
353
|
+
label_offset: int = 0,
|
|
354
|
+
denormalizer=None,
|
|
355
|
+
) -> dict:
|
|
356
|
+
"""
|
|
357
|
+
Reads from a JSON annotation file to retrieve segmentation polygons
|
|
358
|
+
such as multiple (x,y) coordinates around an object to be segmented.
|
|
359
|
+
|
|
360
|
+
Parameters
|
|
361
|
+
----------
|
|
362
|
+
annotation_path: str
|
|
363
|
+
This is the path to the JSON annotation.
|
|
364
|
+
shape: tuple
|
|
365
|
+
This contains the image (height, width) dimensions
|
|
366
|
+
for denormalizing the polygon.
|
|
367
|
+
label_offset: int
|
|
368
|
+
The integer to offset the label indices which
|
|
369
|
+
is used for integer to string mapping for the labels.
|
|
370
|
+
denormalizer: Function
|
|
371
|
+
Denormalizes segmentation coordinates.
|
|
372
|
+
|
|
373
|
+
Returns
|
|
374
|
+
-------
|
|
375
|
+
dict
|
|
376
|
+
This contains segmentation information.
|
|
377
|
+
|
|
378
|
+
.. code-block:: python
|
|
379
|
+
|
|
380
|
+
{
|
|
381
|
+
'segments': list of polygon segments
|
|
382
|
+
[[[x,y], [x,y], ...]...],
|
|
383
|
+
'labels': list of labels
|
|
384
|
+
}
|
|
385
|
+
"""
|
|
386
|
+
annotations = {
|
|
387
|
+
"segments": np.array([]),
|
|
388
|
+
"labels": np.array([]).astype(np.int32)
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
try:
|
|
392
|
+
with open(annotation_path) as file:
|
|
393
|
+
data = json.load(file)
|
|
394
|
+
|
|
395
|
+
segments, labels = list(), list()
|
|
396
|
+
for segment in data["segment"]:
|
|
397
|
+
for polygon in segment:
|
|
398
|
+
cls = polygon["class"]
|
|
399
|
+
poly = polygon["polygon"]
|
|
400
|
+
# label_offset should be 1 if there is a background class.
|
|
401
|
+
labels.append(cls + label_offset)
|
|
402
|
+
# a list of vertices
|
|
403
|
+
x_y = []
|
|
404
|
+
for vertex in poly:
|
|
405
|
+
vertex = denormalizer(vertex, shape[0], shape[1]) \
|
|
406
|
+
if denormalizer else vertex
|
|
407
|
+
x_y.append(float(vertex[0]))
|
|
408
|
+
x_y.append(float(vertex[1]))
|
|
409
|
+
segments.append(x_y)
|
|
410
|
+
|
|
411
|
+
except UnicodeDecodeError:
|
|
412
|
+
logger(
|
|
413
|
+
f"Encountered UnicodeDecodeError for '{annotation_path}'. " +
|
|
414
|
+
"Returning an empty ground truth schema for this image. ",
|
|
415
|
+
code="WARNING"
|
|
416
|
+
)
|
|
417
|
+
return annotations
|
|
418
|
+
|
|
419
|
+
# TypeError is due to the annotation path being None.
|
|
420
|
+
except (FileNotFoundError, TypeError, KeyError):
|
|
421
|
+
return annotations
|
|
422
|
+
|
|
423
|
+
annotations["segments"] = segments
|
|
424
|
+
annotations["labels"] = labels
|
|
425
|
+
return annotations
|