supervisely 6.73.258__py3-none-any.whl → 6.73.260__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.
Potentially problematic release.
This version of supervisely might be problematic. Click here for more details.
- supervisely/annotation/tag_meta.py +63 -4
- supervisely/api/pointcloud/pointcloud_annotation_api.py +94 -1
- supervisely/api/video/video_annotation_api.py +78 -11
- supervisely/api/volume/volume_annotation_api.py +102 -2
- {supervisely-6.73.258.dist-info → supervisely-6.73.260.dist-info}/METADATA +1 -1
- {supervisely-6.73.258.dist-info → supervisely-6.73.260.dist-info}/RECORD +10 -10
- {supervisely-6.73.258.dist-info → supervisely-6.73.260.dist-info}/LICENSE +0 -0
- {supervisely-6.73.258.dist-info → supervisely-6.73.260.dist-info}/WHEEL +0 -0
- {supervisely-6.73.258.dist-info → supervisely-6.73.260.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.258.dist-info → supervisely-6.73.260.dist-info}/top_level.txt +0 -0
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
"""General information about :class:`Tag<supervisely.annotation.tag.Tag>`"""
|
|
3
3
|
|
|
4
4
|
from __future__ import annotations
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
from copy import deepcopy
|
|
7
|
-
from
|
|
8
|
-
|
|
9
|
-
from supervisely.collection.key_indexed_collection import KeyObject
|
|
7
|
+
from typing import Dict, List, Optional
|
|
8
|
+
|
|
10
9
|
from supervisely._utils import take_with_default
|
|
10
|
+
from supervisely.collection.key_indexed_collection import KeyObject
|
|
11
|
+
from supervisely.imaging.color import _validate_color, hex2rgb, random_rgb, rgb2hex
|
|
12
|
+
from supervisely.io.json import JsonSerializable
|
|
11
13
|
|
|
12
14
|
|
|
13
15
|
class TagValueType:
|
|
@@ -47,6 +49,7 @@ class TagMetaJsonFields:
|
|
|
47
49
|
""""""
|
|
48
50
|
APPLICABLE_CLASSES = "classes"
|
|
49
51
|
""""""
|
|
52
|
+
TARGET_TYPE = "target_type" # "Scope"
|
|
50
53
|
|
|
51
54
|
|
|
52
55
|
class TagApplicableTo:
|
|
@@ -62,6 +65,19 @@ class TagApplicableTo:
|
|
|
62
65
|
""""""
|
|
63
66
|
|
|
64
67
|
|
|
68
|
+
class TagTargetType:
|
|
69
|
+
"""
|
|
70
|
+
Defines Tag target type (scope) - entities, frames or both.
|
|
71
|
+
"""
|
|
72
|
+
|
|
73
|
+
ALL = "all" # both entities and frames
|
|
74
|
+
""""""
|
|
75
|
+
FRAME_BASED = "framesOnly"
|
|
76
|
+
""""""
|
|
77
|
+
GLOBAL = "entitiesOnly"
|
|
78
|
+
""""""
|
|
79
|
+
|
|
80
|
+
|
|
65
81
|
SUPPORTED_TAG_VALUE_TYPES = [
|
|
66
82
|
TagValueType.NONE,
|
|
67
83
|
TagValueType.ANY_NUMBER,
|
|
@@ -74,6 +90,12 @@ SUPPORTED_APPLICABLE_TO = [
|
|
|
74
90
|
TagApplicableTo.OBJECTS_ONLY,
|
|
75
91
|
]
|
|
76
92
|
|
|
93
|
+
SUPPORTED_TARGET_TYPES = [
|
|
94
|
+
TagTargetType.ALL,
|
|
95
|
+
TagTargetType.FRAME_BASED,
|
|
96
|
+
TagTargetType.GLOBAL,
|
|
97
|
+
]
|
|
98
|
+
|
|
77
99
|
|
|
78
100
|
class TagMeta(KeyObject, JsonSerializable):
|
|
79
101
|
"""
|
|
@@ -95,6 +117,8 @@ class TagMeta(KeyObject, JsonSerializable):
|
|
|
95
117
|
:type applicable_to: str, optional
|
|
96
118
|
:param applicable_classes: Defines applicability of Tag only to certain classes.
|
|
97
119
|
:type applicable_classes: List[str], optional
|
|
120
|
+
:param target_type: Defines Tag target type (scope) - entities, frames or both.
|
|
121
|
+
:type target_type: str, optional
|
|
98
122
|
:raises: :class:`ValueError`, if color is not list, or doesn't have exactly 3 values
|
|
99
123
|
:Usage example:
|
|
100
124
|
|
|
@@ -128,6 +152,7 @@ class TagMeta(KeyObject, JsonSerializable):
|
|
|
128
152
|
hotkey: Optional[str] = None,
|
|
129
153
|
applicable_to: Optional[str] = None,
|
|
130
154
|
applicable_classes: Optional[List[str]] = None,
|
|
155
|
+
target_type: Optional[str] = None,
|
|
131
156
|
):
|
|
132
157
|
if value_type not in SUPPORTED_TAG_VALUE_TYPES:
|
|
133
158
|
raise ValueError(
|
|
@@ -144,12 +169,20 @@ class TagMeta(KeyObject, JsonSerializable):
|
|
|
144
169
|
self._hotkey = take_with_default(hotkey, "")
|
|
145
170
|
self._applicable_to = take_with_default(applicable_to, TagApplicableTo.ALL)
|
|
146
171
|
self._applicable_classes = take_with_default(applicable_classes, [])
|
|
172
|
+
self._target_type = take_with_default(target_type, TagTargetType.ALL)
|
|
147
173
|
if self._applicable_to not in SUPPORTED_APPLICABLE_TO:
|
|
148
174
|
raise ValueError(
|
|
149
175
|
"applicable_to = {!r} is unknown, should be one of {}".format(
|
|
150
176
|
self._applicable_to, SUPPORTED_APPLICABLE_TO
|
|
151
177
|
)
|
|
152
178
|
)
|
|
179
|
+
|
|
180
|
+
if self._target_type not in SUPPORTED_TARGET_TYPES:
|
|
181
|
+
raise ValueError(
|
|
182
|
+
"target_type = {!r} is unknown, should be one of {}".format(
|
|
183
|
+
self._target_type, SUPPORTED_TARGET_TYPES
|
|
184
|
+
)
|
|
185
|
+
)
|
|
153
186
|
|
|
154
187
|
if self._value_type == TagValueType.ONEOF_STRING:
|
|
155
188
|
if self._possible_values is None:
|
|
@@ -329,6 +362,24 @@ class TagMeta(KeyObject, JsonSerializable):
|
|
|
329
362
|
# Output: ['car', 'bicycle']
|
|
330
363
|
"""
|
|
331
364
|
return self._applicable_classes
|
|
365
|
+
|
|
366
|
+
@property
|
|
367
|
+
def target_type(self) -> str:
|
|
368
|
+
"""
|
|
369
|
+
Tag target type (scope) - entities, frames or both.
|
|
370
|
+
|
|
371
|
+
:return: Target type
|
|
372
|
+
:rtype: :class:`str`
|
|
373
|
+
:Usage example:
|
|
374
|
+
|
|
375
|
+
.. code-block:: python
|
|
376
|
+
|
|
377
|
+
meta_dog = sly.TagMeta('dog', sly.TagValueType.NONE, target_type=TagTargetType.FRAME_BASED)
|
|
378
|
+
|
|
379
|
+
print(meta_dog.target_type)
|
|
380
|
+
# Output: 'framesOnly'
|
|
381
|
+
"""
|
|
382
|
+
return self._target_type
|
|
332
383
|
|
|
333
384
|
def to_json(self) -> Dict:
|
|
334
385
|
"""
|
|
@@ -390,6 +441,8 @@ class TagMeta(KeyObject, JsonSerializable):
|
|
|
390
441
|
jdict[TagMetaJsonFields.APPLICABLE_TYPE] = self.applicable_to
|
|
391
442
|
if self._applicable_classes is not None:
|
|
392
443
|
jdict[TagMetaJsonFields.APPLICABLE_CLASSES] = self.applicable_classes
|
|
444
|
+
if self._target_type is not None:
|
|
445
|
+
jdict[TagMetaJsonFields.TARGET_TYPE] = self.target_type
|
|
393
446
|
|
|
394
447
|
return jdict
|
|
395
448
|
|
|
@@ -445,6 +498,7 @@ class TagMeta(KeyObject, JsonSerializable):
|
|
|
445
498
|
hotkey = data.get(TagMetaJsonFields.HOTKEY, "")
|
|
446
499
|
applicable_to = data.get(TagMetaJsonFields.APPLICABLE_TYPE, TagApplicableTo.ALL)
|
|
447
500
|
applicable_classes = data.get(TagMetaJsonFields.APPLICABLE_CLASSES, [])
|
|
501
|
+
target_type = data.get(TagMetaJsonFields.TARGET_TYPE, TagTargetType.ALL)
|
|
448
502
|
|
|
449
503
|
return cls(
|
|
450
504
|
name=name,
|
|
@@ -455,6 +509,7 @@ class TagMeta(KeyObject, JsonSerializable):
|
|
|
455
509
|
hotkey=hotkey,
|
|
456
510
|
applicable_to=applicable_to,
|
|
457
511
|
applicable_classes=applicable_classes,
|
|
512
|
+
target_type=target_type,
|
|
458
513
|
)
|
|
459
514
|
else:
|
|
460
515
|
raise ValueError("Tags must be dict or str types.")
|
|
@@ -632,6 +687,7 @@ class TagMeta(KeyObject, JsonSerializable):
|
|
|
632
687
|
hotkey: Optional[str] = None,
|
|
633
688
|
applicable_to: Optional[str] = None,
|
|
634
689
|
applicable_classes: Optional[List[str]] = None,
|
|
690
|
+
target_type: Optional[str] = None,
|
|
635
691
|
) -> TagMeta:
|
|
636
692
|
"""
|
|
637
693
|
Clone makes a copy of TagMeta with new fields, if fields are given, otherwise it will use original TagMeta fields.
|
|
@@ -683,6 +739,7 @@ class TagMeta(KeyObject, JsonSerializable):
|
|
|
683
739
|
hotkey=take_with_default(hotkey, self.hotkey),
|
|
684
740
|
applicable_to=take_with_default(applicable_to, self.applicable_to),
|
|
685
741
|
applicable_classes=take_with_default(applicable_classes, self.applicable_classes),
|
|
742
|
+
target_type=take_with_default(target_type, self.target_type),
|
|
686
743
|
)
|
|
687
744
|
|
|
688
745
|
def __str__(self):
|
|
@@ -713,6 +770,7 @@ class TagMeta(KeyObject, JsonSerializable):
|
|
|
713
770
|
"Hotkey",
|
|
714
771
|
"Applicable to",
|
|
715
772
|
"Applicable classes",
|
|
773
|
+
"Target type",
|
|
716
774
|
]
|
|
717
775
|
|
|
718
776
|
def get_row_ptable(self):
|
|
@@ -724,6 +782,7 @@ class TagMeta(KeyObject, JsonSerializable):
|
|
|
724
782
|
self.hotkey,
|
|
725
783
|
self.applicable_to,
|
|
726
784
|
self.applicable_classes,
|
|
785
|
+
self.target_type,
|
|
727
786
|
]
|
|
728
787
|
|
|
729
788
|
def _set_id(self, id: int):
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
# coding: utf-8
|
|
2
2
|
|
|
3
3
|
# docs
|
|
4
|
-
|
|
4
|
+
import asyncio
|
|
5
|
+
from typing import Callable, Dict, List, Optional, Union
|
|
5
6
|
|
|
7
|
+
from tqdm import tqdm
|
|
8
|
+
|
|
9
|
+
from supervisely._utils import batched
|
|
6
10
|
from supervisely.api.entity_annotation.entity_annotation_api import EntityAnnotationAPI
|
|
7
11
|
from supervisely.api.module_api import ApiField
|
|
8
12
|
from supervisely.pointcloud_annotation.pointcloud_annotation import PointcloudAnnotation
|
|
@@ -174,3 +178,92 @@ class PointcloudAnnotationAPI(EntityAnnotationAPI):
|
|
|
174
178
|
ann.figures,
|
|
175
179
|
key_id_map,
|
|
176
180
|
)
|
|
181
|
+
|
|
182
|
+
async def download_async(
|
|
183
|
+
self,
|
|
184
|
+
pointcloud_id: int,
|
|
185
|
+
semaphore: Optional[asyncio.Semaphore] = None,
|
|
186
|
+
progress_cb: Optional[Union[tqdm, Callable]] = None,
|
|
187
|
+
) -> Dict:
|
|
188
|
+
"""
|
|
189
|
+
Download information about PointcloudAnnotation by Point Cloud ID from API asynchronously.
|
|
190
|
+
|
|
191
|
+
:param pointcloud_id: Point Cloud ID in Supervisely.
|
|
192
|
+
:type pointcloud_id: int
|
|
193
|
+
:param semaphore: Semaphore to limit the number of parallel downloads.
|
|
194
|
+
:type semaphore: asyncio.Semaphore, optional
|
|
195
|
+
:param progress_cb: Progress callback to track download progress.
|
|
196
|
+
:type progress_cb: Union[tqdm, Callable], optional
|
|
197
|
+
:return: Information about PointcloudAnnotation in json format
|
|
198
|
+
:rtype: :class:`dict`
|
|
199
|
+
|
|
200
|
+
:Usage example:
|
|
201
|
+
|
|
202
|
+
.. code-block:: python
|
|
203
|
+
|
|
204
|
+
import supervisely as sly
|
|
205
|
+
|
|
206
|
+
os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
|
|
207
|
+
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
|
|
208
|
+
api = sly.Api.from_env()
|
|
209
|
+
|
|
210
|
+
pointcloud_id = 198702499
|
|
211
|
+
loop = sly.utils.get_or_create_event_loop()
|
|
212
|
+
ann_info = loop.run_until_complete(api.pointcloud.annotation.download_async(pointcloud_id))
|
|
213
|
+
"""
|
|
214
|
+
return await self.download_bulk_async(
|
|
215
|
+
pointcloud_ids=[pointcloud_id],
|
|
216
|
+
semaphore=semaphore,
|
|
217
|
+
progress_cb=progress_cb,
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
async def download_bulk_async(
|
|
221
|
+
self,
|
|
222
|
+
pointcloud_ids: List[int],
|
|
223
|
+
semaphore: Optional[asyncio.Semaphore] = None,
|
|
224
|
+
progress_cb: Optional[Union[tqdm, Callable]] = None,
|
|
225
|
+
) -> List[Dict]:
|
|
226
|
+
"""
|
|
227
|
+
Download information about PointcloudAnnotation in bulk by Point Cloud IDs from API asynchronously.
|
|
228
|
+
|
|
229
|
+
:param pointcloud_ids: Point Cloud IDs in Supervisely.
|
|
230
|
+
:type pointcloud_ids: List[int]
|
|
231
|
+
:param semaphore: Semaphore to limit the number of parallel downloads.
|
|
232
|
+
:type semaphore: asyncio.Semaphore, optional
|
|
233
|
+
:param progress_cb: Progress callback to track download progress.
|
|
234
|
+
:type progress_cb: Union[tqdm, Callable], optional
|
|
235
|
+
:return: Information about PointcloudAnnotations in json format
|
|
236
|
+
:rtype: :class:`list`
|
|
237
|
+
|
|
238
|
+
:Usage example:
|
|
239
|
+
|
|
240
|
+
.. code-block:: python
|
|
241
|
+
|
|
242
|
+
import supervisely as sly
|
|
243
|
+
|
|
244
|
+
os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
|
|
245
|
+
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
|
|
246
|
+
api = sly.Api.from_env()
|
|
247
|
+
|
|
248
|
+
pointcloud_ids = [198702499, 198702500, 198702501]
|
|
249
|
+
loop = sly.utils.get_or_create_event_loop()
|
|
250
|
+
ann_infos = loop.run_until_complete(api.pointcloud.annotation.download_bulk_async(pointcloud_ids))
|
|
251
|
+
"""
|
|
252
|
+
if semaphore is None:
|
|
253
|
+
semaphore = self._api.get_default_semaphore()
|
|
254
|
+
|
|
255
|
+
async def fetch_with_semaphore(batch):
|
|
256
|
+
async with semaphore:
|
|
257
|
+
json_data = {self._entity_ids_str: batch}
|
|
258
|
+
response = await self._api.post_async(
|
|
259
|
+
self._method_download_bulk,
|
|
260
|
+
json=json_data,
|
|
261
|
+
)
|
|
262
|
+
if progress_cb is not None:
|
|
263
|
+
progress_cb(len(batch))
|
|
264
|
+
return response.json()
|
|
265
|
+
|
|
266
|
+
tasks = [fetch_with_semaphore(batch) for batch in batched(pointcloud_ids)]
|
|
267
|
+
responses = await asyncio.gather(*tasks)
|
|
268
|
+
json_response = [item for response in responses for item in response]
|
|
269
|
+
return json_response
|
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
from __future__ import annotations
|
|
3
3
|
|
|
4
4
|
import asyncio
|
|
5
|
-
import json
|
|
6
5
|
from typing import Callable, Dict, List, Optional, Union
|
|
7
6
|
|
|
8
7
|
from tqdm import tqdm
|
|
@@ -12,7 +11,6 @@ from supervisely.api.entity_annotation.entity_annotation_api import EntityAnnota
|
|
|
12
11
|
from supervisely.api.module_api import ApiField
|
|
13
12
|
from supervisely.io.json import load_json_file
|
|
14
13
|
from supervisely.project.project_meta import ProjectMeta
|
|
15
|
-
from supervisely.task.progress import Progress
|
|
16
14
|
from supervisely.video_annotation.key_id_map import KeyIdMap
|
|
17
15
|
from supervisely.video_annotation.video_annotation import VideoAnnotation
|
|
18
16
|
|
|
@@ -254,18 +252,28 @@ class VideoAnnotationAPI(EntityAnnotationAPI):
|
|
|
254
252
|
video_id: int,
|
|
255
253
|
video_info=None,
|
|
256
254
|
semaphore: Optional[asyncio.Semaphore] = None,
|
|
255
|
+
force_metadata_for_links: bool = True,
|
|
256
|
+
integer_coords: bool = True,
|
|
257
|
+
progress_cb: Optional[Union[tqdm, Callable]] = None,
|
|
257
258
|
) -> Dict:
|
|
258
259
|
"""
|
|
259
260
|
Download information about VideoAnnotation by video ID from API asynchronously.
|
|
260
261
|
|
|
261
262
|
:param video_id: Video ID in Supervisely.
|
|
262
263
|
:type video_id: int
|
|
263
|
-
:param video_info:
|
|
264
|
+
:param video_info: Does not affect the result, but is left for compatibility with the method signature.
|
|
264
265
|
:type video_info: VideoInfo, optional
|
|
265
266
|
:param semaphore: Semaphore to limit the number of parallel downloads.
|
|
266
267
|
:type semaphore: asyncio.Semaphore, optional
|
|
268
|
+
:param force_metadata_for_links: If True, updates meta for videos with links.
|
|
269
|
+
:type force_metadata_for_links: bool, optional
|
|
270
|
+
:param integer_coords: If True, returns coordinates as integers for objects. If False, returns as floats.
|
|
271
|
+
:type integer_coords: bool, optional
|
|
272
|
+
:param progress_cb: Progress callback to track download progress.
|
|
273
|
+
:type progress_cb: Union[tqdm, Callable], optional
|
|
267
274
|
:return: Information about VideoAnnotation in json format
|
|
268
275
|
:rtype: :class:`dict`
|
|
276
|
+
|
|
269
277
|
:Usage example:
|
|
270
278
|
|
|
271
279
|
.. code-block:: python
|
|
@@ -280,15 +288,74 @@ class VideoAnnotationAPI(EntityAnnotationAPI):
|
|
|
280
288
|
loop = sly.utils.get_or_create_event_loop()
|
|
281
289
|
ann_info = loop.run_until_complete(api.video.annotation.download_async(video_id))
|
|
282
290
|
"""
|
|
283
|
-
|
|
284
|
-
|
|
291
|
+
return await self.download_bulk_async(
|
|
292
|
+
video_ids=[video_id],
|
|
293
|
+
semaphore=semaphore,
|
|
294
|
+
force_metadata_for_links=force_metadata_for_links,
|
|
295
|
+
integer_coords=integer_coords,
|
|
296
|
+
progress_cb=progress_cb,
|
|
297
|
+
)
|
|
285
298
|
|
|
299
|
+
async def download_bulk_async(
|
|
300
|
+
self,
|
|
301
|
+
video_ids: List[int],
|
|
302
|
+
semaphore: Optional[asyncio.Semaphore] = None,
|
|
303
|
+
force_metadata_for_links: bool = True,
|
|
304
|
+
integer_coords: bool = True,
|
|
305
|
+
batch_size: int = 10,
|
|
306
|
+
progress_cb: Optional[Union[tqdm, Callable]] = None,
|
|
307
|
+
) -> List[Dict]:
|
|
308
|
+
"""
|
|
309
|
+
Download information about VideoAnnotation in bulk by video IDs from API asynchronously.
|
|
310
|
+
|
|
311
|
+
:param video_ids: List of Video IDs in Supervisely. All videos must be from the same dataset.
|
|
312
|
+
:type video_ids: int
|
|
313
|
+
:param semaphore: Semaphore to limit the number of parallel downloads.
|
|
314
|
+
:type semaphore: asyncio.Semaphore, optional
|
|
315
|
+
:param force_metadata_for_links: If True, updates meta for videos with links.
|
|
316
|
+
:type force_metadata_for_links: bool, optional
|
|
317
|
+
:param integer_coords: If True, returns coordinates as integers for objects. If False, returns as floats.
|
|
318
|
+
:type integer_coords: bool, optional
|
|
319
|
+
:param batch_size: Batch size for parallel downloads. Default is 10 as an optimal value.
|
|
320
|
+
:type batch_size: int, optional
|
|
321
|
+
:param progress_cb: Function for tracking download progress.
|
|
322
|
+
:type progress_cb: tqdm or callable, optional
|
|
323
|
+
:return: Information about VideoAnnotations in json format
|
|
324
|
+
:rtype: :class:`list`
|
|
325
|
+
|
|
326
|
+
:Usage example:
|
|
327
|
+
|
|
328
|
+
.. code-block:: python
|
|
329
|
+
|
|
330
|
+
import supervisely as sly
|
|
331
|
+
|
|
332
|
+
os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
|
|
333
|
+
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
|
|
334
|
+
api = sly.Api.from_env()
|
|
335
|
+
|
|
336
|
+
video_ids = [198702499, 198702500, 198702501]
|
|
337
|
+
loop = sly.utils.get_or_create_event_loop()
|
|
338
|
+
ann_infos = loop.run_until_complete(api.video.annotation.download_bulk_async(video_ids))
|
|
339
|
+
"""
|
|
286
340
|
if semaphore is None:
|
|
287
341
|
semaphore = self._api.get_default_semaphore()
|
|
288
342
|
|
|
289
|
-
async
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
343
|
+
async def fetch_with_semaphore(batch):
|
|
344
|
+
async with semaphore:
|
|
345
|
+
json_data = {
|
|
346
|
+
self._entity_ids_str: batch,
|
|
347
|
+
ApiField.FORCE_METADATA_FOR_LINKS: force_metadata_for_links,
|
|
348
|
+
ApiField.INTEGER_COORDS: integer_coords,
|
|
349
|
+
}
|
|
350
|
+
response = await self._api.post_async(
|
|
351
|
+
self._method_download_bulk,
|
|
352
|
+
json=json_data,
|
|
353
|
+
)
|
|
354
|
+
if progress_cb is not None:
|
|
355
|
+
progress_cb(len(batch))
|
|
356
|
+
return response.json()
|
|
357
|
+
|
|
358
|
+
tasks = [fetch_with_semaphore(batch) for batch in batched(video_ids, batch_size=batch_size)]
|
|
359
|
+
responses = await asyncio.gather(*tasks)
|
|
360
|
+
json_response = [item for response in responses for item in response]
|
|
361
|
+
return json_response
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
# coding: utf-8
|
|
2
2
|
|
|
3
|
+
import asyncio
|
|
3
4
|
import os
|
|
4
5
|
import re
|
|
5
|
-
from typing import Callable, List, Literal, Optional, Tuple, Union
|
|
6
|
+
from typing import Callable, Dict, List, Literal, Optional, Tuple, Union
|
|
6
7
|
|
|
7
8
|
import numpy as np
|
|
8
9
|
from tqdm import tqdm
|
|
9
10
|
|
|
11
|
+
from supervisely._utils import batched
|
|
10
12
|
from supervisely.annotation.obj_class import ObjClass
|
|
11
13
|
from supervisely.api.entity_annotation.entity_annotation_api import EntityAnnotationAPI
|
|
12
14
|
from supervisely.api.module_api import ApiField
|
|
13
|
-
from supervisely.collection.key_indexed_collection import DuplicateKeyError
|
|
14
15
|
from supervisely.geometry.any_geometry import AnyGeometry
|
|
15
16
|
from supervisely.geometry.mask_3d import Mask3D
|
|
16
17
|
from supervisely.io.fs import (
|
|
@@ -456,3 +457,102 @@ class VolumeAnnotationAPI(EntityAnnotationAPI):
|
|
|
456
457
|
nrrd_paths.remove(nrrd_path)
|
|
457
458
|
keep_nrrd_paths.remove(nrrd_path)
|
|
458
459
|
return stl_paths, nrrd_paths, keep_nrrd_paths
|
|
460
|
+
|
|
461
|
+
async def download_async(
|
|
462
|
+
self,
|
|
463
|
+
volume_id: int,
|
|
464
|
+
semaphore: Optional[asyncio.Semaphore] = None,
|
|
465
|
+
integer_coords: bool = True,
|
|
466
|
+
progress_cb: Optional[Union[tqdm, Callable]] = None,
|
|
467
|
+
) -> Dict:
|
|
468
|
+
"""
|
|
469
|
+
Download information about VolumeAnnotation by volume ID from API asynchronously.
|
|
470
|
+
|
|
471
|
+
:param volume_id: Volume ID in Supervisely.
|
|
472
|
+
:type volume_id: int
|
|
473
|
+
:param semaphore: Semaphore to limit the number of parallel downloads.
|
|
474
|
+
:type semaphore: asyncio.Semaphore, optional
|
|
475
|
+
:param integer_coords: If True, returns coordinates as integers for objects. If False, returns as floats.
|
|
476
|
+
:type integer_coords: bool, optional
|
|
477
|
+
:param progress_cb: Function for tracking download progress.
|
|
478
|
+
:type progress_cb: tqdm or callable, optional
|
|
479
|
+
:return: Information about VolumeAnnotation in json format
|
|
480
|
+
:rtype: :class:`dict`
|
|
481
|
+
|
|
482
|
+
:Usage example:
|
|
483
|
+
|
|
484
|
+
.. code-block:: python
|
|
485
|
+
|
|
486
|
+
import supervisely as sly
|
|
487
|
+
|
|
488
|
+
os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
|
|
489
|
+
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
|
|
490
|
+
api = sly.Api.from_env()
|
|
491
|
+
|
|
492
|
+
volume_id = 198702499
|
|
493
|
+
loop = sly.utils.get_or_create_event_loop()
|
|
494
|
+
ann_info = loop.run_until_complete(api.volume.annotation.download_async(volume_id))
|
|
495
|
+
"""
|
|
496
|
+
return await self.download_bulk_async(
|
|
497
|
+
volume_ids=[volume_id],
|
|
498
|
+
semaphore=semaphore,
|
|
499
|
+
integer_coords=integer_coords,
|
|
500
|
+
progress_cb=progress_cb,
|
|
501
|
+
)
|
|
502
|
+
|
|
503
|
+
async def download_bulk_async(
|
|
504
|
+
self,
|
|
505
|
+
volume_ids: List[int],
|
|
506
|
+
semaphore: Optional[asyncio.Semaphore] = None,
|
|
507
|
+
integer_coords: bool = True,
|
|
508
|
+
progress_cb: Optional[Union[tqdm, Callable]] = None,
|
|
509
|
+
) -> List[Dict]:
|
|
510
|
+
"""
|
|
511
|
+
Download information about VolumeAnnotation in bulk by volume IDs from API asynchronously.
|
|
512
|
+
|
|
513
|
+
:param volume_ids: List of Volume IDs in Supervisely. All volumes must be from the same dataset.
|
|
514
|
+
:type volume_ids: int
|
|
515
|
+
:param semaphore: Semaphore to limit the number of parallel downloads.
|
|
516
|
+
:type semaphore: asyncio.Semaphore, optional
|
|
517
|
+
:param integer_coords: If True, returns coordinates as integers for objects. If False, returns as floats.
|
|
518
|
+
:type integer_coords: bool, optional
|
|
519
|
+
:param progress_cb: Function for tracking download progress.
|
|
520
|
+
:type progress_cb: tqdm or callable, optional
|
|
521
|
+
:return: Information about VolumeAnnotations in json format
|
|
522
|
+
:rtype: :class:`list`
|
|
523
|
+
|
|
524
|
+
:Usage example:
|
|
525
|
+
|
|
526
|
+
.. code-block:: python
|
|
527
|
+
|
|
528
|
+
import supervisely as sly
|
|
529
|
+
|
|
530
|
+
os.environ['SERVER_ADDRESS'] = 'https://app.supervisely.com'
|
|
531
|
+
os.environ['API_TOKEN'] = 'Your Supervisely API Token'
|
|
532
|
+
api = sly.Api.from_env()
|
|
533
|
+
|
|
534
|
+
volume_ids = [198702499, 198702500, 198702501]
|
|
535
|
+
loop = sly.utils.get_or_create_event_loop()
|
|
536
|
+
ann_infos = loop.run_until_complete(api.volume.annotation.download_bulk_async(volume_ids))
|
|
537
|
+
"""
|
|
538
|
+
if semaphore is None:
|
|
539
|
+
semaphore = self._api.get_default_semaphore()
|
|
540
|
+
|
|
541
|
+
async def fetch_with_semaphore(batch):
|
|
542
|
+
async with semaphore:
|
|
543
|
+
json_data = {
|
|
544
|
+
self._entity_ids_str: batch,
|
|
545
|
+
ApiField.INTEGER_COORDS: integer_coords,
|
|
546
|
+
}
|
|
547
|
+
response = await self._api.post_async(
|
|
548
|
+
self._method_download_bulk,
|
|
549
|
+
json=json_data,
|
|
550
|
+
)
|
|
551
|
+
if progress_cb is not None:
|
|
552
|
+
progress_cb(len(batch))
|
|
553
|
+
return response.json()
|
|
554
|
+
|
|
555
|
+
tasks = [fetch_with_semaphore(batch) for batch in batched(volume_ids)]
|
|
556
|
+
responses = await asyncio.gather(*tasks)
|
|
557
|
+
json_response = [item for response in responses for item in response]
|
|
558
|
+
return json_response
|
|
@@ -15,7 +15,7 @@ supervisely/annotation/obj_class_mapper.py,sha256=aIJDoRULqcAOD2a1CQPk2OOF8k3VPP
|
|
|
15
15
|
supervisely/annotation/renamer.py,sha256=rVvNLtpfd1kKUVPgm8VlLmYSDByWjriJ92FobC4buqY,1944
|
|
16
16
|
supervisely/annotation/tag.py,sha256=m_sPgrr_ZW8HuiK7Fr2-WnHwKwez1WZtGrcdZN2DZuQ,17598
|
|
17
17
|
supervisely/annotation/tag_collection.py,sha256=MVPTzer9rLpD4O0g2XhYFUheK7-ILgwAXDJd1em3kZ8,10015
|
|
18
|
-
supervisely/annotation/tag_meta.py,sha256=
|
|
18
|
+
supervisely/annotation/tag_meta.py,sha256=2UkgRSMuQ7LXH48Ok2bJNdlK-miX54wXYAoB_as9_a0,27543
|
|
19
19
|
supervisely/annotation/tag_meta_collection.py,sha256=JY2wAo4dF47UylYeglkJtRtpVOArGjf3dXeEYIHFWP0,14491
|
|
20
20
|
supervisely/annotation/tag_meta_mapper.py,sha256=RWeTrxJ64syodyhXIRSH007bX6Hr3B45tG14YTcpwSU,1639
|
|
21
21
|
supervisely/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -53,7 +53,7 @@ supervisely/api/entity_annotation/figure_api.py,sha256=_JS1x0jn5neoCnZCBKHUBwspo
|
|
|
53
53
|
supervisely/api/entity_annotation/object_api.py,sha256=gbcNvN_KY6G80Me8fHKQgryc2Co7VU_kfFd1GYILZ4E,8875
|
|
54
54
|
supervisely/api/entity_annotation/tag_api.py,sha256=M-28m9h8R4k9Eqo6P1S0UH8_D5kqCwAvQLYY6_Yz4oM,11161
|
|
55
55
|
supervisely/api/pointcloud/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
56
|
-
supervisely/api/pointcloud/pointcloud_annotation_api.py,sha256=
|
|
56
|
+
supervisely/api/pointcloud/pointcloud_annotation_api.py,sha256=x2Bw_1ZaGZffc89k670LWQiwMhlb4CbB-6suDpHJRgg,11256
|
|
57
57
|
supervisely/api/pointcloud/pointcloud_api.py,sha256=pn72znCr5hkAfgniXxfD6Vi8-HqRb1Nrf6l23-HQ7Bc,53277
|
|
58
58
|
supervisely/api/pointcloud/pointcloud_episode_annotation_api.py,sha256=YGpU7g05XNV9o5daH5mFcUMmPPfgd085yIMNzXOVJqc,7009
|
|
59
59
|
supervisely/api/pointcloud/pointcloud_episode_api.py,sha256=K_oPJeibj5oRYooeEWuSe6VxlxCYK3D8yLunm7vDeM0,7919
|
|
@@ -63,14 +63,14 @@ supervisely/api/pointcloud/pointcloud_figure_api.py,sha256=r1sk3g9IgYVHuNhxyZT1T
|
|
|
63
63
|
supervisely/api/pointcloud/pointcloud_object_api.py,sha256=bO1USWb9HAywG_CW4CDu1HLu6l58OqQFuD3ikS9F3bM,5130
|
|
64
64
|
supervisely/api/pointcloud/pointcloud_tag_api.py,sha256=iShtr052nOElxsyMyZEUT2vypEm6kP00gnP13ABX24A,4691
|
|
65
65
|
supervisely/api/video/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
66
|
-
supervisely/api/video/video_annotation_api.py,sha256=
|
|
66
|
+
supervisely/api/video/video_annotation_api.py,sha256=nvbn_ofcqFCZ2qKgu0O5y5zOHxFc4tsY-o93sUgqlWk,14134
|
|
67
67
|
supervisely/api/video/video_api.py,sha256=KO_Nfqa4xDWrc7FqOR14PciC0TX8PF0g0peqgPnctEE,94677
|
|
68
68
|
supervisely/api/video/video_figure_api.py,sha256=quksohjhgrK2l2-PtbbNE99fOW6uWXX59-_4xfc-I-k,6244
|
|
69
69
|
supervisely/api/video/video_frame_api.py,sha256=4GwSI4xdCNYEUvTqzKc-Ewd44fw5zqkFoD24jrrN_aY,10214
|
|
70
70
|
supervisely/api/video/video_object_api.py,sha256=IC0NP8EoIT_d3xxDRgz2cA3ixSiuJ5ymy64eS-RfmDM,2227
|
|
71
71
|
supervisely/api/video/video_tag_api.py,sha256=oJgdJt_0w-5UfXaxZ7jdxK0PetZjax1vOfjm0IMYwe8,12266
|
|
72
72
|
supervisely/api/volume/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
73
|
-
supervisely/api/volume/volume_annotation_api.py,sha256=
|
|
73
|
+
supervisely/api/volume/volume_annotation_api.py,sha256=q1nzSeMBndxCTPf-3apliXvqcOaOjYWohSO5CZDHITQ,22243
|
|
74
74
|
supervisely/api/volume/volume_api.py,sha256=-n3r5qj4I4EtoERKTHFT8PpsKFJ141SvQfamIcHqWK4,55387
|
|
75
75
|
supervisely/api/volume/volume_figure_api.py,sha256=WwmcMw7o3Nvyv52tzmz64yF-WJI0qzAU-zL2JlD7_w0,26039
|
|
76
76
|
supervisely/api/volume/volume_object_api.py,sha256=F7pLV2MTlBlyN6fEKdxBSUatIMGWSuu8bWj3Hvcageo,2139
|
|
@@ -1057,9 +1057,9 @@ supervisely/worker_proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
1057
1057
|
supervisely/worker_proto/worker_api_pb2.py,sha256=VQfi5JRBHs2pFCK1snec3JECgGnua3Xjqw_-b3aFxuM,59142
|
|
1058
1058
|
supervisely/worker_proto/worker_api_pb2_grpc.py,sha256=3BwQXOaP9qpdi0Dt9EKG--Lm8KGN0C5AgmUfRv77_Jk,28940
|
|
1059
1059
|
supervisely_lib/__init__.py,sha256=7-3QnN8Zf0wj8NCr2oJmqoQWMKKPKTECvjH9pd2S5vY,159
|
|
1060
|
-
supervisely-6.73.
|
|
1061
|
-
supervisely-6.73.
|
|
1062
|
-
supervisely-6.73.
|
|
1063
|
-
supervisely-6.73.
|
|
1064
|
-
supervisely-6.73.
|
|
1065
|
-
supervisely-6.73.
|
|
1060
|
+
supervisely-6.73.260.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
1061
|
+
supervisely-6.73.260.dist-info/METADATA,sha256=CPwcqKvIAjMyeGM6DRLQKHF3owWEcixltIqVe4T0x-E,33573
|
|
1062
|
+
supervisely-6.73.260.dist-info/WHEEL,sha256=P9jw-gEje8ByB7_hXoICnHtVCrEwMQh-630tKvQWehc,91
|
|
1063
|
+
supervisely-6.73.260.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
|
|
1064
|
+
supervisely-6.73.260.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
|
|
1065
|
+
supervisely-6.73.260.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|