lightly-studio 0.3.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.
Potentially problematic release.
This version of lightly-studio might be problematic. Click here for more details.
- lightly_studio/__init__.py +11 -0
- lightly_studio/api/__init__.py +0 -0
- lightly_studio/api/app.py +110 -0
- lightly_studio/api/cache.py +77 -0
- lightly_studio/api/db.py +133 -0
- lightly_studio/api/db_tables.py +32 -0
- lightly_studio/api/features.py +7 -0
- lightly_studio/api/routes/api/annotation.py +233 -0
- lightly_studio/api/routes/api/annotation_label.py +90 -0
- lightly_studio/api/routes/api/annotation_task.py +38 -0
- lightly_studio/api/routes/api/classifier.py +387 -0
- lightly_studio/api/routes/api/dataset.py +182 -0
- lightly_studio/api/routes/api/dataset_tag.py +257 -0
- lightly_studio/api/routes/api/exceptions.py +96 -0
- lightly_studio/api/routes/api/features.py +17 -0
- lightly_studio/api/routes/api/metadata.py +37 -0
- lightly_studio/api/routes/api/metrics.py +80 -0
- lightly_studio/api/routes/api/sample.py +196 -0
- lightly_studio/api/routes/api/settings.py +45 -0
- lightly_studio/api/routes/api/status.py +19 -0
- lightly_studio/api/routes/api/text_embedding.py +48 -0
- lightly_studio/api/routes/api/validators.py +17 -0
- lightly_studio/api/routes/healthz.py +13 -0
- lightly_studio/api/routes/images.py +104 -0
- lightly_studio/api/routes/webapp.py +51 -0
- lightly_studio/api/server.py +82 -0
- lightly_studio/core/__init__.py +0 -0
- lightly_studio/core/dataset.py +523 -0
- lightly_studio/core/sample.py +77 -0
- lightly_studio/core/start_gui.py +15 -0
- lightly_studio/dataset/__init__.py +0 -0
- lightly_studio/dataset/edge_embedding_generator.py +144 -0
- lightly_studio/dataset/embedding_generator.py +91 -0
- lightly_studio/dataset/embedding_manager.py +163 -0
- lightly_studio/dataset/env.py +16 -0
- lightly_studio/dataset/file_utils.py +35 -0
- lightly_studio/dataset/loader.py +622 -0
- lightly_studio/dataset/mobileclip_embedding_generator.py +144 -0
- lightly_studio/dist_lightly_studio_view_app/_app/env.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/0.DenzbfeK.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/LightlyLogo.BNjCIww-.png +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans- +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Bold.DGvYQtcs.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Italic-VariableFont_wdth_wght.B4AZ-wl6.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-Regular.DxJTClRG.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-SemiBold.D3TTYgdB.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/OpenSans-VariableFont_wdth_wght.BZBpG5Iz.ttf +0 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/SelectableSvgGroup.OwPEPQZu.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/SelectableSvgGroup.b653GmVf.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.T-zjSUd3.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/useFeatureFlags.CV-KWLNP.css +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/69_IOA4Y.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/B2FVR0s0.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/B90CZVMX.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/B9zumHo5.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BJXwVxaE.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Bsi3UGy5.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Bu7uvVrG.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Bx1xMsFy.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BylOuP6i.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C8I8rFJQ.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CDnpyLsT.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CWj6FrbW.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CYgJF_JY.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CcaPhhk3.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CvOmgdoc.js +93 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CxtLVaYz.js +3 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D5-A_Ffd.js +4 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D6RI2Zrd.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D6su9Aln.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D98V7j6A.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DIRAtgl0.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DIeogL5L.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DOlTMNyt.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DjUWrjOv.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DjfY96ND.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/H7C68rOM.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/O-EABkf9.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/XO7A28GO.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/hQVEETDE.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/l7KrR96u.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/nAHhluT7.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/r64xT6ao.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/vC4nQVEB.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/x9G_hzyY.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/app.CjnvpsmS.js +2 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/start.0o1H7wM9.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/0.XRq_TUwu.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/1.B4rNYwVp.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/10.DfBwOEhN.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/11.CWG1ehzT.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/12.CwF2_8mP.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/2.CS4muRY-.js +6 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/3.CWHpKonm.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/4.OUWOLQeV.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/5.Dm6t9F5W.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/6.Bw5ck4gK.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/7.CF0EDTR6.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/8.Cw30LEcV.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/9.CPu3CiBc.js +1 -0
- lightly_studio/dist_lightly_studio_view_app/_app/version.json +1 -0
- lightly_studio/dist_lightly_studio_view_app/apple-touch-icon-precomposed.png +0 -0
- lightly_studio/dist_lightly_studio_view_app/apple-touch-icon.png +0 -0
- lightly_studio/dist_lightly_studio_view_app/favicon.png +0 -0
- lightly_studio/dist_lightly_studio_view_app/index.html +44 -0
- lightly_studio/examples/example.py +23 -0
- lightly_studio/examples/example_metadata.py +338 -0
- lightly_studio/examples/example_selection.py +39 -0
- lightly_studio/examples/example_split_work.py +67 -0
- lightly_studio/examples/example_v2.py +21 -0
- lightly_studio/export_schema.py +18 -0
- lightly_studio/few_shot_classifier/__init__.py +0 -0
- lightly_studio/few_shot_classifier/classifier.py +80 -0
- lightly_studio/few_shot_classifier/classifier_manager.py +663 -0
- lightly_studio/few_shot_classifier/random_forest_classifier.py +489 -0
- lightly_studio/metadata/complex_metadata.py +47 -0
- lightly_studio/metadata/gps_coordinate.py +41 -0
- lightly_studio/metadata/metadata_protocol.py +17 -0
- lightly_studio/metrics/__init__.py +0 -0
- lightly_studio/metrics/detection/__init__.py +0 -0
- lightly_studio/metrics/detection/map.py +268 -0
- lightly_studio/models/__init__.py +1 -0
- lightly_studio/models/annotation/__init__.py +0 -0
- lightly_studio/models/annotation/annotation_base.py +171 -0
- lightly_studio/models/annotation/instance_segmentation.py +56 -0
- lightly_studio/models/annotation/links.py +17 -0
- lightly_studio/models/annotation/object_detection.py +47 -0
- lightly_studio/models/annotation/semantic_segmentation.py +44 -0
- lightly_studio/models/annotation_label.py +47 -0
- lightly_studio/models/annotation_task.py +28 -0
- lightly_studio/models/classifier.py +20 -0
- lightly_studio/models/dataset.py +84 -0
- lightly_studio/models/embedding_model.py +30 -0
- lightly_studio/models/metadata.py +208 -0
- lightly_studio/models/sample.py +180 -0
- lightly_studio/models/sample_embedding.py +37 -0
- lightly_studio/models/settings.py +60 -0
- lightly_studio/models/tag.py +96 -0
- lightly_studio/py.typed +0 -0
- lightly_studio/resolvers/__init__.py +7 -0
- lightly_studio/resolvers/annotation_label_resolver/__init__.py +21 -0
- lightly_studio/resolvers/annotation_label_resolver/create.py +27 -0
- lightly_studio/resolvers/annotation_label_resolver/delete.py +28 -0
- lightly_studio/resolvers/annotation_label_resolver/get_all.py +22 -0
- lightly_studio/resolvers/annotation_label_resolver/get_by_id.py +24 -0
- lightly_studio/resolvers/annotation_label_resolver/get_by_ids.py +25 -0
- lightly_studio/resolvers/annotation_label_resolver/get_by_label_name.py +24 -0
- lightly_studio/resolvers/annotation_label_resolver/names_by_ids.py +25 -0
- lightly_studio/resolvers/annotation_label_resolver/update.py +38 -0
- lightly_studio/resolvers/annotation_resolver/__init__.py +33 -0
- lightly_studio/resolvers/annotation_resolver/count_annotations_by_dataset.py +120 -0
- lightly_studio/resolvers/annotation_resolver/create.py +19 -0
- lightly_studio/resolvers/annotation_resolver/create_many.py +96 -0
- lightly_studio/resolvers/annotation_resolver/delete_annotation.py +45 -0
- lightly_studio/resolvers/annotation_resolver/delete_annotations.py +56 -0
- lightly_studio/resolvers/annotation_resolver/get_all.py +74 -0
- lightly_studio/resolvers/annotation_resolver/get_by_id.py +18 -0
- lightly_studio/resolvers/annotation_resolver/update_annotation_label.py +144 -0
- lightly_studio/resolvers/annotation_resolver/update_bounding_box.py +68 -0
- lightly_studio/resolvers/annotation_task_resolver.py +31 -0
- lightly_studio/resolvers/annotations/__init__.py +1 -0
- lightly_studio/resolvers/annotations/annotations_filter.py +89 -0
- lightly_studio/resolvers/dataset_resolver.py +278 -0
- lightly_studio/resolvers/embedding_model_resolver.py +100 -0
- lightly_studio/resolvers/metadata_resolver/__init__.py +15 -0
- lightly_studio/resolvers/metadata_resolver/metadata_filter.py +163 -0
- lightly_studio/resolvers/metadata_resolver/sample/__init__.py +21 -0
- lightly_studio/resolvers/metadata_resolver/sample/bulk_set_metadata.py +48 -0
- lightly_studio/resolvers/metadata_resolver/sample/get_by_sample_id.py +24 -0
- lightly_studio/resolvers/metadata_resolver/sample/get_metadata_info.py +104 -0
- lightly_studio/resolvers/metadata_resolver/sample/get_value_for_sample.py +27 -0
- lightly_studio/resolvers/metadata_resolver/sample/set_value_for_sample.py +53 -0
- lightly_studio/resolvers/sample_embedding_resolver.py +86 -0
- lightly_studio/resolvers/sample_resolver.py +249 -0
- lightly_studio/resolvers/samples_filter.py +81 -0
- lightly_studio/resolvers/settings_resolver.py +58 -0
- lightly_studio/resolvers/tag_resolver.py +276 -0
- lightly_studio/selection/README.md +6 -0
- lightly_studio/selection/mundig.py +105 -0
- lightly_studio/selection/select.py +96 -0
- lightly_studio/selection/select_via_db.py +93 -0
- lightly_studio/selection/selection_config.py +31 -0
- lightly_studio/services/annotations_service/__init__.py +21 -0
- lightly_studio/services/annotations_service/get_annotation_by_id.py +31 -0
- lightly_studio/services/annotations_service/update_annotation.py +65 -0
- lightly_studio/services/annotations_service/update_annotation_label.py +48 -0
- lightly_studio/services/annotations_service/update_annotations.py +29 -0
- lightly_studio/setup_logging.py +19 -0
- lightly_studio/type_definitions.py +19 -0
- lightly_studio/vendor/ACKNOWLEDGEMENTS +422 -0
- lightly_studio/vendor/LICENSE +31 -0
- lightly_studio/vendor/LICENSE_weights_data +50 -0
- lightly_studio/vendor/README.md +5 -0
- lightly_studio/vendor/__init__.py +1 -0
- lightly_studio/vendor/mobileclip/__init__.py +96 -0
- lightly_studio/vendor/mobileclip/clip.py +77 -0
- lightly_studio/vendor/mobileclip/configs/mobileclip_b.json +18 -0
- lightly_studio/vendor/mobileclip/configs/mobileclip_s0.json +18 -0
- lightly_studio/vendor/mobileclip/configs/mobileclip_s1.json +18 -0
- lightly_studio/vendor/mobileclip/configs/mobileclip_s2.json +18 -0
- lightly_studio/vendor/mobileclip/image_encoder.py +67 -0
- lightly_studio/vendor/mobileclip/logger.py +154 -0
- lightly_studio/vendor/mobileclip/models/__init__.py +10 -0
- lightly_studio/vendor/mobileclip/models/mci.py +933 -0
- lightly_studio/vendor/mobileclip/models/vit.py +433 -0
- lightly_studio/vendor/mobileclip/modules/__init__.py +4 -0
- lightly_studio/vendor/mobileclip/modules/common/__init__.py +4 -0
- lightly_studio/vendor/mobileclip/modules/common/mobileone.py +341 -0
- lightly_studio/vendor/mobileclip/modules/common/transformer.py +451 -0
- lightly_studio/vendor/mobileclip/modules/image/__init__.py +4 -0
- lightly_studio/vendor/mobileclip/modules/image/image_projection.py +113 -0
- lightly_studio/vendor/mobileclip/modules/image/replknet.py +188 -0
- lightly_studio/vendor/mobileclip/modules/text/__init__.py +4 -0
- lightly_studio/vendor/mobileclip/modules/text/repmixer.py +281 -0
- lightly_studio/vendor/mobileclip/modules/text/tokenizer.py +38 -0
- lightly_studio/vendor/mobileclip/text_encoder.py +245 -0
- lightly_studio-0.3.1.dist-info/METADATA +520 -0
- lightly_studio-0.3.1.dist-info/RECORD +219 -0
- lightly_studio-0.3.1.dist-info/WHEEL +4 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""This module contains the Tag model and related enumerations."""
|
|
2
|
+
|
|
3
|
+
from datetime import datetime, timezone
|
|
4
|
+
from typing import TYPE_CHECKING, List, Literal, Optional
|
|
5
|
+
from uuid import UUID, uuid4
|
|
6
|
+
|
|
7
|
+
from sqlalchemy import UniqueConstraint
|
|
8
|
+
from sqlalchemy.orm import Mapped
|
|
9
|
+
from sqlmodel import Field, Relationship, SQLModel, String
|
|
10
|
+
|
|
11
|
+
from lightly_studio.models.annotation.links import AnnotationTagLinkTable
|
|
12
|
+
from lightly_studio.models.sample import SampleTagLinkTable
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from lightly_studio.models.annotation.annotation_base import (
|
|
16
|
+
AnnotationBaseTable,
|
|
17
|
+
)
|
|
18
|
+
from lightly_studio.models.sample import SampleTable
|
|
19
|
+
|
|
20
|
+
else:
|
|
21
|
+
SampleTable = object
|
|
22
|
+
TagTable = object
|
|
23
|
+
AnnotationBaseTable = object
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
# TagKind is the kind of tag we support.
|
|
27
|
+
TagKind = Literal[
|
|
28
|
+
"sample",
|
|
29
|
+
"annotation",
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class TagBase(SQLModel):
|
|
34
|
+
"""Base class for the Tag model."""
|
|
35
|
+
|
|
36
|
+
name: str
|
|
37
|
+
description: Optional[str] = ""
|
|
38
|
+
kind: TagKind = "sample"
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class TagCreate(TagBase):
|
|
42
|
+
"""Tag model when creating."""
|
|
43
|
+
|
|
44
|
+
dataset_id: UUID
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class TagCreateBody(TagBase):
|
|
48
|
+
"""Tag model when creating."""
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
class TagUpdate(TagBase):
|
|
52
|
+
"""Tag model when updating."""
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class TagUpdateBody(TagBase):
|
|
56
|
+
"""Tag model when updating."""
|
|
57
|
+
|
|
58
|
+
dataset_id: Optional[UUID] = None
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
class TagView(TagBase):
|
|
62
|
+
"""Tag model when retrieving."""
|
|
63
|
+
|
|
64
|
+
tag_id: UUID
|
|
65
|
+
kind: TagKind
|
|
66
|
+
created_at: datetime
|
|
67
|
+
updated_at: datetime
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
class TagTable(TagBase, table=True):
|
|
71
|
+
"""This class defines the Tag model."""
|
|
72
|
+
|
|
73
|
+
__tablename__ = "tags"
|
|
74
|
+
# ensure there can only be one tag named "lightly_studio" per dataset
|
|
75
|
+
__table_args__ = (
|
|
76
|
+
UniqueConstraint("dataset_id", "kind", "name", name="unique_name_constraint"),
|
|
77
|
+
)
|
|
78
|
+
tag_id: UUID = Field(default_factory=uuid4, primary_key=True)
|
|
79
|
+
dataset_id: UUID
|
|
80
|
+
kind: TagKind = Field(sa_type=String)
|
|
81
|
+
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc), index=True)
|
|
82
|
+
updated_at: datetime = Field(
|
|
83
|
+
default_factory=lambda: datetime.now(timezone.utc),
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
"""The sample ids associated with the tag."""
|
|
87
|
+
samples: Mapped[List["SampleTable"]] = Relationship(
|
|
88
|
+
back_populates="tags",
|
|
89
|
+
link_model=SampleTagLinkTable,
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
"""The annotation ids associated with the tag (legacy bounding box)."""
|
|
93
|
+
annotations: Mapped[List["AnnotationBaseTable"]] = Relationship(
|
|
94
|
+
back_populates="tags",
|
|
95
|
+
link_model=AnnotationTagLinkTable,
|
|
96
|
+
)
|
lightly_studio/py.typed
ADDED
|
File without changes
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""Handler for database operations related to annotation labels."""
|
|
2
|
+
|
|
3
|
+
from .create import create
|
|
4
|
+
from .delete import delete
|
|
5
|
+
from .get_all import get_all
|
|
6
|
+
from .get_by_id import get_by_id
|
|
7
|
+
from .get_by_ids import get_by_ids
|
|
8
|
+
from .get_by_label_name import get_by_label_name
|
|
9
|
+
from .names_by_ids import names_by_ids
|
|
10
|
+
from .update import update
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
"create",
|
|
14
|
+
"delete",
|
|
15
|
+
"get_all",
|
|
16
|
+
"get_by_id",
|
|
17
|
+
"get_by_ids",
|
|
18
|
+
"get_by_label_name",
|
|
19
|
+
"names_by_ids",
|
|
20
|
+
"update",
|
|
21
|
+
]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"""Create annotation label functionality."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from sqlmodel import Session
|
|
6
|
+
|
|
7
|
+
from lightly_studio.models.annotation_label import (
|
|
8
|
+
AnnotationLabelCreate,
|
|
9
|
+
AnnotationLabelTable,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def create(session: Session, label: AnnotationLabelCreate) -> AnnotationLabelTable:
|
|
14
|
+
"""Create a new annotation label in the database.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
session (Session): The database session.
|
|
18
|
+
label (AnnotationLabelCreate): The annotation label data to be created.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
AnnotationLabelTable: The newly created annotation label record.
|
|
22
|
+
"""
|
|
23
|
+
db_label = AnnotationLabelTable.model_validate(label)
|
|
24
|
+
session.add(db_label)
|
|
25
|
+
session.commit()
|
|
26
|
+
session.refresh(db_label)
|
|
27
|
+
return db_label
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""Delete annotation label functionality."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from sqlmodel import Session
|
|
8
|
+
|
|
9
|
+
from .get_by_id import get_by_id
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def delete(session: Session, label_id: UUID) -> bool:
|
|
13
|
+
"""Delete an annotation label.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
session (Session): The database session.
|
|
17
|
+
label_id (UUID): The unique identifier of the annotation label.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
bool: True if the label was deleted, False if the label was not found.
|
|
21
|
+
"""
|
|
22
|
+
label = get_by_id(session=session, label_id=label_id)
|
|
23
|
+
if not label:
|
|
24
|
+
return False
|
|
25
|
+
|
|
26
|
+
session.delete(label)
|
|
27
|
+
session.commit()
|
|
28
|
+
return True
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Get all annotation labels functionality."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from sqlmodel import Session, col, select
|
|
6
|
+
|
|
7
|
+
from lightly_studio.models.annotation_label import AnnotationLabelTable
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def get_all(session: Session) -> list[AnnotationLabelTable]:
|
|
11
|
+
"""Retrieve all annotation labels.
|
|
12
|
+
|
|
13
|
+
Args:
|
|
14
|
+
session (Session): The database session.
|
|
15
|
+
|
|
16
|
+
Returns:
|
|
17
|
+
list[AnnotationLabelTable]: A list of annotation labels.
|
|
18
|
+
"""
|
|
19
|
+
labels = session.exec(
|
|
20
|
+
select(AnnotationLabelTable).order_by(col(AnnotationLabelTable.created_at).asc())
|
|
21
|
+
).all()
|
|
22
|
+
return list(labels) if labels else []
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Get annotation label by ID functionality."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from sqlmodel import Session, select
|
|
8
|
+
|
|
9
|
+
from lightly_studio.models.annotation_label import AnnotationLabelTable
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_by_id(session: Session, label_id: UUID) -> AnnotationLabelTable | None:
|
|
13
|
+
"""Retrieve a single annotation label by ID.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
session (Session): The database session used to execute the query.
|
|
17
|
+
label_id (UUID): The unique identifier of the annotation label to get.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
AnnotationLabelTable | None: The annotation label if found, or None.
|
|
21
|
+
"""
|
|
22
|
+
return session.exec(
|
|
23
|
+
select(AnnotationLabelTable).where(AnnotationLabelTable.annotation_label_id == label_id)
|
|
24
|
+
).one_or_none()
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Get annotation labels by IDs functionality."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Sequence
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
|
|
8
|
+
from sqlmodel import Session, col, select
|
|
9
|
+
|
|
10
|
+
from lightly_studio.models.annotation_label import AnnotationLabelTable
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_by_ids(session: Session, ids: Sequence[UUID]) -> list[AnnotationLabelTable]:
|
|
14
|
+
"""Retrieve annotation labels by their IDs.
|
|
15
|
+
|
|
16
|
+
Output order matches the input order.
|
|
17
|
+
"""
|
|
18
|
+
results = session.exec(
|
|
19
|
+
select(AnnotationLabelTable).where(
|
|
20
|
+
col(AnnotationLabelTable.annotation_label_id).in_(list(ids))
|
|
21
|
+
)
|
|
22
|
+
).all()
|
|
23
|
+
# Return labels in the same order as the input ids.
|
|
24
|
+
label_map = {label.annotation_label_id: label for label in results}
|
|
25
|
+
return [label_map[id_] for id_ in ids if id_ in label_map]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""Handler for database operations related to annotation labels."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from sqlmodel import Session, select
|
|
6
|
+
|
|
7
|
+
from lightly_studio.models.annotation_label import (
|
|
8
|
+
AnnotationLabelTable,
|
|
9
|
+
)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def get_by_label_name(session: Session, label_name: str) -> AnnotationLabelTable | None:
|
|
13
|
+
"""Retrieve a single annotation label by its name.
|
|
14
|
+
|
|
15
|
+
Args:
|
|
16
|
+
session: The database session to use for the query.
|
|
17
|
+
label_name: The name of the annotation label to retrieve.
|
|
18
|
+
|
|
19
|
+
Returns:
|
|
20
|
+
The AnnotationLabelTable instance if found, None otherwise.
|
|
21
|
+
"""
|
|
22
|
+
return session.exec(
|
|
23
|
+
select(AnnotationLabelTable).where(AnnotationLabelTable.annotation_label_name == label_name)
|
|
24
|
+
).one_or_none()
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
"""Get annotation label names by IDs functionality."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Sequence
|
|
6
|
+
from uuid import UUID
|
|
7
|
+
|
|
8
|
+
from sqlmodel import Session
|
|
9
|
+
|
|
10
|
+
from .get_by_ids import get_by_ids
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def names_by_ids(session: Session, ids: Sequence[UUID]) -> dict[str, str]:
|
|
14
|
+
"""Return a dictionary mapping annotation label IDs to their names.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
session (Session): The database session used to query the labels.
|
|
18
|
+
ids (Sequence[UUID]): A sequence of UUIDs of the annotation label IDs.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
dict[str, str]: A dictionary with string representations of the UUIDs
|
|
22
|
+
and the values are the corresponding annotation label names.
|
|
23
|
+
"""
|
|
24
|
+
labels = get_by_ids(session=session, ids=ids)
|
|
25
|
+
return {str(label.annotation_label_id): label.annotation_label_name for label in labels}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"""Update annotation label functionality."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from sqlmodel import Session
|
|
8
|
+
|
|
9
|
+
from lightly_studio.models.annotation_label import (
|
|
10
|
+
AnnotationLabelCreate,
|
|
11
|
+
AnnotationLabelTable,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
from .get_by_id import get_by_id
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def update(
|
|
18
|
+
session: Session, label_id: UUID, label_data: AnnotationLabelCreate
|
|
19
|
+
) -> AnnotationLabelTable | None:
|
|
20
|
+
"""Update an existing annotation label.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
session (Session): The database session.
|
|
24
|
+
label_id (UUID): The identifier of the annotation label to update.
|
|
25
|
+
label_data (AnnotationLabelCreate): The new data.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
AnnotationLabelTable | None: The updated annotation label if it exists,
|
|
29
|
+
otherwise None.
|
|
30
|
+
"""
|
|
31
|
+
label = get_by_id(session=session, label_id=label_id)
|
|
32
|
+
if not label:
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
label.annotation_label_name = label_data.annotation_label_name
|
|
36
|
+
session.commit()
|
|
37
|
+
session.refresh(label)
|
|
38
|
+
return label
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
"""Resolvers for database operations."""
|
|
2
|
+
|
|
3
|
+
from lightly_studio.resolvers.annotation_resolver.count_annotations_by_dataset import (
|
|
4
|
+
count_annotations_by_dataset,
|
|
5
|
+
)
|
|
6
|
+
from lightly_studio.resolvers.annotation_resolver.create import create
|
|
7
|
+
from lightly_studio.resolvers.annotation_resolver.create_many import create_many
|
|
8
|
+
from lightly_studio.resolvers.annotation_resolver.delete_annotation import (
|
|
9
|
+
delete_annotation,
|
|
10
|
+
)
|
|
11
|
+
from lightly_studio.resolvers.annotation_resolver.delete_annotations import (
|
|
12
|
+
delete_annotations,
|
|
13
|
+
)
|
|
14
|
+
from lightly_studio.resolvers.annotation_resolver.get_all import get_all
|
|
15
|
+
from lightly_studio.resolvers.annotation_resolver.get_by_id import get_by_id
|
|
16
|
+
from lightly_studio.resolvers.annotation_resolver.update_annotation_label import (
|
|
17
|
+
update_annotation_label,
|
|
18
|
+
)
|
|
19
|
+
from lightly_studio.resolvers.annotation_resolver.update_bounding_box import (
|
|
20
|
+
update_bounding_box,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
__all__ = [
|
|
24
|
+
"count_annotations_by_dataset",
|
|
25
|
+
"create",
|
|
26
|
+
"create_many",
|
|
27
|
+
"delete_annotation",
|
|
28
|
+
"delete_annotations",
|
|
29
|
+
"get_all",
|
|
30
|
+
"get_by_id",
|
|
31
|
+
"update_annotation_label",
|
|
32
|
+
"update_bounding_box",
|
|
33
|
+
]
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
"""Handler for database operations related to annotations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from sqlmodel import Session, col, func, select
|
|
8
|
+
|
|
9
|
+
from lightly_studio.models.annotation.annotation_base import (
|
|
10
|
+
AnnotationBaseTable,
|
|
11
|
+
)
|
|
12
|
+
from lightly_studio.models.annotation_label import AnnotationLabelTable
|
|
13
|
+
from lightly_studio.models.sample import SampleTable
|
|
14
|
+
from lightly_studio.models.tag import TagTable
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def count_annotations_by_dataset( # noqa: PLR0913 // FIXME: refactor to use proper pydantic
|
|
18
|
+
session: Session,
|
|
19
|
+
dataset_id: UUID,
|
|
20
|
+
filtered_labels: list[str] | None = None,
|
|
21
|
+
min_width: int | None = None,
|
|
22
|
+
max_width: int | None = None,
|
|
23
|
+
min_height: int | None = None,
|
|
24
|
+
max_height: int | None = None,
|
|
25
|
+
tag_ids: list[UUID] | None = None,
|
|
26
|
+
) -> list[tuple[str, int, int]]:
|
|
27
|
+
"""Count annotations for a specific dataset.
|
|
28
|
+
|
|
29
|
+
Annotations for a specific dataset are grouped by annotation
|
|
30
|
+
label name and counted for total and filtered.
|
|
31
|
+
"""
|
|
32
|
+
# Query for total counts (unfiltered)
|
|
33
|
+
total_counts_query = (
|
|
34
|
+
select(
|
|
35
|
+
AnnotationLabelTable.annotation_label_name,
|
|
36
|
+
func.count(col(AnnotationBaseTable.annotation_id)).label("total_count"),
|
|
37
|
+
)
|
|
38
|
+
.join(
|
|
39
|
+
AnnotationBaseTable,
|
|
40
|
+
col(AnnotationBaseTable.annotation_label_id)
|
|
41
|
+
== col(AnnotationLabelTable.annotation_label_id),
|
|
42
|
+
)
|
|
43
|
+
.join(
|
|
44
|
+
SampleTable,
|
|
45
|
+
col(SampleTable.sample_id) == col(AnnotationBaseTable.sample_id),
|
|
46
|
+
)
|
|
47
|
+
.where(SampleTable.dataset_id == dataset_id)
|
|
48
|
+
.group_by(AnnotationLabelTable.annotation_label_name)
|
|
49
|
+
.order_by(col(AnnotationLabelTable.annotation_label_name).asc())
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
total_counts = {row[0]: row[1] for row in session.exec(total_counts_query).all()}
|
|
53
|
+
|
|
54
|
+
# Build filtered query for current counts
|
|
55
|
+
filtered_query = (
|
|
56
|
+
select(
|
|
57
|
+
AnnotationLabelTable.annotation_label_name,
|
|
58
|
+
func.count(col(AnnotationBaseTable.annotation_id)).label("current_count"),
|
|
59
|
+
)
|
|
60
|
+
.join(
|
|
61
|
+
AnnotationBaseTable,
|
|
62
|
+
col(AnnotationBaseTable.annotation_label_id)
|
|
63
|
+
== col(AnnotationLabelTable.annotation_label_id),
|
|
64
|
+
)
|
|
65
|
+
.join(
|
|
66
|
+
SampleTable,
|
|
67
|
+
col(SampleTable.sample_id) == col(AnnotationBaseTable.sample_id),
|
|
68
|
+
)
|
|
69
|
+
.where(SampleTable.dataset_id == dataset_id)
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
# Add dimension filters
|
|
73
|
+
if min_width is not None:
|
|
74
|
+
filtered_query = filtered_query.where(SampleTable.width >= min_width)
|
|
75
|
+
if max_width is not None:
|
|
76
|
+
filtered_query = filtered_query.where(SampleTable.width <= max_width)
|
|
77
|
+
if min_height is not None:
|
|
78
|
+
filtered_query = filtered_query.where(SampleTable.height >= min_height)
|
|
79
|
+
if max_height is not None:
|
|
80
|
+
filtered_query = filtered_query.where(SampleTable.height <= max_height)
|
|
81
|
+
|
|
82
|
+
# Add label filter if specified
|
|
83
|
+
if filtered_labels:
|
|
84
|
+
filtered_query = filtered_query.where(
|
|
85
|
+
col(SampleTable.sample_id).in_(
|
|
86
|
+
select(SampleTable.sample_id)
|
|
87
|
+
.join(
|
|
88
|
+
AnnotationBaseTable,
|
|
89
|
+
col(SampleTable.sample_id) == col(AnnotationBaseTable.sample_id),
|
|
90
|
+
)
|
|
91
|
+
.join(
|
|
92
|
+
AnnotationLabelTable,
|
|
93
|
+
col(AnnotationBaseTable.annotation_label_id)
|
|
94
|
+
== col(AnnotationLabelTable.annotation_label_id),
|
|
95
|
+
)
|
|
96
|
+
.where(col(AnnotationLabelTable.annotation_label_name).in_(filtered_labels))
|
|
97
|
+
)
|
|
98
|
+
)
|
|
99
|
+
|
|
100
|
+
# filter by tag_ids
|
|
101
|
+
if tag_ids:
|
|
102
|
+
filtered_query = (
|
|
103
|
+
filtered_query.join(AnnotationBaseTable.tags)
|
|
104
|
+
.where(AnnotationBaseTable.tags.any(col(TagTable.tag_id).in_(tag_ids)))
|
|
105
|
+
.distinct()
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Group by label name and sort
|
|
109
|
+
filtered_query = filtered_query.group_by(AnnotationLabelTable.annotation_label_name).order_by(
|
|
110
|
+
col(AnnotationLabelTable.annotation_label_name).asc()
|
|
111
|
+
)
|
|
112
|
+
|
|
113
|
+
_rows = session.exec(filtered_query).all()
|
|
114
|
+
|
|
115
|
+
current_counts = {row[0]: row[1] for row in _rows}
|
|
116
|
+
|
|
117
|
+
return [
|
|
118
|
+
(label, current_counts.get(label, 0), total_count)
|
|
119
|
+
for label, total_count in total_counts.items()
|
|
120
|
+
]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""Handler for database operations related to annotations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from sqlmodel import Session
|
|
6
|
+
|
|
7
|
+
from lightly_studio.models.annotation.annotation_base import (
|
|
8
|
+
AnnotationBaseTable,
|
|
9
|
+
AnnotationCreate,
|
|
10
|
+
)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def create(session: Session, annotation: AnnotationCreate) -> AnnotationBaseTable:
|
|
14
|
+
"""Create a new annotation in the database."""
|
|
15
|
+
db_annotation = AnnotationBaseTable.model_validate(annotation)
|
|
16
|
+
session.add(db_annotation)
|
|
17
|
+
session.commit()
|
|
18
|
+
session.refresh(db_annotation)
|
|
19
|
+
return db_annotation
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""Handler for database operations related to annotations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Sequence
|
|
6
|
+
|
|
7
|
+
from sqlmodel import Session
|
|
8
|
+
|
|
9
|
+
from lightly_studio.models.annotation.annotation_base import (
|
|
10
|
+
AnnotationBaseTable,
|
|
11
|
+
AnnotationCreate,
|
|
12
|
+
)
|
|
13
|
+
from lightly_studio.models.annotation.instance_segmentation import (
|
|
14
|
+
InstanceSegmentationAnnotationTable,
|
|
15
|
+
)
|
|
16
|
+
from lightly_studio.models.annotation.object_detection import (
|
|
17
|
+
ObjectDetectionAnnotationTable,
|
|
18
|
+
)
|
|
19
|
+
from lightly_studio.models.annotation.semantic_segmentation import (
|
|
20
|
+
SemanticSegmentationAnnotationTable,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def create_many(
|
|
25
|
+
session: Session,
|
|
26
|
+
annotations: list[AnnotationCreate],
|
|
27
|
+
) -> Sequence[AnnotationBaseTable]:
|
|
28
|
+
"""Create many annotations with object detection details in bulk."""
|
|
29
|
+
# Step 1: Create all base annotations
|
|
30
|
+
base_annotations = []
|
|
31
|
+
object_detection_annotations = []
|
|
32
|
+
instance_segmentation_annotations = []
|
|
33
|
+
semantic_segmentation_annotations = []
|
|
34
|
+
|
|
35
|
+
for annotation_create in annotations:
|
|
36
|
+
# Create base annotation
|
|
37
|
+
db_base_annotation = AnnotationBaseTable(
|
|
38
|
+
annotation_label_id=annotation_create.annotation_label_id,
|
|
39
|
+
annotation_type=annotation_create.annotation_type,
|
|
40
|
+
annotation_task_id=annotation_create.annotation_task_id,
|
|
41
|
+
confidence=annotation_create.confidence,
|
|
42
|
+
dataset_id=annotation_create.dataset_id,
|
|
43
|
+
sample_id=annotation_create.sample_id,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
# Set other relationship details to None
|
|
47
|
+
db_base_annotation.instance_segmentation_details = None
|
|
48
|
+
db_base_annotation.semantic_segmentation_details = None
|
|
49
|
+
db_base_annotation.object_detection_details = None
|
|
50
|
+
|
|
51
|
+
base_annotations.append(db_base_annotation)
|
|
52
|
+
|
|
53
|
+
# Bulk save base annotations and flush to get IDs
|
|
54
|
+
session.bulk_save_objects(base_annotations)
|
|
55
|
+
session.flush()
|
|
56
|
+
|
|
57
|
+
# Step 2: Create specific annotation details
|
|
58
|
+
for i, annotation_create in enumerate(annotations):
|
|
59
|
+
# Create object detection details
|
|
60
|
+
if base_annotations[i].annotation_type == "object_detection":
|
|
61
|
+
db_object_detection = ObjectDetectionAnnotationTable(
|
|
62
|
+
annotation_id=base_annotations[i].annotation_id,
|
|
63
|
+
x=annotation_create.x,
|
|
64
|
+
y=annotation_create.y,
|
|
65
|
+
width=annotation_create.width,
|
|
66
|
+
height=annotation_create.height,
|
|
67
|
+
)
|
|
68
|
+
object_detection_annotations.append(db_object_detection)
|
|
69
|
+
|
|
70
|
+
# Create instance segmentation details
|
|
71
|
+
elif base_annotations[i].annotation_type == "instance_segmentation":
|
|
72
|
+
db_instance_segmentation = InstanceSegmentationAnnotationTable(
|
|
73
|
+
annotation_id=base_annotations[i].annotation_id,
|
|
74
|
+
segmentation_mask=annotation_create.segmentation_mask,
|
|
75
|
+
x=annotation_create.x,
|
|
76
|
+
y=annotation_create.y,
|
|
77
|
+
width=annotation_create.width,
|
|
78
|
+
height=annotation_create.height,
|
|
79
|
+
)
|
|
80
|
+
instance_segmentation_annotations.append(db_instance_segmentation)
|
|
81
|
+
elif base_annotations[i].annotation_type == "semantic_segmentation":
|
|
82
|
+
db_semantic_segmentation = SemanticSegmentationAnnotationTable(
|
|
83
|
+
annotation_id=base_annotations[i].annotation_id,
|
|
84
|
+
segmentation_mask=annotation_create.segmentation_mask,
|
|
85
|
+
)
|
|
86
|
+
semantic_segmentation_annotations.append(db_semantic_segmentation)
|
|
87
|
+
|
|
88
|
+
# Bulk save object detection annotations
|
|
89
|
+
session.bulk_save_objects(object_detection_annotations)
|
|
90
|
+
session.bulk_save_objects(instance_segmentation_annotations)
|
|
91
|
+
session.bulk_save_objects(semantic_segmentation_annotations)
|
|
92
|
+
|
|
93
|
+
# Commit everything
|
|
94
|
+
session.commit()
|
|
95
|
+
|
|
96
|
+
return base_annotations
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"""Handler for database operations related to annotations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from uuid import UUID
|
|
6
|
+
|
|
7
|
+
from sqlmodel import Session, col, delete
|
|
8
|
+
|
|
9
|
+
from lightly_studio.models.annotation.links import AnnotationTagLinkTable
|
|
10
|
+
from lightly_studio.resolvers import annotation_resolver
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def delete_annotation(
|
|
14
|
+
session: Session,
|
|
15
|
+
annotation_id: UUID,
|
|
16
|
+
) -> None:
|
|
17
|
+
"""Delete all annotations and their tag links using filters.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
session: Database session.
|
|
21
|
+
annotation_id: Annotation ID to filter by.
|
|
22
|
+
"""
|
|
23
|
+
# Find annotation_ids to delete
|
|
24
|
+
annotation = annotation_resolver.get_by_id(
|
|
25
|
+
session,
|
|
26
|
+
annotation_id=annotation_id,
|
|
27
|
+
)
|
|
28
|
+
if not annotation:
|
|
29
|
+
return
|
|
30
|
+
if annotation.object_detection_details:
|
|
31
|
+
session.delete(annotation.object_detection_details)
|
|
32
|
+
if annotation.instance_segmentation_details:
|
|
33
|
+
session.delete(annotation.instance_segmentation_details)
|
|
34
|
+
if annotation.semantic_segmentation_details:
|
|
35
|
+
session.delete(annotation.semantic_segmentation_details)
|
|
36
|
+
|
|
37
|
+
session.exec( # type: ignore
|
|
38
|
+
delete(AnnotationTagLinkTable).where(
|
|
39
|
+
col(AnnotationTagLinkTable.annotation_id).in_([annotation.annotation_id])
|
|
40
|
+
)
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
session.commit()
|
|
44
|
+
session.delete(annotation)
|
|
45
|
+
session.commit()
|