supervisely 6.73.360__py3-none-any.whl → 6.73.362__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.
- supervisely/nn/inference/inference.py +1 -2
- supervisely/project/download.py +24 -6
- supervisely/project/video_project.py +35 -6
- supervisely/volume/volume.py +105 -9
- supervisely/volume_annotation/volume_annotation.py +39 -2
- supervisely/volume_annotation/volume_figure.py +17 -15
- {supervisely-6.73.360.dist-info → supervisely-6.73.362.dist-info}/METADATA +1 -1
- {supervisely-6.73.360.dist-info → supervisely-6.73.362.dist-info}/RECORD +12 -12
- {supervisely-6.73.360.dist-info → supervisely-6.73.362.dist-info}/LICENSE +0 -0
- {supervisely-6.73.360.dist-info → supervisely-6.73.362.dist-info}/WHEEL +0 -0
- {supervisely-6.73.360.dist-info → supervisely-6.73.362.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.360.dist-info → supervisely-6.73.362.dist-info}/top_level.txt +0 -0
|
@@ -1519,7 +1519,7 @@ class Inference:
|
|
|
1519
1519
|
if frames_count is not None:
|
|
1520
1520
|
n_frames = frames_count
|
|
1521
1521
|
elif end_frame_index is not None:
|
|
1522
|
-
n_frames = end_frame_index - start_frame_index
|
|
1522
|
+
n_frames = end_frame_index - start_frame_index + 1
|
|
1523
1523
|
elif duration is not None:
|
|
1524
1524
|
fps = frames_reader.fps()
|
|
1525
1525
|
n_frames = int(duration * fps)
|
|
@@ -1729,7 +1729,6 @@ class Inference:
|
|
|
1729
1729
|
inference_settings = self._get_inference_settings(state)
|
|
1730
1730
|
logger.debug(f"Inference settings:", extra=inference_settings)
|
|
1731
1731
|
batch_size = self._get_batch_size_from_state(state)
|
|
1732
|
-
video_id = state["videoId"]
|
|
1733
1732
|
video_id = get_value_for_keys(state, ["videoId", "video_id"], ignore_none=True)
|
|
1734
1733
|
if video_id is None:
|
|
1735
1734
|
raise ValueError("Video id is not provided")
|
supervisely/project/download.py
CHANGED
|
@@ -409,12 +409,22 @@ def _project_meta_changed(meta1: ProjectMeta, meta2: ProjectMeta) -> bool:
|
|
|
409
409
|
return False
|
|
410
410
|
|
|
411
411
|
|
|
412
|
+
def _get_ds_full_name(
|
|
413
|
+
dataset_info: DatasetInfo, all_ds_infos: List[DatasetInfo], suffix: str = ""
|
|
414
|
+
) -> str:
|
|
415
|
+
if dataset_info.parent_id is None:
|
|
416
|
+
return dataset_info.name + suffix
|
|
417
|
+
parent = next((ds_info for ds_info in all_ds_infos if ds_info.id == dataset_info.parent_id))
|
|
418
|
+
return _get_ds_full_name(parent, all_ds_infos, "/" + dataset_info.name)
|
|
419
|
+
|
|
420
|
+
|
|
412
421
|
def _validate_dataset(
|
|
413
422
|
api: Api,
|
|
414
423
|
project_id: int,
|
|
415
424
|
project_type: str,
|
|
416
425
|
project_meta: ProjectMeta,
|
|
417
426
|
dataset_info: DatasetInfo,
|
|
427
|
+
all_ds_infos: List[DatasetInfo] = None,
|
|
418
428
|
):
|
|
419
429
|
try:
|
|
420
430
|
project_class = get_project_class(project_type)
|
|
@@ -430,10 +440,12 @@ def _validate_dataset(
|
|
|
430
440
|
except:
|
|
431
441
|
logger.debug("Validating dataset failed. Unable to download items infos.", exc_info=True)
|
|
432
442
|
return False
|
|
443
|
+
if all_ds_infos is None:
|
|
444
|
+
all_ds_infos = api.dataset.get_list(project_id, recursive=True)
|
|
433
445
|
project_meta_changed = _project_meta_changed(project_meta, project.meta)
|
|
434
446
|
for dataset in project.datasets:
|
|
435
447
|
dataset: Dataset
|
|
436
|
-
if dataset.name
|
|
448
|
+
if dataset.name == _get_ds_full_name(dataset_info, all_ds_infos):
|
|
437
449
|
diff = set(items_infos_dict.keys()).difference(set(dataset.get_items_names()))
|
|
438
450
|
if diff:
|
|
439
451
|
logger.debug(
|
|
@@ -481,7 +493,11 @@ def _validate_dataset(
|
|
|
481
493
|
|
|
482
494
|
|
|
483
495
|
def _validate(
|
|
484
|
-
api: Api,
|
|
496
|
+
api: Api,
|
|
497
|
+
project_info: ProjectInfo,
|
|
498
|
+
project_meta: ProjectMeta,
|
|
499
|
+
dataset_infos: List[DatasetInfo],
|
|
500
|
+
all_ds_infos: List[DatasetInfo] = None,
|
|
485
501
|
):
|
|
486
502
|
project_id = project_info.id
|
|
487
503
|
to_download, cached = _split_by_cache(
|
|
@@ -498,6 +514,7 @@ def _validate(
|
|
|
498
514
|
project_info.type,
|
|
499
515
|
project_meta,
|
|
500
516
|
dataset_info,
|
|
517
|
+
all_ds_infos,
|
|
501
518
|
):
|
|
502
519
|
to_download.add(ds_path)
|
|
503
520
|
cached.remove(ds_path)
|
|
@@ -520,7 +537,7 @@ def _add_save_items_infos_to_kwargs(kwargs: dict, project_type: str):
|
|
|
520
537
|
|
|
521
538
|
|
|
522
539
|
def _add_resume_download_to_kwargs(kwargs: dict, project_type: str):
|
|
523
|
-
supported_force_projects = (str(ProjectType.IMAGES),)
|
|
540
|
+
supported_force_projects = (str(ProjectType.IMAGES), (str(ProjectType.VIDEOS)))
|
|
524
541
|
if project_type in supported_force_projects:
|
|
525
542
|
kwargs["resume_download"] = True
|
|
526
543
|
return kwargs
|
|
@@ -592,13 +609,14 @@ def download_to_cache(
|
|
|
592
609
|
project_meta = ProjectMeta.from_json(api.project.get_meta(project_id))
|
|
593
610
|
if dataset_infos is not None and dataset_ids is not None:
|
|
594
611
|
raise ValueError("dataset_infos and dataset_ids cannot be specified at the same time")
|
|
612
|
+
all_ds_infos = api.dataset.get_list(project_id, recursive=True)
|
|
595
613
|
if dataset_infos is None:
|
|
596
614
|
if dataset_ids is None:
|
|
597
|
-
dataset_infos =
|
|
615
|
+
dataset_infos = all_ds_infos
|
|
598
616
|
else:
|
|
599
|
-
dataset_infos = [
|
|
617
|
+
dataset_infos = [ds_info for ds_info in all_ds_infos if ds_info.id in dataset_ids]
|
|
600
618
|
path_to_info = {_get_dataset_path(api, dataset_infos, info.id): info for info in dataset_infos}
|
|
601
|
-
to_download, cached = _validate(api, project_info, project_meta, dataset_infos)
|
|
619
|
+
to_download, cached = _validate(api, project_info, project_meta, dataset_infos, all_ds_infos)
|
|
602
620
|
if progress_cb is not None:
|
|
603
621
|
cached_items_n = sum(path_to_info[ds_path].items_count for ds_path in cached)
|
|
604
622
|
progress_cb(cached_items_n)
|
|
@@ -16,7 +16,7 @@ from supervisely.api.dataset_api import DatasetInfo
|
|
|
16
16
|
from supervisely.api.module_api import ApiField
|
|
17
17
|
from supervisely.api.video.video_api import VideoInfo
|
|
18
18
|
from supervisely.collection.key_indexed_collection import KeyIndexedCollection
|
|
19
|
-
from supervisely.io.fs import mkdir, touch, touch_async
|
|
19
|
+
from supervisely.io.fs import clean_dir, mkdir, touch, touch_async
|
|
20
20
|
from supervisely.io.json import dump_json_file, dump_json_file_async, load_json_file
|
|
21
21
|
from supervisely.project.project import Dataset, OpenMode, Project
|
|
22
22
|
from supervisely.project.project import read_single_project as read_project_wrapper
|
|
@@ -1056,6 +1056,7 @@ class VideoProject(Project):
|
|
|
1056
1056
|
save_video_info: bool = False,
|
|
1057
1057
|
log_progress: bool = True,
|
|
1058
1058
|
progress_cb: Optional[Union[tqdm, Callable]] = None,
|
|
1059
|
+
resume_download: Optional[bool] = False,
|
|
1059
1060
|
) -> None:
|
|
1060
1061
|
"""
|
|
1061
1062
|
Download video project from Supervisely to the given directory.
|
|
@@ -1109,6 +1110,7 @@ class VideoProject(Project):
|
|
|
1109
1110
|
save_video_info=save_video_info,
|
|
1110
1111
|
log_progress=log_progress,
|
|
1111
1112
|
progress_cb=progress_cb,
|
|
1113
|
+
resume_download=resume_download,
|
|
1112
1114
|
)
|
|
1113
1115
|
|
|
1114
1116
|
@staticmethod
|
|
@@ -1182,6 +1184,7 @@ class VideoProject(Project):
|
|
|
1182
1184
|
log_progress: bool = True,
|
|
1183
1185
|
progress_cb: Optional[Union[tqdm, Callable]] = None,
|
|
1184
1186
|
include_custom_data: bool = False,
|
|
1187
|
+
resume_download: Optional[bool] = False,
|
|
1185
1188
|
**kwargs,
|
|
1186
1189
|
) -> None:
|
|
1187
1190
|
"""
|
|
@@ -1238,6 +1241,7 @@ class VideoProject(Project):
|
|
|
1238
1241
|
log_progress=log_progress,
|
|
1239
1242
|
progress_cb=progress_cb,
|
|
1240
1243
|
include_custom_data=include_custom_data,
|
|
1244
|
+
resume_download=resume_download,
|
|
1241
1245
|
**kwargs,
|
|
1242
1246
|
)
|
|
1243
1247
|
|
|
@@ -1252,6 +1256,7 @@ def download_video_project(
|
|
|
1252
1256
|
log_progress: bool = True,
|
|
1253
1257
|
progress_cb: Optional[Union[tqdm, Callable]] = None,
|
|
1254
1258
|
include_custom_data: Optional[bool] = False,
|
|
1259
|
+
resume_download: Optional[bool] = False,
|
|
1255
1260
|
) -> None:
|
|
1256
1261
|
"""
|
|
1257
1262
|
Download video project to the local directory.
|
|
@@ -1312,9 +1317,22 @@ def download_video_project(
|
|
|
1312
1317
|
LOG_BATCH_SIZE = 1
|
|
1313
1318
|
|
|
1314
1319
|
key_id_map = KeyIdMap()
|
|
1315
|
-
|
|
1316
|
-
meta = ProjectMeta.from_json(api.project.get_meta(project_id))
|
|
1320
|
+
|
|
1321
|
+
meta = ProjectMeta.from_json(api.project.get_meta(project_id, with_settings=True))
|
|
1322
|
+
if os.path.exists(dest_dir) and resume_download:
|
|
1323
|
+
dump_json_file(meta.to_json(), os.path.join(dest_dir, "meta.json"))
|
|
1324
|
+
try:
|
|
1325
|
+
project_fs = VideoProject(dest_dir, OpenMode.READ)
|
|
1326
|
+
except RuntimeError as e:
|
|
1327
|
+
if "Project is empty" in str(e):
|
|
1328
|
+
clean_dir(dest_dir)
|
|
1329
|
+
project_fs = None
|
|
1330
|
+
else:
|
|
1331
|
+
raise
|
|
1332
|
+
if project_fs is None:
|
|
1333
|
+
project_fs = VideoProject(dest_dir, OpenMode.CREATE)
|
|
1317
1334
|
project_fs.set_meta(meta)
|
|
1335
|
+
|
|
1318
1336
|
if progress_cb is not None:
|
|
1319
1337
|
log_progress = False
|
|
1320
1338
|
|
|
@@ -1549,6 +1567,7 @@ async def download_video_project_async(
|
|
|
1549
1567
|
log_progress: bool = True,
|
|
1550
1568
|
progress_cb: Optional[Union[tqdm, Callable]] = None,
|
|
1551
1569
|
include_custom_data: Optional[bool] = False,
|
|
1570
|
+
resume_download: Optional[bool] = False,
|
|
1552
1571
|
**kwargs,
|
|
1553
1572
|
) -> None:
|
|
1554
1573
|
"""
|
|
@@ -1603,9 +1622,19 @@ async def download_video_project_async(
|
|
|
1603
1622
|
|
|
1604
1623
|
key_id_map = KeyIdMap()
|
|
1605
1624
|
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1625
|
+
meta = ProjectMeta.from_json(api.project.get_meta(project_id, with_settings=True))
|
|
1626
|
+
if os.path.exists(dest_dir) and resume_download:
|
|
1627
|
+
dump_json_file(meta.to_json(), os.path.join(dest_dir, "meta.json"))
|
|
1628
|
+
try:
|
|
1629
|
+
project_fs = VideoProject(dest_dir, OpenMode.READ)
|
|
1630
|
+
except RuntimeError as e:
|
|
1631
|
+
if "Project is empty" in str(e):
|
|
1632
|
+
clean_dir(dest_dir)
|
|
1633
|
+
project_fs = None
|
|
1634
|
+
else:
|
|
1635
|
+
raise
|
|
1636
|
+
if project_fs is None:
|
|
1637
|
+
project_fs = VideoProject(dest_dir, OpenMode.CREATE)
|
|
1609
1638
|
project_fs.set_meta(meta)
|
|
1610
1639
|
|
|
1611
1640
|
if progress_cb is not None:
|
supervisely/volume/volume.py
CHANGED
|
@@ -9,9 +9,11 @@ import numpy as np
|
|
|
9
9
|
import pydicom
|
|
10
10
|
import SimpleITK as sitk
|
|
11
11
|
import stringcase
|
|
12
|
+
from trimesh import Trimesh
|
|
12
13
|
|
|
13
14
|
import supervisely.volume.nrrd_encoder as nrrd_encoder
|
|
14
15
|
from supervisely import logger
|
|
16
|
+
from supervisely.geometry.mask_3d import Mask3D
|
|
15
17
|
from supervisely.io.fs import get_file_ext, get_file_name, list_files_recursively
|
|
16
18
|
|
|
17
19
|
# Do NOT use directly for extension validation. Use is_valid_ext() / has_valid_ext() below instead.
|
|
@@ -783,7 +785,7 @@ def convert_nifti_to_nrrd(path: str) -> Tuple[np.ndarray, dict]:
|
|
|
783
785
|
data, header = sly.volume.convert_nifti_to_nrrd(path)
|
|
784
786
|
"""
|
|
785
787
|
|
|
786
|
-
import nibabel as nib
|
|
788
|
+
import nibabel as nib # pylint: disable=import-error
|
|
787
789
|
|
|
788
790
|
nifti = nib.load(path)
|
|
789
791
|
reordered_to_ras_nifti = nib.as_closest_canonical(nifti)
|
|
@@ -799,6 +801,7 @@ def convert_nifti_to_nrrd(path: str) -> Tuple[np.ndarray, dict]:
|
|
|
799
801
|
}
|
|
800
802
|
return data, header
|
|
801
803
|
|
|
804
|
+
|
|
802
805
|
def convert_3d_nifti_to_nrrd(path: str) -> Tuple[np.ndarray, dict]:
|
|
803
806
|
"""Convert 3D NIFTI volume to NRRD format.
|
|
804
807
|
Volume automatically reordered to RAS orientation as closest to canonical.
|
|
@@ -830,14 +833,14 @@ def convert_3d_nifti_to_nrrd(path: str) -> Tuple[np.ndarray, dict]:
|
|
|
830
833
|
space_directions = (direction.T * spacing[:, None]).tolist()
|
|
831
834
|
|
|
832
835
|
header = {
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
836
|
+
"dimension": 3,
|
|
837
|
+
"space": "right-anterior-superior",
|
|
838
|
+
"sizes": list(data.shape),
|
|
839
|
+
"space directions": space_directions,
|
|
840
|
+
"endian": "little",
|
|
841
|
+
"encoding": "gzip",
|
|
842
|
+
"space origin": origin,
|
|
843
|
+
}
|
|
841
844
|
return data, header
|
|
842
845
|
|
|
843
846
|
|
|
@@ -861,3 +864,96 @@ def is_nifti_file(path: str) -> bool:
|
|
|
861
864
|
return True
|
|
862
865
|
except nib.filebasedimages.ImageFileError:
|
|
863
866
|
return False
|
|
867
|
+
|
|
868
|
+
|
|
869
|
+
def convert_3d_geometry_to_mesh(
|
|
870
|
+
geometry: Mask3D,
|
|
871
|
+
spacing: tuple = None,
|
|
872
|
+
level: float = 0.5,
|
|
873
|
+
apply_decimation: bool = False,
|
|
874
|
+
decimation_fraction: float = 0.5,
|
|
875
|
+
) -> Trimesh:
|
|
876
|
+
"""
|
|
877
|
+
Converts a 3D geometry (Mask3D) to a Trimesh mesh.
|
|
878
|
+
|
|
879
|
+
:param geometry: The 3D geometry to convert.
|
|
880
|
+
:type geometry: supervisely.geometry.mask_3d.Mask3D
|
|
881
|
+
:param spacing: Voxel spacing in (x, y, z). Default is taken from geometry meta.
|
|
882
|
+
:type spacing: tuple
|
|
883
|
+
:param level: Isosurface value for marching cubes. Default is 0.5.
|
|
884
|
+
:type level: float
|
|
885
|
+
:param apply_decimation: Whether to simplify the mesh. Default is False.
|
|
886
|
+
:type apply_decimation: bool
|
|
887
|
+
:param decimation_fraction: Fraction of faces to keep if decimation is applied. Default is 0.5.
|
|
888
|
+
:type decimation_fraction: float
|
|
889
|
+
:return: The resulting Trimesh mesh.
|
|
890
|
+
:rtype: trimesh.Trimesh
|
|
891
|
+
|
|
892
|
+
:Usage example:
|
|
893
|
+
|
|
894
|
+
.. code-block:: python
|
|
895
|
+
|
|
896
|
+
mask3d = Mask3D.create_from_file("path/to/mask3d")
|
|
897
|
+
mesh = convert_3d_geometry_to_mesh(mask3d, spacing=(1.0, 1.0, 1.0), level=0.7, apply_decimation=True)
|
|
898
|
+
"""
|
|
899
|
+
from skimage import measure
|
|
900
|
+
|
|
901
|
+
# Flip the mask along the x-axis to correct mirroring
|
|
902
|
+
mask = np.flip(geometry.data, axis=0)
|
|
903
|
+
if spacing is None:
|
|
904
|
+
try:
|
|
905
|
+
spacing = tuple(
|
|
906
|
+
float(abs(direction[i])) for i, direction in enumerate(geometry._space_directions)
|
|
907
|
+
)
|
|
908
|
+
except Exception as e:
|
|
909
|
+
logger.warning(
|
|
910
|
+
"Failed to get spacing from geometry meta. Using (1.0, 1.0, 1.0).", exc_info=1
|
|
911
|
+
)
|
|
912
|
+
spacing = (1.0, 1.0, 1.0)
|
|
913
|
+
|
|
914
|
+
# marching_cubes expects (z, y, x) order
|
|
915
|
+
verts, faces, normals, _ = measure.marching_cubes(
|
|
916
|
+
mask.astype(np.float32), level=level, spacing=spacing
|
|
917
|
+
)
|
|
918
|
+
mesh = Trimesh(vertices=verts, faces=faces, vertex_normals=normals, process=False)
|
|
919
|
+
|
|
920
|
+
if apply_decimation and 0 < decimation_fraction < 1:
|
|
921
|
+
mesh = mesh.simplify_quadric_decimation(int(len(mesh.faces) * decimation_fraction))
|
|
922
|
+
|
|
923
|
+
return mesh
|
|
924
|
+
|
|
925
|
+
|
|
926
|
+
def export_3d_as_mesh(geometry: Mask3D, output_path: str, kwargs=None):
|
|
927
|
+
"""
|
|
928
|
+
Exports the 3D mesh representation of the object to a file in either STL or OBJ format.
|
|
929
|
+
|
|
930
|
+
:param geometry: The 3D geometry to be exported.
|
|
931
|
+
:type geometry: supervisely.geometry.mask_3d.Mask3D
|
|
932
|
+
:param output_path: The path to the output file. Must have a ".stl" or ".obj" extension.
|
|
933
|
+
:type output_path: str
|
|
934
|
+
:param kwargs: Additional keyword arguments for mesh generation. Supported keys:
|
|
935
|
+
- spacing (tuple): Voxel spacing in (x, y, z). By default the value will be taken from geometry meta.
|
|
936
|
+
- level (float): Isosurface value for marching cubes. Default is 0.5.
|
|
937
|
+
- apply_decimation (bool): Whether to simplify the mesh. Default is False.
|
|
938
|
+
- decimation_fraction (float): Fraction of faces to keep if decimation is applied. Default is 0.5.
|
|
939
|
+
:type kwargs: dict, optional
|
|
940
|
+
:return: None
|
|
941
|
+
|
|
942
|
+
:Usage example:
|
|
943
|
+
|
|
944
|
+
.. code-block:: python
|
|
945
|
+
|
|
946
|
+
mask3d_path = "path/to/mask3d"
|
|
947
|
+
mask3d = Mask3D.create_from_file(mask3d_path)
|
|
948
|
+
|
|
949
|
+
mask3d.export_3d_as_mesh(mask3d, "output.stl", {"spacing": (1.0, 1.0, 1.0), "level": 0.7, "apply_decimation": True})
|
|
950
|
+
"""
|
|
951
|
+
|
|
952
|
+
if kwargs is None:
|
|
953
|
+
kwargs = {}
|
|
954
|
+
|
|
955
|
+
if get_file_ext(output_path).lower() not in [".stl", ".obj"]:
|
|
956
|
+
raise ValueError('File extension must be either ".stl" or ".obj"')
|
|
957
|
+
|
|
958
|
+
mesh = convert_3d_geometry_to_mesh(geometry, **kwargs)
|
|
959
|
+
mesh.export(output_path)
|
|
@@ -11,6 +11,7 @@ from supervisely.volume_annotation.volume_figure import VolumeFigure
|
|
|
11
11
|
|
|
12
12
|
from supervisely.project.project_meta import ProjectMeta
|
|
13
13
|
from supervisely._utils import take_with_default
|
|
14
|
+
from supervisely.io.fs import file_exists
|
|
14
15
|
from supervisely.video_annotation.key_id_map import KeyIdMap
|
|
15
16
|
from supervisely.volume_annotation.slice import Slice
|
|
16
17
|
from supervisely.volume_annotation.volume_tag_collection import VolumeTagCollection
|
|
@@ -30,7 +31,7 @@ from supervisely.volume_annotation.constants import (
|
|
|
30
31
|
PLANES,
|
|
31
32
|
SPATIAL_FIGURES,
|
|
32
33
|
)
|
|
33
|
-
|
|
34
|
+
from supervisely.io.fs import get_file_name
|
|
34
35
|
from supervisely.io.json import dump_json_file
|
|
35
36
|
|
|
36
37
|
|
|
@@ -484,7 +485,13 @@ class VolumeAnnotation:
|
|
|
484
485
|
)
|
|
485
486
|
|
|
486
487
|
@classmethod
|
|
487
|
-
def from_json(
|
|
488
|
+
def from_json(
|
|
489
|
+
cls,
|
|
490
|
+
data: dict,
|
|
491
|
+
project_meta: ProjectMeta,
|
|
492
|
+
key_id_map: KeyIdMap = None,
|
|
493
|
+
spatial_geometry_paths: Union[list, dict] = None,
|
|
494
|
+
):
|
|
488
495
|
"""
|
|
489
496
|
Convert a json dict to VolumeAnnotation.
|
|
490
497
|
|
|
@@ -494,6 +501,11 @@ class VolumeAnnotation:
|
|
|
494
501
|
:type project_meta: ProjectMeta
|
|
495
502
|
:param key_id_map: KeyIdMap object.
|
|
496
503
|
:type key_id_map: KeyIdMap, optional
|
|
504
|
+
:param spatial_geometry_paths: Optional. Can be either:
|
|
505
|
+
- a list of file paths to spatial geometry files, where each file name should match either the figure's id or the hex value of its key,
|
|
506
|
+
- or a dict mapping figure ids (or keys) to their corresponding geometry file paths.
|
|
507
|
+
Used to load 3D geometry for spatial figures.
|
|
508
|
+
:type spatial_geometry_paths: list or dict, optional
|
|
497
509
|
:return: VolumeAnnotation object
|
|
498
510
|
:rtype: :class:`VolumeAnnotation<VolumeAnnotation>`
|
|
499
511
|
:Usage example:
|
|
@@ -585,6 +597,31 @@ class VolumeAnnotation:
|
|
|
585
597
|
slice_index=None,
|
|
586
598
|
key_id_map=key_id_map,
|
|
587
599
|
)
|
|
600
|
+
if spatial_geometry_paths:
|
|
601
|
+
figure_id = figure_json["id"]
|
|
602
|
+
if isinstance(spatial_geometry_paths, list):
|
|
603
|
+
spatial_geometry_paths = {
|
|
604
|
+
get_file_name(path): path for path in spatial_geometry_paths
|
|
605
|
+
}
|
|
606
|
+
geometry_path = spatial_geometry_paths.get(
|
|
607
|
+
figure.key().hex
|
|
608
|
+
) or spatial_geometry_paths.get(str(figure_id))
|
|
609
|
+
elif isinstance(spatial_geometry_paths, dict):
|
|
610
|
+
geometry_path = spatial_geometry_paths.get(figure_id, None)
|
|
611
|
+
else:
|
|
612
|
+
raise ValueError(
|
|
613
|
+
f"spatial_geometry_paths should be either a list or a dict. Got: {type(spatial_geometry_paths)}"
|
|
614
|
+
)
|
|
615
|
+
|
|
616
|
+
if geometry_path is not None:
|
|
617
|
+
if not file_exists(geometry_path):
|
|
618
|
+
raise RuntimeError(
|
|
619
|
+
f"Geometry file {geometry_path} for figure {figure_id} does not exist."
|
|
620
|
+
)
|
|
621
|
+
mask3d = Mask3D.create_from_file(geometry_path)
|
|
622
|
+
mask3d.sly_id = figure_id
|
|
623
|
+
figure._set_3d_geometry(mask3d)
|
|
624
|
+
|
|
588
625
|
spatial_figures.append(figure)
|
|
589
626
|
|
|
590
627
|
return cls(
|
|
@@ -1,28 +1,30 @@
|
|
|
1
1
|
# coding: utf-8
|
|
2
2
|
from __future__ import annotations
|
|
3
|
+
|
|
3
4
|
import uuid
|
|
4
|
-
from typing import
|
|
5
|
-
from numpy import ndarray
|
|
5
|
+
from typing import Literal, Optional, Union
|
|
6
6
|
from uuid import UUID
|
|
7
|
-
|
|
8
|
-
from
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
|
|
8
|
+
from numpy import ndarray
|
|
9
|
+
|
|
10
|
+
import supervisely.volume_annotation.constants as constants
|
|
11
|
+
from supervisely._utils import take_with_default
|
|
12
|
+
from supervisely.annotation.json_geometries_map import GET_GEOMETRY_FROM_STR
|
|
11
13
|
from supervisely.api.module_api import ApiField
|
|
12
14
|
from supervisely.geometry.any_geometry import AnyGeometry
|
|
13
|
-
from supervisely.
|
|
14
|
-
from supervisely._utils import take_with_default
|
|
15
|
-
from supervisely.volume_annotation.volume_object import VolumeObject
|
|
16
|
-
from supervisely.geometry.geometry import Geometry
|
|
17
|
-
import supervisely.volume_annotation.constants as constants
|
|
18
|
-
from supervisely.volume_annotation.constants import ID, KEY, OBJECT_ID, OBJECT_KEY, META
|
|
15
|
+
from supervisely.geometry.closed_surface_mesh import ClosedSurfaceMesh
|
|
19
16
|
from supervisely.geometry.constants import (
|
|
17
|
+
CLASS_ID,
|
|
18
|
+
CREATED_AT,
|
|
20
19
|
LABELER_LOGIN,
|
|
21
20
|
UPDATED_AT,
|
|
22
|
-
CREATED_AT,
|
|
23
|
-
CLASS_ID,
|
|
24
21
|
)
|
|
25
|
-
|
|
22
|
+
from supervisely.geometry.geometry import Geometry
|
|
23
|
+
from supervisely.geometry.mask_3d import Mask3D
|
|
24
|
+
from supervisely.video_annotation.key_id_map import KeyIdMap
|
|
25
|
+
from supervisely.video_annotation.video_figure import VideoFigure
|
|
26
|
+
from supervisely.volume_annotation.constants import ID, KEY, META, OBJECT_ID, OBJECT_KEY
|
|
27
|
+
from supervisely.volume_annotation.volume_object import VolumeObject
|
|
26
28
|
from supervisely.volume_annotation.volume_object_collection import (
|
|
27
29
|
VolumeObjectCollection,
|
|
28
30
|
)
|
|
@@ -888,7 +888,7 @@ supervisely/nn/benchmark/visualization/widgets/table/__init__.py,sha256=47DEQpj8
|
|
|
888
888
|
supervisely/nn/benchmark/visualization/widgets/table/table.py,sha256=atmDnF1Af6qLQBUjLhK18RMDKAYlxnsuVHMSEa5a-e8,4319
|
|
889
889
|
supervisely/nn/inference/__init__.py,sha256=QFukX2ip-U7263aEPCF_UCFwj6EujbMnsgrXp5Bbt8I,1623
|
|
890
890
|
supervisely/nn/inference/cache.py,sha256=rc_CRlCuTCzLDtcl1paTJib7ALTer0ge9o32WtoUMkY,34795
|
|
891
|
-
supervisely/nn/inference/inference.py,sha256=
|
|
891
|
+
supervisely/nn/inference/inference.py,sha256=OoslbS1Rog8PgvxBCrdkyxwMQw8ITlot1mQSxxSCd0c,177297
|
|
892
892
|
supervisely/nn/inference/inference_request.py,sha256=y6yw0vbaRRcEBS27nq3y0sL6Gmq2qLA_Bm0GrnJGegE,14267
|
|
893
893
|
supervisely/nn/inference/session.py,sha256=dIg2F-OBl68pUzcmtmcI0YQIp1WWNnrJTVMjwFN91Q4,35824
|
|
894
894
|
supervisely/nn/inference/uploader.py,sha256=21a9coOimCHhEqAbV-llZWcp12847DEMoQp3N16bpK0,5425
|
|
@@ -1032,7 +1032,7 @@ supervisely/pointcloud_episodes/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm
|
|
|
1032
1032
|
supervisely/pointcloud_episodes/pointcloud_episodes.py,sha256=cRXdtw7bMsbsdVQjxfWxFSESrO-LGiqqsZyyExl2Mbg,3430
|
|
1033
1033
|
supervisely/project/__init__.py,sha256=hlzdj9Pgy53Q3qdP8LMtGTChvZHQuuShdtui2eRUQeE,2601
|
|
1034
1034
|
supervisely/project/data_version.py,sha256=P5Lui6i64pYeJWmAdGJDv8GRXxjfpSSZ8zT_MxIrynE,19553
|
|
1035
|
-
supervisely/project/download.py,sha256=
|
|
1035
|
+
supervisely/project/download.py,sha256=nhxID-kbsNTgIY9l1lnRuUlzKrsJw80X07jEElyl3sE,28466
|
|
1036
1036
|
supervisely/project/pointcloud_episode_project.py,sha256=yiWdNBQiI6f1O9sr1pg8JHW6O-w3XUB1rikJNn3Oung,41866
|
|
1037
1037
|
supervisely/project/pointcloud_project.py,sha256=Kx1Vaes-krwG3BiRRtHRLQxb9G5m5bTHPN9IzRqmNWo,49399
|
|
1038
1038
|
supervisely/project/project.py,sha256=k0eE6Jy9eDYO-WUbDK0a-IVA34VVWYRzMBVkPY9XdGw,235812
|
|
@@ -1041,7 +1041,7 @@ supervisely/project/project_settings.py,sha256=NLThzU_DCynOK6hkHhVdFyezwprn9Uqln
|
|
|
1041
1041
|
supervisely/project/project_type.py,sha256=7mQ7zg6r7Bm2oFn5aR8n_PeLqMmOaPZd6ph7Z8ZISTw,608
|
|
1042
1042
|
supervisely/project/readme_template.md,sha256=NKYEoJubNWLV_HmhVmdB6L4dneLqDkvl2b71xy5fc54,9150
|
|
1043
1043
|
supervisely/project/upload.py,sha256=AjgHYgVZwUE25ygC5pqvFjdAladbyB8T78mlet5Qpho,3750
|
|
1044
|
-
supervisely/project/video_project.py,sha256=
|
|
1044
|
+
supervisely/project/video_project.py,sha256=zAtB3YpW9tC9Tc3qfapbQ9O2nhAWU2wDjMuS5sepXqc,65297
|
|
1045
1045
|
supervisely/project/volume_project.py,sha256=Kn9VEvWuKKZvL2nx6B6bjSvHuoZhAOxEc6DvPRexUco,22666
|
|
1046
1046
|
supervisely/pyscripts_utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
1047
1047
|
supervisely/pyscripts_utils/utils.py,sha256=scEwHJvHRQa8NHIOn2eTwH6-Zc8CGdLoxM-WzH9jcRo,314
|
|
@@ -1075,13 +1075,13 @@ supervisely/volume/__init__.py,sha256=EBZBY_5mzabXzMUQh5akusIGd16XnX9n8J0jIi_JmW
|
|
|
1075
1075
|
supervisely/volume/nrrd_encoder.py,sha256=1lqwwyqxEvctw1ysQ70x4xPSV1uy1g5YcH5CURwL7-c,4084
|
|
1076
1076
|
supervisely/volume/nrrd_loader.py,sha256=_yqahKcqSRxunHZ5LtnUWIRA7UvIhPKOhAUwYijSGY4,9065
|
|
1077
1077
|
supervisely/volume/stl_converter.py,sha256=WIMQgHO_u4JT58QdcMXcb_euF1BFhM7D52IVX_0QTxE,6285
|
|
1078
|
-
supervisely/volume/volume.py,sha256=
|
|
1078
|
+
supervisely/volume/volume.py,sha256=ekU8gYhSXrTvWISd_HJT7lwtQ9Uh5t7qgVcFwzJ2NOc,29273
|
|
1079
1079
|
supervisely/volume_annotation/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
1080
1080
|
supervisely/volume_annotation/constants.py,sha256=BdFIh56fy7vzLIjt0gH8xP01EIU-qgQIwbSHVUcABCU,569
|
|
1081
1081
|
supervisely/volume_annotation/plane.py,sha256=wyezAcc8tLp38O44CwWY0wjdQxf3VjRdFLWooCrk-Nw,16301
|
|
1082
1082
|
supervisely/volume_annotation/slice.py,sha256=9m3jtUYz4PYKV3rgbeh2ofDebkyg4TomNbkC6BwZ0lA,4635
|
|
1083
|
-
supervisely/volume_annotation/volume_annotation.py,sha256=
|
|
1084
|
-
supervisely/volume_annotation/volume_figure.py,sha256=
|
|
1083
|
+
supervisely/volume_annotation/volume_annotation.py,sha256=pGu6n8_5JkFpir4HTVRf302gGD2EqJ96Gh4M0_236Qg,32047
|
|
1084
|
+
supervisely/volume_annotation/volume_figure.py,sha256=B4rXacAMM-eVPLZHQTBpT2USBv8Zh6eTzj0_e3tmuSA,25331
|
|
1085
1085
|
supervisely/volume_annotation/volume_object.py,sha256=rWzOnycoSJ4-CvFgDOP_rPortU4CdcYR26txe5wJHNo,3577
|
|
1086
1086
|
supervisely/volume_annotation/volume_object_collection.py,sha256=Tc4AovntgoFj5hpTLBv7pCQ3eL0BjorOVpOh2nAE_tA,5706
|
|
1087
1087
|
supervisely/volume_annotation/volume_tag.py,sha256=N2eOhAlbRDVVdSVQ83dzg7URDGtb1xHjxL2g9BW6ljU,9488
|
|
@@ -1097,9 +1097,9 @@ supervisely/worker_proto/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZ
|
|
|
1097
1097
|
supervisely/worker_proto/worker_api_pb2.py,sha256=VQfi5JRBHs2pFCK1snec3JECgGnua3Xjqw_-b3aFxuM,59142
|
|
1098
1098
|
supervisely/worker_proto/worker_api_pb2_grpc.py,sha256=3BwQXOaP9qpdi0Dt9EKG--Lm8KGN0C5AgmUfRv77_Jk,28940
|
|
1099
1099
|
supervisely_lib/__init__.py,sha256=7-3QnN8Zf0wj8NCr2oJmqoQWMKKPKTECvjH9pd2S5vY,159
|
|
1100
|
-
supervisely-6.73.
|
|
1101
|
-
supervisely-6.73.
|
|
1102
|
-
supervisely-6.73.
|
|
1103
|
-
supervisely-6.73.
|
|
1104
|
-
supervisely-6.73.
|
|
1105
|
-
supervisely-6.73.
|
|
1100
|
+
supervisely-6.73.362.dist-info/LICENSE,sha256=xx0jnfkXJvxRnG63LTGOxlggYnIysveWIZ6H3PNdCrQ,11357
|
|
1101
|
+
supervisely-6.73.362.dist-info/METADATA,sha256=pEJ1fz_ct_nNeRITHBz-wp16AYlUFbNvG9zwIKwbWTI,35151
|
|
1102
|
+
supervisely-6.73.362.dist-info/WHEEL,sha256=iAkIy5fosb7FzIOwONchHf19Qu7_1wCWyFNR5gu9nU0,91
|
|
1103
|
+
supervisely-6.73.362.dist-info/entry_points.txt,sha256=U96-5Hxrp2ApRjnCoUiUhWMqijqh8zLR03sEhWtAcms,102
|
|
1104
|
+
supervisely-6.73.362.dist-info/top_level.txt,sha256=kcFVwb7SXtfqZifrZaSE3owHExX4gcNYe7Q2uoby084,28
|
|
1105
|
+
supervisely-6.73.362.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|