supervisely 6.73.438__py3-none-any.whl → 6.73.513__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/__init__.py +137 -1
- supervisely/_utils.py +81 -0
- supervisely/annotation/annotation.py +8 -2
- supervisely/annotation/json_geometries_map.py +14 -11
- supervisely/annotation/label.py +80 -3
- supervisely/api/annotation_api.py +14 -11
- supervisely/api/api.py +59 -38
- supervisely/api/app_api.py +11 -2
- supervisely/api/dataset_api.py +74 -12
- supervisely/api/entities_collection_api.py +10 -0
- supervisely/api/entity_annotation/figure_api.py +52 -4
- supervisely/api/entity_annotation/object_api.py +3 -3
- supervisely/api/entity_annotation/tag_api.py +63 -12
- supervisely/api/guides_api.py +210 -0
- supervisely/api/image_api.py +72 -1
- supervisely/api/labeling_job_api.py +83 -1
- supervisely/api/labeling_queue_api.py +33 -7
- supervisely/api/module_api.py +9 -0
- supervisely/api/project_api.py +71 -26
- supervisely/api/storage_api.py +3 -1
- supervisely/api/task_api.py +13 -2
- supervisely/api/team_api.py +4 -3
- supervisely/api/video/video_annotation_api.py +119 -3
- supervisely/api/video/video_api.py +65 -14
- supervisely/api/video/video_figure_api.py +24 -11
- supervisely/app/__init__.py +1 -1
- supervisely/app/content.py +23 -7
- supervisely/app/development/development.py +18 -2
- supervisely/app/fastapi/__init__.py +1 -0
- supervisely/app/fastapi/custom_static_files.py +1 -1
- supervisely/app/fastapi/multi_user.py +105 -0
- supervisely/app/fastapi/subapp.py +88 -42
- supervisely/app/fastapi/websocket.py +77 -9
- supervisely/app/singleton.py +21 -0
- supervisely/app/v1/app_service.py +18 -2
- supervisely/app/v1/constants.py +7 -1
- supervisely/app/widgets/__init__.py +6 -0
- supervisely/app/widgets/activity_feed/__init__.py +0 -0
- supervisely/app/widgets/activity_feed/activity_feed.py +239 -0
- supervisely/app/widgets/activity_feed/style.css +78 -0
- supervisely/app/widgets/activity_feed/template.html +22 -0
- supervisely/app/widgets/card/card.py +20 -0
- supervisely/app/widgets/classes_list_selector/classes_list_selector.py +121 -9
- supervisely/app/widgets/classes_list_selector/template.html +60 -93
- supervisely/app/widgets/classes_mapping/classes_mapping.py +13 -12
- supervisely/app/widgets/classes_table/classes_table.py +1 -0
- supervisely/app/widgets/deploy_model/deploy_model.py +56 -35
- supervisely/app/widgets/dialog/dialog.py +12 -0
- supervisely/app/widgets/dialog/template.html +2 -1
- supervisely/app/widgets/ecosystem_model_selector/ecosystem_model_selector.py +1 -1
- supervisely/app/widgets/experiment_selector/experiment_selector.py +8 -0
- supervisely/app/widgets/fast_table/fast_table.py +184 -60
- supervisely/app/widgets/fast_table/template.html +1 -1
- supervisely/app/widgets/heatmap/__init__.py +0 -0
- supervisely/app/widgets/heatmap/heatmap.py +564 -0
- supervisely/app/widgets/heatmap/script.js +533 -0
- supervisely/app/widgets/heatmap/style.css +233 -0
- supervisely/app/widgets/heatmap/template.html +21 -0
- supervisely/app/widgets/modal/__init__.py +0 -0
- supervisely/app/widgets/modal/modal.py +198 -0
- supervisely/app/widgets/modal/template.html +10 -0
- supervisely/app/widgets/object_class_view/object_class_view.py +3 -0
- supervisely/app/widgets/radio_tabs/radio_tabs.py +18 -2
- supervisely/app/widgets/radio_tabs/template.html +1 -0
- supervisely/app/widgets/select/select.py +6 -3
- supervisely/app/widgets/select_class/__init__.py +0 -0
- supervisely/app/widgets/select_class/select_class.py +363 -0
- supervisely/app/widgets/select_class/template.html +50 -0
- supervisely/app/widgets/select_cuda/select_cuda.py +22 -0
- supervisely/app/widgets/select_dataset_tree/select_dataset_tree.py +65 -7
- supervisely/app/widgets/select_tag/__init__.py +0 -0
- supervisely/app/widgets/select_tag/select_tag.py +352 -0
- supervisely/app/widgets/select_tag/template.html +64 -0
- supervisely/app/widgets/select_team/select_team.py +37 -4
- supervisely/app/widgets/select_team/template.html +4 -5
- supervisely/app/widgets/select_user/__init__.py +0 -0
- supervisely/app/widgets/select_user/select_user.py +270 -0
- supervisely/app/widgets/select_user/template.html +13 -0
- supervisely/app/widgets/select_workspace/select_workspace.py +59 -10
- supervisely/app/widgets/select_workspace/template.html +9 -12
- supervisely/app/widgets/table/table.py +68 -13
- supervisely/app/widgets/tree_select/tree_select.py +2 -0
- supervisely/aug/aug.py +6 -2
- supervisely/convert/base_converter.py +1 -0
- supervisely/convert/converter.py +2 -2
- supervisely/convert/image/csv/csv_converter.py +24 -15
- supervisely/convert/image/image_converter.py +3 -1
- supervisely/convert/image/image_helper.py +48 -4
- supervisely/convert/image/label_studio/label_studio_converter.py +2 -0
- supervisely/convert/image/medical2d/medical2d_helper.py +2 -24
- supervisely/convert/image/multispectral/multispectral_converter.py +6 -0
- supervisely/convert/image/pascal_voc/pascal_voc_converter.py +8 -5
- supervisely/convert/image/pascal_voc/pascal_voc_helper.py +7 -0
- supervisely/convert/pointcloud/kitti_3d/kitti_3d_converter.py +33 -3
- supervisely/convert/pointcloud/kitti_3d/kitti_3d_helper.py +12 -5
- supervisely/convert/pointcloud/las/las_converter.py +13 -1
- supervisely/convert/pointcloud/las/las_helper.py +110 -11
- supervisely/convert/pointcloud/nuscenes_conv/nuscenes_converter.py +27 -16
- supervisely/convert/pointcloud/pointcloud_converter.py +91 -3
- supervisely/convert/pointcloud_episodes/nuscenes_conv/nuscenes_converter.py +58 -22
- supervisely/convert/pointcloud_episodes/nuscenes_conv/nuscenes_helper.py +21 -47
- supervisely/convert/video/__init__.py +1 -0
- supervisely/convert/video/multi_view/__init__.py +0 -0
- supervisely/convert/video/multi_view/multi_view.py +543 -0
- supervisely/convert/video/sly/sly_video_converter.py +359 -3
- supervisely/convert/video/video_converter.py +24 -4
- supervisely/convert/volume/dicom/dicom_converter.py +13 -5
- supervisely/convert/volume/dicom/dicom_helper.py +30 -18
- supervisely/geometry/constants.py +1 -0
- supervisely/geometry/geometry.py +4 -0
- supervisely/geometry/helpers.py +5 -1
- supervisely/geometry/oriented_bbox.py +676 -0
- supervisely/geometry/polyline_3d.py +110 -0
- supervisely/geometry/rectangle.py +2 -1
- supervisely/io/env.py +76 -1
- supervisely/io/fs.py +21 -0
- supervisely/nn/benchmark/base_evaluator.py +104 -11
- supervisely/nn/benchmark/instance_segmentation/evaluator.py +1 -8
- supervisely/nn/benchmark/object_detection/evaluator.py +20 -4
- supervisely/nn/benchmark/object_detection/vis_metrics/pr_curve.py +10 -5
- supervisely/nn/benchmark/semantic_segmentation/evaluator.py +34 -16
- supervisely/nn/benchmark/semantic_segmentation/vis_metrics/confusion_matrix.py +1 -1
- supervisely/nn/benchmark/semantic_segmentation/vis_metrics/frequently_confused.py +1 -1
- supervisely/nn/benchmark/semantic_segmentation/vis_metrics/overview.py +1 -1
- supervisely/nn/benchmark/visualization/evaluation_result.py +66 -4
- supervisely/nn/inference/cache.py +43 -18
- supervisely/nn/inference/gui/serving_gui_template.py +5 -2
- supervisely/nn/inference/inference.py +916 -222
- supervisely/nn/inference/inference_request.py +55 -10
- supervisely/nn/inference/predict_app/gui/classes_selector.py +83 -12
- supervisely/nn/inference/predict_app/gui/gui.py +676 -488
- supervisely/nn/inference/predict_app/gui/input_selector.py +205 -26
- supervisely/nn/inference/predict_app/gui/model_selector.py +2 -4
- supervisely/nn/inference/predict_app/gui/output_selector.py +46 -6
- supervisely/nn/inference/predict_app/gui/settings_selector.py +756 -59
- supervisely/nn/inference/predict_app/gui/tags_selector.py +1 -1
- supervisely/nn/inference/predict_app/gui/utils.py +236 -119
- supervisely/nn/inference/predict_app/predict_app.py +2 -2
- supervisely/nn/inference/session.py +43 -35
- supervisely/nn/inference/tracking/bbox_tracking.py +118 -35
- supervisely/nn/inference/tracking/point_tracking.py +5 -1
- supervisely/nn/inference/tracking/tracker_interface.py +10 -1
- supervisely/nn/inference/uploader.py +139 -12
- supervisely/nn/live_training/__init__.py +7 -0
- supervisely/nn/live_training/api_server.py +111 -0
- supervisely/nn/live_training/artifacts_utils.py +243 -0
- supervisely/nn/live_training/checkpoint_utils.py +229 -0
- supervisely/nn/live_training/dynamic_sampler.py +44 -0
- supervisely/nn/live_training/helpers.py +14 -0
- supervisely/nn/live_training/incremental_dataset.py +146 -0
- supervisely/nn/live_training/live_training.py +497 -0
- supervisely/nn/live_training/loss_plateau_detector.py +111 -0
- supervisely/nn/live_training/request_queue.py +52 -0
- supervisely/nn/model/model_api.py +9 -0
- supervisely/nn/model/prediction.py +2 -1
- supervisely/nn/model/prediction_session.py +26 -14
- supervisely/nn/prediction_dto.py +19 -1
- supervisely/nn/tracker/base_tracker.py +11 -1
- supervisely/nn/tracker/botsort/botsort_config.yaml +0 -1
- supervisely/nn/tracker/botsort/tracker/mc_bot_sort.py +7 -4
- supervisely/nn/tracker/botsort_tracker.py +94 -65
- supervisely/nn/tracker/utils.py +4 -5
- supervisely/nn/tracker/visualize.py +93 -93
- supervisely/nn/training/gui/classes_selector.py +16 -1
- supervisely/nn/training/gui/train_val_splits_selector.py +52 -31
- supervisely/nn/training/train_app.py +46 -31
- supervisely/project/data_version.py +115 -51
- supervisely/project/download.py +1 -1
- supervisely/project/pointcloud_episode_project.py +37 -8
- supervisely/project/pointcloud_project.py +30 -2
- supervisely/project/project.py +14 -2
- supervisely/project/project_meta.py +27 -1
- supervisely/project/project_settings.py +32 -18
- supervisely/project/versioning/__init__.py +1 -0
- supervisely/project/versioning/common.py +20 -0
- supervisely/project/versioning/schema_fields.py +35 -0
- supervisely/project/versioning/video_schema.py +221 -0
- supervisely/project/versioning/volume_schema.py +87 -0
- supervisely/project/video_project.py +717 -15
- supervisely/project/volume_project.py +623 -5
- supervisely/template/experiment/experiment.html.jinja +4 -4
- supervisely/template/experiment/experiment_generator.py +14 -21
- supervisely/template/live_training/__init__.py +0 -0
- supervisely/template/live_training/header.html.jinja +96 -0
- supervisely/template/live_training/live_training.html.jinja +51 -0
- supervisely/template/live_training/live_training_generator.py +464 -0
- supervisely/template/live_training/sly-style.css +402 -0
- supervisely/template/live_training/template.html.jinja +18 -0
- supervisely/versions.json +28 -26
- supervisely/video/sampling.py +39 -20
- supervisely/video/video.py +41 -12
- supervisely/video_annotation/video_figure.py +38 -4
- supervisely/video_annotation/video_object.py +29 -4
- supervisely/volume/stl_converter.py +2 -0
- supervisely/worker_api/agent_rpc.py +24 -1
- supervisely/worker_api/rpc_servicer.py +31 -7
- {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info}/METADATA +58 -40
- {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info}/RECORD +203 -155
- {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info}/WHEEL +1 -1
- supervisely_lib/__init__.py +6 -1
- {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info}/entry_points.txt +0 -0
- {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info/licenses}/LICENSE +0 -0
- {supervisely-6.73.438.dist-info → supervisely-6.73.513.dist-info}/top_level.txt +0 -0
|
@@ -10,6 +10,7 @@ from supervisely._utils import take_with_default
|
|
|
10
10
|
from supervisely.annotation.tag_meta import TagValueType
|
|
11
11
|
from supervisely.collection.str_enum import StrEnum
|
|
12
12
|
from supervisely.io.json import JsonSerializable
|
|
13
|
+
from supervisely.project.project_type import ProjectType
|
|
13
14
|
from supervisely.sly_logger import logger
|
|
14
15
|
|
|
15
16
|
|
|
@@ -184,31 +185,44 @@ class ProjectSettings(JsonSerializable):
|
|
|
184
185
|
|
|
185
186
|
def validate(self, meta):
|
|
186
187
|
if meta.project_settings.multiview_enabled is True:
|
|
187
|
-
|
|
188
|
-
if
|
|
189
|
-
|
|
190
|
-
return # (tag_name, tag_id) == (None, None) is OK
|
|
191
|
-
mtag_name = meta.get_tag_name_by_id(meta.project_settings.multiview_tag_id)
|
|
188
|
+
# Images multiview
|
|
189
|
+
if meta.project_type == ProjectType.IMAGES:
|
|
190
|
+
mtag_name = meta.project_settings.multiview_tag_name
|
|
192
191
|
if mtag_name is None:
|
|
192
|
+
if meta.project_settings.multiview_tag_id is None:
|
|
193
|
+
return # (tag_name, tag_id) == (None, None) is OK
|
|
194
|
+
mtag_name = meta.get_tag_name_by_id(meta.project_settings.multiview_tag_id)
|
|
195
|
+
if mtag_name is None:
|
|
196
|
+
raise RuntimeError(
|
|
197
|
+
f"The multi-view tag with ID={meta.project_settings.multiview_tag_id} was not found in the project meta. "
|
|
198
|
+
"Please directly add the tag meta that will be used for image grouping for multi-view labeling interface."
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
multi_tag = meta.get_tag_meta(mtag_name)
|
|
202
|
+
if multi_tag is None:
|
|
193
203
|
raise RuntimeError(
|
|
194
|
-
f"The multi-view tag
|
|
195
|
-
"
|
|
204
|
+
f"The multi-view tag '{mtag_name}' was not found in the project meta. Please directly add the tag meta "
|
|
205
|
+
"that will be used for image grouping for multi-view labeling interface."
|
|
206
|
+
)
|
|
207
|
+
elif multi_tag.value_type != TagValueType.ANY_STRING:
|
|
208
|
+
raise RuntimeError(
|
|
209
|
+
f"The multi-view tag value type should be '{TagValueType.ANY_STRING}'. The provided type: '{multi_tag.value_type}'."
|
|
196
210
|
)
|
|
197
211
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
)
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
212
|
+
# Video multiview
|
|
213
|
+
elif meta.project_type == ProjectType.VIDEOS:
|
|
214
|
+
if (
|
|
215
|
+
meta.project_settings.multiview_tag_name is not None
|
|
216
|
+
or meta.project_settings.multiview_tag_id is not None
|
|
217
|
+
):
|
|
218
|
+
raise RuntimeError(
|
|
219
|
+
"For video projects, multiview_tag_name and multiview_tag_id should be None. "
|
|
220
|
+
"Videos are grouped by datasets, not by tags."
|
|
221
|
+
)
|
|
208
222
|
|
|
209
223
|
if meta.project_settings.labeling_interface is not None:
|
|
210
224
|
if meta.project_settings.labeling_interface not in LabelingInterface.values():
|
|
211
225
|
raise RuntimeError(
|
|
212
226
|
f"Invalid labeling interface value: {meta.project_settings.labeling_interface}. "
|
|
213
227
|
f"The available values: {LabelingInterface.values()}"
|
|
214
|
-
)
|
|
228
|
+
)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
from supervisely.project.versioning.schema_fields import VersionSchemaField
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from supervisely.project.versioning.video_schema import VideoSnapshotSchema, _VIDEO_SCHEMAS
|
|
2
|
+
from supervisely.project.versioning.volume_schema import VolumeSnapshotSchema, _VOLUME_SCHEMAS
|
|
3
|
+
|
|
4
|
+
DEFAULT_IMAGE_SCHEMA_VERSION = "v1.0.0"
|
|
5
|
+
DEFAULT_VOLUME_SCHEMA_VERSION = "v2.0.0"
|
|
6
|
+
DEFAULT_VIDEO_SCHEMA_VERSION = "v2.0.0"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_video_snapshot_schema(schema_version: str) -> VideoSnapshotSchema:
|
|
10
|
+
schema = _VIDEO_SCHEMAS.get(schema_version)
|
|
11
|
+
if schema is None:
|
|
12
|
+
raise RuntimeError(f"Unsupported video snapshot schema_version: {schema_version!r}")
|
|
13
|
+
return schema
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def get_volume_snapshot_schema(schema_version: str) -> VolumeSnapshotSchema:
|
|
17
|
+
schema = _VOLUME_SCHEMAS.get(schema_version)
|
|
18
|
+
if schema is None:
|
|
19
|
+
raise RuntimeError(f"Unsupported volume snapshot schema_version: {schema_version!r}")
|
|
20
|
+
return schema
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
class VersionSchemaField:
|
|
2
|
+
"""String constants used as column names across snapshot table schemas."""
|
|
3
|
+
|
|
4
|
+
SCHEMA_VERSION = "schema_version"
|
|
5
|
+
TABLES = "tables"
|
|
6
|
+
NAME = "name"
|
|
7
|
+
PATH = "path"
|
|
8
|
+
ROW_COUNT = "row_count"
|
|
9
|
+
SRC_DATASET_ID = "src_dataset_id"
|
|
10
|
+
PARENT_SRC_DATASET_ID = "parent_src_dataset_id"
|
|
11
|
+
FULL_PATH = "full_path"
|
|
12
|
+
DESCRIPTION = "description"
|
|
13
|
+
SRC_VIDEO_ID = "src_video_id"
|
|
14
|
+
SRC_VOLUME_ID = "src_volume_id"
|
|
15
|
+
HASH = "hash"
|
|
16
|
+
LINK = "link"
|
|
17
|
+
FRAMES_COUNT = "frames_count"
|
|
18
|
+
FRAME_WIDTH = "frame_width"
|
|
19
|
+
FRAME_HEIGHT = "frame_height"
|
|
20
|
+
FRAMES_TO_TIMECODES = "frames_to_timecodes"
|
|
21
|
+
META = "meta"
|
|
22
|
+
CUSTOM_DATA = "custom_data"
|
|
23
|
+
CREATED_AT = "created_at"
|
|
24
|
+
UPDATED_AT = "updated_at"
|
|
25
|
+
ANN_JSON = "ann_json"
|
|
26
|
+
JSON = "json"
|
|
27
|
+
ANNOTATION = "annotation"
|
|
28
|
+
SRC_OBJECT_ID = "src_object_id"
|
|
29
|
+
CLASS_NAME = "class_name"
|
|
30
|
+
KEY = "key"
|
|
31
|
+
TAGS_JSON = "tags_json"
|
|
32
|
+
SRC_FIGURE_ID = "src_figure_id"
|
|
33
|
+
FRAME_INDEX = "frame_index"
|
|
34
|
+
GEOMETRY_TYPE = "geometry_type"
|
|
35
|
+
GEOMETRY_JSON = "geometry_json"
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Any, Dict, List, Optional
|
|
6
|
+
|
|
7
|
+
from supervisely.project.versioning.schema_fields import VersionSchemaField
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@dataclass(frozen=True)
|
|
11
|
+
class VideoSnapshotSchema:
|
|
12
|
+
schema_version: str
|
|
13
|
+
|
|
14
|
+
def datasets_schema(self, pa_module):
|
|
15
|
+
return pa_module.schema(
|
|
16
|
+
[
|
|
17
|
+
(VersionSchemaField.SRC_DATASET_ID, pa_module.int64()),
|
|
18
|
+
(VersionSchemaField.PARENT_SRC_DATASET_ID, pa_module.int64()),
|
|
19
|
+
(VersionSchemaField.NAME, pa_module.utf8()),
|
|
20
|
+
(VersionSchemaField.FULL_PATH, pa_module.utf8()),
|
|
21
|
+
(VersionSchemaField.DESCRIPTION, pa_module.utf8()),
|
|
22
|
+
(VersionSchemaField.CUSTOM_DATA, pa_module.utf8()),
|
|
23
|
+
]
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
def videos_schema(self, pa_module):
|
|
27
|
+
return pa_module.schema(
|
|
28
|
+
[
|
|
29
|
+
(VersionSchemaField.SRC_VIDEO_ID, pa_module.int64()),
|
|
30
|
+
(VersionSchemaField.SRC_DATASET_ID, pa_module.int64()),
|
|
31
|
+
(VersionSchemaField.NAME, pa_module.utf8()),
|
|
32
|
+
(VersionSchemaField.HASH, pa_module.utf8()),
|
|
33
|
+
(VersionSchemaField.LINK, pa_module.utf8()),
|
|
34
|
+
(VersionSchemaField.FRAMES_COUNT, pa_module.int32()),
|
|
35
|
+
(VersionSchemaField.FRAME_WIDTH, pa_module.int32()),
|
|
36
|
+
(VersionSchemaField.FRAME_HEIGHT, pa_module.int32()),
|
|
37
|
+
(VersionSchemaField.FRAMES_TO_TIMECODES, pa_module.utf8()),
|
|
38
|
+
(VersionSchemaField.META, pa_module.utf8()),
|
|
39
|
+
(VersionSchemaField.CUSTOM_DATA, pa_module.utf8()),
|
|
40
|
+
(VersionSchemaField.CREATED_AT, pa_module.utf8()),
|
|
41
|
+
(VersionSchemaField.UPDATED_AT, pa_module.utf8()),
|
|
42
|
+
(VersionSchemaField.ANN_JSON, pa_module.utf8()),
|
|
43
|
+
]
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def objects_schema(self, pa_module):
|
|
47
|
+
return pa_module.schema(
|
|
48
|
+
[
|
|
49
|
+
(VersionSchemaField.SRC_OBJECT_ID, pa_module.int64()),
|
|
50
|
+
(VersionSchemaField.SRC_VIDEO_ID, pa_module.int64()),
|
|
51
|
+
(VersionSchemaField.CLASS_NAME, pa_module.utf8()),
|
|
52
|
+
(VersionSchemaField.KEY, pa_module.utf8()),
|
|
53
|
+
(VersionSchemaField.TAGS_JSON, pa_module.utf8()),
|
|
54
|
+
]
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
def figures_schema(self, pa_module):
|
|
58
|
+
return pa_module.schema(
|
|
59
|
+
[
|
|
60
|
+
(VersionSchemaField.SRC_FIGURE_ID, pa_module.int64()),
|
|
61
|
+
(VersionSchemaField.SRC_OBJECT_ID, pa_module.int64()),
|
|
62
|
+
(VersionSchemaField.SRC_VIDEO_ID, pa_module.int64()),
|
|
63
|
+
(VersionSchemaField.FRAME_INDEX, pa_module.int32()),
|
|
64
|
+
(VersionSchemaField.GEOMETRY_TYPE, pa_module.utf8()),
|
|
65
|
+
(VersionSchemaField.GEOMETRY_JSON, pa_module.utf8()),
|
|
66
|
+
]
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
def dataset_row(
|
|
70
|
+
self,
|
|
71
|
+
*,
|
|
72
|
+
src_dataset_id: int,
|
|
73
|
+
parent_src_dataset_id: Optional[int],
|
|
74
|
+
name: str,
|
|
75
|
+
full_path: str,
|
|
76
|
+
description: Optional[str],
|
|
77
|
+
custom_data: Optional[dict],
|
|
78
|
+
) -> Dict[str, Any]:
|
|
79
|
+
return {
|
|
80
|
+
VersionSchemaField.SRC_DATASET_ID: src_dataset_id,
|
|
81
|
+
VersionSchemaField.PARENT_SRC_DATASET_ID: parent_src_dataset_id,
|
|
82
|
+
VersionSchemaField.NAME: name,
|
|
83
|
+
VersionSchemaField.FULL_PATH: full_path,
|
|
84
|
+
VersionSchemaField.DESCRIPTION: description,
|
|
85
|
+
VersionSchemaField.CUSTOM_DATA: (
|
|
86
|
+
json.dumps(custom_data) if isinstance(custom_data, dict) and len(custom_data) > 0 else None
|
|
87
|
+
),
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
def video_row(
|
|
91
|
+
self,
|
|
92
|
+
*,
|
|
93
|
+
src_video_id: int,
|
|
94
|
+
src_dataset_id: int,
|
|
95
|
+
name: str,
|
|
96
|
+
hash: Optional[str],
|
|
97
|
+
link: Optional[str],
|
|
98
|
+
frames_count: Optional[int],
|
|
99
|
+
frame_width: Optional[int],
|
|
100
|
+
frame_height: Optional[int],
|
|
101
|
+
frames_to_timecodes: Optional[list],
|
|
102
|
+
meta: Optional[dict],
|
|
103
|
+
custom_data: Optional[dict],
|
|
104
|
+
created_at: Optional[str],
|
|
105
|
+
updated_at: Optional[str],
|
|
106
|
+
ann_json: dict,
|
|
107
|
+
) -> Dict[str, Any]:
|
|
108
|
+
return {
|
|
109
|
+
VersionSchemaField.SRC_VIDEO_ID: src_video_id,
|
|
110
|
+
VersionSchemaField.SRC_DATASET_ID: src_dataset_id,
|
|
111
|
+
VersionSchemaField.NAME: name,
|
|
112
|
+
VersionSchemaField.HASH: hash,
|
|
113
|
+
VersionSchemaField.LINK: link,
|
|
114
|
+
VersionSchemaField.FRAMES_COUNT: frames_count,
|
|
115
|
+
VersionSchemaField.FRAME_WIDTH: frame_width,
|
|
116
|
+
VersionSchemaField.FRAME_HEIGHT: frame_height,
|
|
117
|
+
VersionSchemaField.FRAMES_TO_TIMECODES: (
|
|
118
|
+
json.dumps(frames_to_timecodes) if frames_to_timecodes else None
|
|
119
|
+
),
|
|
120
|
+
VersionSchemaField.META: json.dumps(meta) if meta else None,
|
|
121
|
+
VersionSchemaField.CUSTOM_DATA: json.dumps(custom_data) if custom_data else None,
|
|
122
|
+
VersionSchemaField.CREATED_AT: created_at,
|
|
123
|
+
VersionSchemaField.UPDATED_AT: updated_at,
|
|
124
|
+
VersionSchemaField.ANN_JSON: json.dumps(ann_json),
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
def object_row(
|
|
128
|
+
self,
|
|
129
|
+
*,
|
|
130
|
+
src_object_id: int,
|
|
131
|
+
src_video_id: int,
|
|
132
|
+
class_name: str,
|
|
133
|
+
key_hex: str,
|
|
134
|
+
tags_json: Optional[List[Dict[str, Any]]],
|
|
135
|
+
) -> Dict[str, Any]:
|
|
136
|
+
return {
|
|
137
|
+
VersionSchemaField.SRC_OBJECT_ID: src_object_id,
|
|
138
|
+
VersionSchemaField.SRC_VIDEO_ID: src_video_id,
|
|
139
|
+
VersionSchemaField.CLASS_NAME: class_name,
|
|
140
|
+
VersionSchemaField.KEY: key_hex,
|
|
141
|
+
VersionSchemaField.TAGS_JSON: json.dumps(tags_json) if tags_json is not None else None,
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
def figure_row(
|
|
145
|
+
self,
|
|
146
|
+
*,
|
|
147
|
+
src_figure_id: int,
|
|
148
|
+
src_object_id: int,
|
|
149
|
+
src_video_id: int,
|
|
150
|
+
frame_index: int,
|
|
151
|
+
geometry_type: str,
|
|
152
|
+
geometry_json: dict,
|
|
153
|
+
) -> Dict[str, Any]:
|
|
154
|
+
return {
|
|
155
|
+
VersionSchemaField.SRC_FIGURE_ID: src_figure_id,
|
|
156
|
+
VersionSchemaField.SRC_OBJECT_ID: src_object_id,
|
|
157
|
+
VersionSchemaField.SRC_VIDEO_ID: src_video_id,
|
|
158
|
+
VersionSchemaField.FRAME_INDEX: frame_index,
|
|
159
|
+
VersionSchemaField.GEOMETRY_TYPE: geometry_type,
|
|
160
|
+
VersionSchemaField.GEOMETRY_JSON: json.dumps(geometry_json),
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
def dataset_row_from_ds_info(self, ds_info, *, full_path: str, custom_data: Optional[dict]):
|
|
164
|
+
return self.dataset_row(
|
|
165
|
+
src_dataset_id=ds_info.id,
|
|
166
|
+
parent_src_dataset_id=ds_info.parent_id,
|
|
167
|
+
name=ds_info.name,
|
|
168
|
+
full_path=full_path,
|
|
169
|
+
description=getattr(ds_info, "description", None),
|
|
170
|
+
custom_data=custom_data,
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
def video_row_from_video_info(self, video_info, *, src_dataset_id: int, ann_json: dict):
|
|
174
|
+
return self.video_row(
|
|
175
|
+
src_video_id=video_info.id,
|
|
176
|
+
src_dataset_id=src_dataset_id,
|
|
177
|
+
name=video_info.name,
|
|
178
|
+
hash=getattr(video_info, "hash", None),
|
|
179
|
+
link=getattr(video_info, "link", None),
|
|
180
|
+
frames_count=getattr(video_info, "frames_count", None),
|
|
181
|
+
frame_width=getattr(video_info, "frame_width", None),
|
|
182
|
+
frame_height=getattr(video_info, "frame_height", None),
|
|
183
|
+
frames_to_timecodes=getattr(video_info, "frames_to_timecodes", None),
|
|
184
|
+
meta=getattr(video_info, "meta", None),
|
|
185
|
+
custom_data=getattr(video_info, "custom_data", None),
|
|
186
|
+
created_at=getattr(video_info, "created_at", None),
|
|
187
|
+
updated_at=getattr(video_info, "updated_at", None),
|
|
188
|
+
ann_json=ann_json,
|
|
189
|
+
)
|
|
190
|
+
|
|
191
|
+
def object_row_from_object(self, obj, *, src_object_id: int, src_video_id: int) -> Dict[str, Any]:
|
|
192
|
+
return self.object_row(
|
|
193
|
+
src_object_id=src_object_id,
|
|
194
|
+
src_video_id=src_video_id,
|
|
195
|
+
class_name=obj.obj_class.name,
|
|
196
|
+
key_hex=obj.key().hex,
|
|
197
|
+
tags_json=obj.tags.to_json() if getattr(obj, "tags", None) is not None else None,
|
|
198
|
+
)
|
|
199
|
+
|
|
200
|
+
def figure_row_from_figure(
|
|
201
|
+
self,
|
|
202
|
+
fig,
|
|
203
|
+
*,
|
|
204
|
+
figure_row_idx: int,
|
|
205
|
+
src_object_id: int,
|
|
206
|
+
src_video_id: int,
|
|
207
|
+
frame_index: int,
|
|
208
|
+
) -> Dict[str, Any]:
|
|
209
|
+
return self.figure_row(
|
|
210
|
+
src_figure_id=figure_row_idx + 1,
|
|
211
|
+
src_object_id=src_object_id,
|
|
212
|
+
src_video_id=src_video_id,
|
|
213
|
+
frame_index=frame_index,
|
|
214
|
+
geometry_type=fig.geometry.geometry_name(),
|
|
215
|
+
geometry_json=fig.geometry.to_json(),
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
_VIDEO_SCHEMAS: Dict[str, VideoSnapshotSchema] = {
|
|
219
|
+
"v2.0.0": VideoSnapshotSchema(schema_version="v2.0.0"),
|
|
220
|
+
}
|
|
221
|
+
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from dataclasses import dataclass
|
|
5
|
+
from typing import Any, Dict
|
|
6
|
+
|
|
7
|
+
from supervisely.api.api import Api
|
|
8
|
+
from supervisely.api.module_api import ApiField
|
|
9
|
+
from supervisely.geometry.mask_3d import Mask3D
|
|
10
|
+
from supervisely.project.data_version import VersionSchemaField
|
|
11
|
+
from supervisely.project.project_meta import ProjectMeta
|
|
12
|
+
from supervisely.project.versioning.schema_fields import VersionSchemaField
|
|
13
|
+
from supervisely.video_annotation.key_id_map import KeyIdMap
|
|
14
|
+
from supervisely.volume_annotation.volume_annotation import VolumeAnnotation
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
@dataclass(frozen=True)
|
|
18
|
+
class VolumeSnapshotSchema:
|
|
19
|
+
schema_version: str
|
|
20
|
+
|
|
21
|
+
def datasets_table_schema(self, pa_module):
|
|
22
|
+
return pa_module.schema(
|
|
23
|
+
[
|
|
24
|
+
(VersionSchemaField.SRC_DATASET_ID, pa_module.int64()),
|
|
25
|
+
(VersionSchemaField.JSON, pa_module.large_string()),
|
|
26
|
+
]
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
def volumes_table_schema(self, pa_module):
|
|
30
|
+
return pa_module.schema(
|
|
31
|
+
[
|
|
32
|
+
(VersionSchemaField.SRC_VOLUME_ID, pa_module.int64()),
|
|
33
|
+
(VersionSchemaField.SRC_DATASET_ID, pa_module.int64()),
|
|
34
|
+
(VersionSchemaField.JSON, pa_module.large_string()),
|
|
35
|
+
]
|
|
36
|
+
)
|
|
37
|
+
|
|
38
|
+
def annotations_table_schema(self, pa_module):
|
|
39
|
+
return pa_module.schema(
|
|
40
|
+
[
|
|
41
|
+
(VersionSchemaField.SRC_VOLUME_ID, pa_module.int64()),
|
|
42
|
+
(VersionSchemaField.ANNOTATION, pa_module.large_string()),
|
|
43
|
+
]
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
def dataset_row_from_record(self, dataset_record: dict) -> Dict[str, Any]:
|
|
47
|
+
return {
|
|
48
|
+
VersionSchemaField.SRC_DATASET_ID: dataset_record.get(ApiField.ID),
|
|
49
|
+
VersionSchemaField.JSON: json.dumps(dataset_record, ensure_ascii=False),
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
def volume_row_from_record(self, volume_record: dict) -> Dict[str, Any]:
|
|
53
|
+
return {
|
|
54
|
+
VersionSchemaField.SRC_VOLUME_ID: volume_record.get(ApiField.ID),
|
|
55
|
+
VersionSchemaField.SRC_DATASET_ID: volume_record.get(ApiField.DATASET_ID),
|
|
56
|
+
VersionSchemaField.JSON: json.dumps(volume_record, ensure_ascii=False),
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
def annotation_row_from_dict(self, *, src_volume_id: int, annotation: dict) -> Dict[str, Any]:
|
|
60
|
+
return {
|
|
61
|
+
VersionSchemaField.SRC_VOLUME_ID: src_volume_id,
|
|
62
|
+
VersionSchemaField.ANNOTATION: json.dumps(annotation, ensure_ascii=False),
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
def annotation_dict_from_raw(
|
|
66
|
+
self,
|
|
67
|
+
*,
|
|
68
|
+
api: Api,
|
|
69
|
+
raw_ann_json: dict,
|
|
70
|
+
project_meta_obj: ProjectMeta,
|
|
71
|
+
key_id_map: KeyIdMap,
|
|
72
|
+
) -> dict:
|
|
73
|
+
ann = VolumeAnnotation.from_json(raw_ann_json, project_meta_obj, key_id_map)
|
|
74
|
+
self._load_mask_geometries(api, ann, key_id_map)
|
|
75
|
+
return ann.to_json()
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def _load_mask_geometries(api: Api, ann: VolumeAnnotation, key_id_map: KeyIdMap) -> None:
|
|
79
|
+
for sf in ann.spatial_figures:
|
|
80
|
+
if sf.geometry.name() != Mask3D.name():
|
|
81
|
+
continue
|
|
82
|
+
api.volume.figure.load_sf_geometry(sf, key_id_map)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
_VOLUME_SCHEMAS: Dict[str, VolumeSnapshotSchema] = {
|
|
86
|
+
"v2.0.0": VolumeSnapshotSchema(schema_version="v2.0.0"),
|
|
87
|
+
}
|