lightly-studio 0.3.2__py3-none-any.whl → 0.3.4__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.

Files changed (163) hide show
  1. lightly_studio/__init__.py +1 -1
  2. lightly_studio/api/app.py +8 -4
  3. lightly_studio/api/db_tables.py +0 -3
  4. lightly_studio/api/routes/api/annotation.py +26 -0
  5. lightly_studio/api/routes/api/annotations/__init__.py +7 -0
  6. lightly_studio/api/routes/api/annotations/create_annotation.py +52 -0
  7. lightly_studio/api/routes/api/caption.py +30 -0
  8. lightly_studio/api/routes/api/dataset.py +3 -5
  9. lightly_studio/api/routes/api/embeddings2d.py +136 -0
  10. lightly_studio/api/routes/api/export.py +73 -0
  11. lightly_studio/api/routes/api/metadata.py +57 -1
  12. lightly_studio/api/routes/api/selection.py +87 -0
  13. lightly_studio/core/add_samples.py +138 -9
  14. lightly_studio/core/dataset.py +174 -63
  15. lightly_studio/core/dataset_query/dataset_query.py +5 -0
  16. lightly_studio/dataset/env.py +4 -0
  17. lightly_studio/dataset/file_utils.py +13 -2
  18. lightly_studio/dataset/loader.py +2 -62
  19. lightly_studio/dataset/mobileclip_embedding_generator.py +3 -2
  20. lightly_studio/db_manager.py +10 -4
  21. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/0.B3oFNb6O.css +1 -0
  22. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/2.CkOblLn7.css +1 -0
  23. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/Samples.CIbricz7.css +1 -0
  24. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.7Ma7YdVg.css +1 -0
  25. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/{useFeatureFlags.CV-KWLNP.css → _layout.CefECEWA.css} +1 -1
  26. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/transform.2jKMtOWG.css +1 -0
  27. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/-DXuGN29.js +1 -0
  28. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{Ccq4ZD0B.js → B7302SU7.js} +1 -1
  29. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BeWf8-vJ.js +1 -0
  30. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Bqz7dyEC.js +1 -0
  31. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C1FmrZbK.js +1 -0
  32. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{DRZO-E-T.js → CSCQddQS.js} +1 -1
  33. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CZGpyrcA.js +1 -0
  34. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CfQ4mGwl.js +1 -0
  35. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CiaNZCBa.js +1 -0
  36. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Cqo0Vpvt.js +417 -0
  37. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Cy4fgWTG.js +1 -0
  38. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D5w4xp5l.js +1 -0
  39. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DD63uD-T.js +1 -0
  40. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DQ8aZ1o-.js +3 -0
  41. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{Df3aMO5B.js → DSxvnAMh.js} +1 -1
  42. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D_JuJOO3.js +20 -0
  43. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D_ynJAfY.js +2 -0
  44. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Dafy4oEQ.js +1 -0
  45. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/{BqBqV92V.js → Dj4O-5se.js} +1 -1
  46. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DmjAI-UV.js +1 -0
  47. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Dug7Bq1S.js +1 -0
  48. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Dv5BSBQG.js +1 -0
  49. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DzBTnFhV.js +1 -0
  50. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DzX_yyqb.js +1 -0
  51. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Frwd2CjB.js +1 -0
  52. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/H4l0JFh9.js +1 -0
  53. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/H60ATh8g.js +2 -0
  54. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/qIv1kPyv.js +1 -0
  55. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/sLqs1uaK.js +20 -0
  56. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/u-it74zV.js +96 -0
  57. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/app.BPc0HQPq.js +2 -0
  58. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/start.SNvc2nrm.js +1 -0
  59. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/0.5jT7P06o.js +1 -0
  60. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/1.Cdy-7S5q.js +1 -0
  61. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/10.C_uoESTX.js +1 -0
  62. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/12.DcO8wIAc.js +1 -0
  63. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/2.BIldfkxL.js +1012 -0
  64. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/{3.w9g4AcAx.js → 3.BC9z_TWM.js} +1 -1
  65. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/{4.BBI8KwnD.js → 4.D8X_Ch5n.js} +1 -1
  66. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/5.CAXhxJu6.js +39 -0
  67. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/{6.CrbkRPam.js → 6.DRA5Ru_2.js} +1 -1
  68. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/7.WVBsruHQ.js +1 -0
  69. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/8.BuKUrCEN.js +20 -0
  70. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/9.CUIn1yCR.js +1 -0
  71. lightly_studio/dist_lightly_studio_view_app/_app/immutable/workers/clustering.worker-DKqeLtG0.js +2 -0
  72. lightly_studio/dist_lightly_studio_view_app/_app/immutable/workers/search.worker-vNSty3B0.js +1 -0
  73. lightly_studio/dist_lightly_studio_view_app/_app/version.json +1 -1
  74. lightly_studio/dist_lightly_studio_view_app/index.html +15 -14
  75. lightly_studio/examples/example.py +4 -0
  76. lightly_studio/examples/example_coco.py +4 -0
  77. lightly_studio/examples/example_coco_caption.py +24 -0
  78. lightly_studio/examples/example_metadata.py +4 -1
  79. lightly_studio/examples/example_selection.py +4 -0
  80. lightly_studio/examples/example_split_work.py +4 -0
  81. lightly_studio/examples/example_yolo.py +4 -0
  82. lightly_studio/export/export_dataset.py +73 -0
  83. lightly_studio/export/lightly_studio_label_input.py +120 -0
  84. lightly_studio/few_shot_classifier/classifier_manager.py +5 -26
  85. lightly_studio/metadata/compute_typicality.py +67 -0
  86. lightly_studio/models/annotation/annotation_base.py +11 -12
  87. lightly_studio/models/caption.py +73 -0
  88. lightly_studio/models/dataset.py +1 -2
  89. lightly_studio/models/metadata.py +1 -1
  90. lightly_studio/models/sample.py +2 -2
  91. lightly_studio/resolvers/annotation_label_resolver/__init__.py +2 -1
  92. lightly_studio/resolvers/annotation_label_resolver/get_all.py +15 -0
  93. lightly_studio/resolvers/annotation_resolver/__init__.py +2 -3
  94. lightly_studio/resolvers/annotation_resolver/create_many.py +3 -3
  95. lightly_studio/resolvers/annotation_resolver/delete_annotation.py +1 -1
  96. lightly_studio/resolvers/annotation_resolver/delete_annotations.py +7 -3
  97. lightly_studio/resolvers/annotation_resolver/get_by_id.py +19 -1
  98. lightly_studio/resolvers/annotation_resolver/update_annotation_label.py +0 -1
  99. lightly_studio/resolvers/annotations/annotations_filter.py +1 -11
  100. lightly_studio/resolvers/caption_resolver.py +80 -0
  101. lightly_studio/resolvers/dataset_resolver.py +4 -7
  102. lightly_studio/resolvers/metadata_resolver/__init__.py +2 -2
  103. lightly_studio/resolvers/metadata_resolver/sample/__init__.py +3 -3
  104. lightly_studio/resolvers/metadata_resolver/sample/bulk_update_metadata.py +46 -0
  105. lightly_studio/resolvers/samples_filter.py +18 -10
  106. lightly_studio/selection/mundig.py +7 -10
  107. lightly_studio/selection/selection_config.py +4 -1
  108. lightly_studio/services/annotations_service/__init__.py +8 -0
  109. lightly_studio/services/annotations_service/create_annotation.py +63 -0
  110. lightly_studio/services/annotations_service/delete_annotation.py +22 -0
  111. lightly_studio/type_definitions.py +2 -0
  112. {lightly_studio-0.3.2.dist-info → lightly_studio-0.3.4.dist-info}/METADATA +231 -41
  113. {lightly_studio-0.3.2.dist-info → lightly_studio-0.3.4.dist-info}/RECORD +114 -104
  114. lightly_studio/api/routes/api/annotation_task.py +0 -37
  115. lightly_studio/api/routes/api/metrics.py +0 -76
  116. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/0.DenzbfeK.css +0 -1
  117. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/SelectableSvgGroup.BBm0IWdq.css +0 -1
  118. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/SelectableSvgGroup.BNTuXSAe.css +0 -1
  119. lightly_studio/dist_lightly_studio_view_app/_app/immutable/assets/_layout.T-zjSUd3.css +0 -1
  120. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/2O287xak.js +0 -3
  121. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/7YNGEs1C.js +0 -1
  122. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BBoGk9hq.js +0 -1
  123. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/BRnH9v23.js +0 -92
  124. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Bg1Y5eUZ.js +0 -1
  125. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C0JiMuYn.js +0 -1
  126. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/C98Hk3r5.js +0 -1
  127. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CG0dMCJi.js +0 -1
  128. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Cpy-nab_.js +0 -1
  129. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Crk-jcvV.js +0 -1
  130. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Cs31G8Qn.js +0 -1
  131. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CsKrY2zA.js +0 -1
  132. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/Cur71c3O.js +0 -1
  133. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/CzgC3GFB.js +0 -1
  134. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/D8GZDMNN.js +0 -1
  135. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DFRh-Spp.js +0 -1
  136. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DcGCxgpH.js +0 -1
  137. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DkR_EZ_B.js +0 -1
  138. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/DqUGznj_.js +0 -1
  139. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/H7C68rOM.js +0 -1
  140. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/KpAtIldw.js +0 -1
  141. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/M1Q1F7bw.js +0 -4
  142. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/OH7-C_mc.js +0 -1
  143. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/gLNdjSzu.js +0 -1
  144. lightly_studio/dist_lightly_studio_view_app/_app/immutable/chunks/i0ZZ4z06.js +0 -1
  145. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/app.BI-EA5gL.js +0 -2
  146. lightly_studio/dist_lightly_studio_view_app/_app/immutable/entry/start.CcsRl3cZ.js +0 -1
  147. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/0.BbO4Zc3r.js +0 -1
  148. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/1._I9GR805.js +0 -1
  149. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/10.J2RBFrSr.js +0 -1
  150. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/12.Cmqj25a-.js +0 -1
  151. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/2.C45iKJHA.js +0 -6
  152. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/5.huHuxdiF.js +0 -1
  153. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/7.FomEdhD6.js +0 -1
  154. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/8.Cb_ADSLk.js +0 -1
  155. lightly_studio/dist_lightly_studio_view_app/_app/immutable/nodes/9.CajIG5ce.js +0 -1
  156. lightly_studio/metrics/__init__.py +0 -0
  157. lightly_studio/metrics/detection/__init__.py +0 -0
  158. lightly_studio/metrics/detection/map.py +0 -268
  159. lightly_studio/models/annotation_task.py +0 -28
  160. lightly_studio/resolvers/annotation_resolver/create.py +0 -19
  161. lightly_studio/resolvers/annotation_task_resolver.py +0 -31
  162. lightly_studio/resolvers/metadata_resolver/sample/bulk_set_metadata.py +0 -48
  163. {lightly_studio-0.3.2.dist-info → lightly_studio-0.3.4.dist-info}/WHEEL +0 -0
@@ -1,268 +0,0 @@
1
- """Implementation for calculating Mean Average Precision (MAP)."""
2
-
3
- from __future__ import annotations
4
-
5
- import math
6
- from collections import defaultdict
7
- from collections.abc import Sequence
8
- from uuid import UUID
9
-
10
- import torch
11
- from pydantic import BaseModel
12
- from torch import Tensor
13
- from torchmetrics.detection.mean_ap import MeanAveragePrecision
14
-
15
- from lightly_studio.models.annotation.annotation_base import AnnotationBaseTable
16
-
17
-
18
- class DetectionMetricsMAP(BaseModel):
19
- """Response for computing the MAP detection metric."""
20
-
21
- name: str
22
- map: float
23
- map_small: float
24
- map_medium: float
25
- map_large: float
26
- mar_1: float
27
- mar_10: float
28
- mar_100: float
29
- mar_small: float
30
- mar_medium: float
31
- mar_large: float
32
- map_50: float
33
- map_75: float
34
- map_per_class: dict[str, float] | None = None
35
- mar_100_per_class: dict[str, float] | None = None
36
- classes: list[int]
37
-
38
- @property
39
- def value(self) -> float:
40
- """Backwards compatibility alias for map."""
41
- return self.map
42
-
43
- @property
44
- def per_class(self) -> dict[str, float] | None:
45
- """Backwards compatibility alias for map_per_class."""
46
- return self.map_per_class
47
-
48
-
49
- def calculate_map_metric( # noqa: C901
50
- pred_annotations: Sequence[AnnotationBaseTable],
51
- gt_annotations: Sequence[AnnotationBaseTable],
52
- ) -> DetectionMetricsMAP:
53
- """Calculate the Mean Average Precision (MAP) metric."""
54
- if not gt_annotations or not pred_annotations:
55
- return DetectionMetricsMAP(
56
- name="mAP@.5:.95",
57
- map=0.0,
58
- map_small=0.0,
59
- map_medium=0.0,
60
- map_large=0.0,
61
- mar_1=0.0,
62
- mar_10=0.0,
63
- mar_100=0.0,
64
- mar_small=0.0,
65
- mar_medium=0.0,
66
- mar_large=0.0,
67
- map_50=-1.0,
68
- map_75=-1.0,
69
- map_per_class=None,
70
- mar_100_per_class=None,
71
- classes=[],
72
- )
73
- uuid_to_int_label: dict[UUID, int] = {}
74
-
75
- # Map sample_id to annotations.
76
- sample_id_to_annotations = _group_by_sample_id(
77
- pred_annotations=pred_annotations,
78
- gt_annotations=gt_annotations,
79
- )
80
-
81
- # Create the MeanAveragePrecision object.
82
- map_metric = MeanAveragePrecision(
83
- box_format="xywh",
84
- iou_thresholds=None,
85
- class_metrics=True,
86
- average="macro",
87
- backend="faster_coco_eval",
88
- )
89
-
90
- # Compute MAP updating the object sample by sample.
91
- for _sample_id, (
92
- sample_pred_annotations,
93
- sample_gt_annotations,
94
- ) in sample_id_to_annotations.items():
95
- # Convert to torchmetrics format.
96
- prediction_tm = _convert_to_torchmetrics(
97
- annotations=sample_pred_annotations,
98
- is_prediction=True,
99
- uuid_to_int_label_map=uuid_to_int_label,
100
- )
101
- ground_truth_tm = _convert_to_torchmetrics(
102
- annotations=sample_gt_annotations,
103
- is_prediction=False,
104
- uuid_to_int_label_map=uuid_to_int_label,
105
- )
106
-
107
- # Update the metric.
108
- map_metric.update(preds=[prediction_tm], target=[ground_truth_tm])
109
-
110
- # Compute the final results.
111
- results = map_metric.compute()
112
- # Invert label map to recover original UUIDs
113
- int_to_uuid = {v: k for k, v in uuid_to_int_label.items()}
114
-
115
- # Helper to convert Tensor to Python list
116
- def to_list(t: Tensor) -> list[float]:
117
- if t.dim() == 0:
118
- return [t.item()]
119
- return t.tolist()
120
-
121
- # Scalar metrics
122
- map_val = results["map"].item()
123
- map_small = results["map_small"].item()
124
- map_medium = results["map_medium"].item()
125
- map_large = results["map_large"].item()
126
- mar_1 = results["mar_1"].item()
127
- mar_10 = results["mar_10"].item()
128
- mar_100 = results["mar_100"].item()
129
- mar_small = results["mar_small"].item()
130
- mar_medium = results["mar_medium"].item()
131
- mar_large = results["mar_large"].item()
132
-
133
- # IoU-specific metrics
134
- map_50 = results.get("map_50")
135
- map_50 = map_50.item() if isinstance(map_50, Tensor) and map_50.dim() == 0 else -1.0
136
- map_75 = results.get("map_75")
137
- map_75 = map_75.item() if isinstance(map_75, Tensor) and map_75.dim() == 0 else -1.0
138
-
139
- # Per-class metrics
140
- raw_map_pc = results.get("map_per_class")
141
- per_class_dict: dict[str, float] | None = None
142
- if raw_map_pc is not None:
143
- pc_list = to_list(raw_map_pc)
144
- per_class_dict = {}
145
- for idx, val in enumerate(pc_list):
146
- if not math.isnan(val):
147
- per_class_dict[str(int_to_uuid[idx])] = val
148
-
149
- # Per-class recall at 100 detections
150
- raw_mar100_pc = results.get("mar_100_per_class")
151
- mar_100_pc_dict: dict[str, float] | None = None
152
- if raw_mar100_pc is not None:
153
- m100_list = to_list(raw_mar100_pc)
154
- mar_100_pc_dict = {}
155
- for idx, val in enumerate(m100_list):
156
- if not math.isnan(val):
157
- mar_100_pc_dict[str(int_to_uuid[idx])] = val
158
-
159
- # Observed classes
160
- raw_classes = results.get("classes")
161
- classes_list_output: list[int] = []
162
- if raw_classes is not None:
163
- classes_list_output = [int(x) for x in to_list(raw_classes)]
164
-
165
- return DetectionMetricsMAP(
166
- name="mAP@.5:.95",
167
- map=map_val,
168
- map_small=map_small,
169
- map_medium=map_medium,
170
- map_large=map_large,
171
- mar_1=mar_1,
172
- mar_10=mar_10,
173
- mar_100=mar_100,
174
- mar_small=mar_small,
175
- mar_medium=mar_medium,
176
- mar_large=mar_large,
177
- map_50=map_50,
178
- map_75=map_75,
179
- map_per_class=per_class_dict,
180
- mar_100_per_class=mar_100_pc_dict,
181
- classes=classes_list_output,
182
- )
183
-
184
-
185
- def _group_by_sample_id(
186
- pred_annotations: Sequence[AnnotationBaseTable],
187
- gt_annotations: Sequence[AnnotationBaseTable],
188
- ) -> dict[
189
- UUID,
190
- tuple[list[AnnotationBaseTable], list[AnnotationBaseTable]],
191
- ]:
192
- """Group prediction and ground truth annotations by sample_id.
193
-
194
- Returns a dictionary with sample_id as key and a tuple of
195
- (list of prediction annotations, list of ground truth annotations) as value.
196
- """
197
- sample_id_to_annotations: defaultdict[
198
- UUID,
199
- tuple[list[AnnotationBaseTable], list[AnnotationBaseTable]],
200
- ] = defaultdict(lambda: ([], []))
201
- for ann in pred_annotations:
202
- sample_id_to_annotations[ann.sample_id][0].append(ann)
203
- for ann in gt_annotations:
204
- sample_id_to_annotations[ann.sample_id][1].append(ann)
205
- return sample_id_to_annotations
206
-
207
-
208
- def _convert_to_torchmetrics(
209
- annotations: Sequence[AnnotationBaseTable],
210
- is_prediction: bool,
211
- uuid_to_int_label_map: dict[UUID, int],
212
- ) -> dict[str, Tensor]:
213
- """Convert annotations to torchmetrics format.
214
-
215
- Args:
216
- annotations: List of bounding box annotations.
217
- is_prediction: Whether the annotations are predictions.
218
- uuid_to_int_label_map: Map from UUID to integer label.
219
-
220
- Returns:
221
- Dictionary in torchmetrics format. For predictions the keys are
222
- `boxes`, `scores`, `labels`. For ground truth they are `boxes`,
223
- `labels`.
224
-
225
- """
226
- if not annotations:
227
- empty_boxes = torch.empty((0, 4), dtype=torch.float32)
228
- empty_labels = torch.empty((0,), dtype=torch.int64)
229
- if is_prediction:
230
- return {
231
- "boxes": empty_boxes,
232
- "scores": torch.empty((0,), dtype=torch.float32),
233
- "labels": empty_labels,
234
- }
235
- return {"boxes": empty_boxes, "labels": empty_labels}
236
-
237
- boxes = torch.tensor(
238
- [
239
- [
240
- a.object_detection_details.x,
241
- a.object_detection_details.y,
242
- a.object_detection_details.width,
243
- a.object_detection_details.height,
244
- ]
245
- for a in annotations
246
- if a.object_detection_details is not None
247
- ],
248
- dtype=torch.float32,
249
- )
250
-
251
- mapped_labels = []
252
- # Use the passed-in map instead of a global one
253
- for uuid_label in (a.annotation_label_id for a in annotations):
254
- if uuid_label not in uuid_to_int_label_map:
255
- # Assign the next available integer ID based on the current map size
256
- uuid_to_int_label_map[uuid_label] = len(uuid_to_int_label_map)
257
- mapped_labels.append(uuid_to_int_label_map[uuid_label])
258
-
259
- labels = torch.tensor(mapped_labels, dtype=torch.int64)
260
-
261
- if is_prediction:
262
- scores = torch.tensor([a.confidence for a in annotations], dtype=torch.float32)
263
- return {
264
- "boxes": boxes,
265
- "scores": scores,
266
- "labels": labels,
267
- }
268
- return {"boxes": boxes, "labels": labels}
@@ -1,28 +0,0 @@
1
- """This module defines the AnnotationTask model."""
2
-
3
- from datetime import datetime
4
- from enum import Enum
5
- from uuid import UUID, uuid4
6
-
7
- from sqlmodel import Field, SQLModel
8
-
9
-
10
- class AnnotationType(str, Enum):
11
- """The type of annotation task."""
12
-
13
- BBOX = "bbox"
14
- CLASSIFICATION = "classification"
15
- SEMANTIC_SEGMENTATION = "semantic_segmentation"
16
- INSTANCE_SEGMENTATION = "instance_segmentation"
17
- OBJECT_DETECTION = "object_detection"
18
-
19
-
20
- class AnnotationTaskTable(SQLModel, table=True):
21
- """The annotation task model."""
22
-
23
- __tablename__ = "annotation_tasks"
24
- annotation_task_id: UUID = Field(default_factory=uuid4, primary_key=True)
25
- name: str
26
- created_at: datetime = Field(default_factory=datetime.utcnow)
27
- annotation_type: AnnotationType
28
- is_prediction: bool
@@ -1,19 +0,0 @@
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
@@ -1,31 +0,0 @@
1
- """Resolver for annotation tasks."""
2
-
3
- from typing import List, Optional, Sequence
4
- from uuid import UUID
5
-
6
- from sqlmodel import Session, col, select
7
-
8
- from lightly_studio.models.annotation_task import AnnotationTaskTable
9
-
10
-
11
- def create(session: Session, annotation_task: AnnotationTaskTable) -> AnnotationTaskTable:
12
- """Create a new annotation task."""
13
- session.add(annotation_task)
14
- session.commit()
15
- session.refresh(annotation_task)
16
- return annotation_task
17
-
18
-
19
- def get_by_id(session: Session, annotation_task_id: UUID) -> Optional[AnnotationTaskTable]:
20
- """Get an annotation task by ID."""
21
- statement = select(AnnotationTaskTable).where(
22
- AnnotationTaskTable.annotation_task_id == annotation_task_id
23
- )
24
- return session.exec(statement).first()
25
-
26
-
27
- def get_all(session: Session) -> List[AnnotationTaskTable]:
28
- """Get all annotation tasks."""
29
- statement = select(AnnotationTaskTable).order_by(col(AnnotationTaskTable.created_at).asc())
30
- results: Sequence[AnnotationTaskTable] = session.exec(statement).all()
31
- return list(results)
@@ -1,48 +0,0 @@
1
- """Resolver for operations for setting metadata."""
2
-
3
- from __future__ import annotations
4
-
5
- from datetime import datetime, timezone
6
- from typing import Any
7
- from uuid import UUID
8
-
9
- from sqlmodel import Session
10
-
11
- from lightly_studio.metadata.complex_metadata import serialize_complex_metadata
12
- from lightly_studio.models.metadata import (
13
- SampleMetadataTable,
14
- get_type_name,
15
- )
16
-
17
-
18
- def bulk_set_metadata(
19
- session: Session,
20
- sample_metadata: list[tuple[UUID, dict[str, Any]]],
21
- ) -> None:
22
- """Bulk insert metadata for multiple samples.
23
-
24
- Args:
25
- session: The database session.
26
- sample_metadata: List of (sample_id, metadata_dict) tuples.
27
- """
28
- now = datetime.now(timezone.utc)
29
- objects = []
30
- for sample_id, metadata in sample_metadata:
31
- metadata_schema = {}
32
- serialized_data = {}
33
- for key, value in metadata.items():
34
- # Serialize complex metadata objects.
35
- serialized_data[key] = serialize_complex_metadata(value)
36
- # Get the type name
37
- metadata_schema[key] = get_type_name(value)
38
-
39
- obj = SampleMetadataTable(
40
- sample_id=sample_id,
41
- data=serialized_data,
42
- metadata_schema=metadata_schema,
43
- created_at=now,
44
- updated_at=now,
45
- )
46
- objects.append(obj)
47
- session.bulk_save_objects(objects)
48
- session.commit()