scale-nucleus 0.1.10__py3-none-any.whl → 0.1.24__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.
- nucleus/__init__.py +259 -162
- nucleus/annotation.py +121 -32
- nucleus/autocurate.py +26 -0
- nucleus/constants.py +43 -5
- nucleus/dataset.py +213 -52
- nucleus/dataset_item.py +139 -26
- nucleus/errors.py +21 -3
- nucleus/job.py +27 -6
- nucleus/model.py +23 -2
- nucleus/model_run.py +56 -14
- nucleus/payload_constructor.py +39 -2
- nucleus/prediction.py +75 -14
- nucleus/scene.py +241 -0
- nucleus/slice.py +24 -15
- nucleus/url_utils.py +22 -0
- nucleus/utils.py +26 -5
- {scale_nucleus-0.1.10.dist-info → scale_nucleus-0.1.24.dist-info}/LICENSE +0 -0
- scale_nucleus-0.1.24.dist-info/METADATA +85 -0
- scale_nucleus-0.1.24.dist-info/RECORD +21 -0
- {scale_nucleus-0.1.10.dist-info → scale_nucleus-0.1.24.dist-info}/WHEEL +1 -1
- scale_nucleus-0.1.10.dist-info/METADATA +0 -236
- scale_nucleus-0.1.10.dist-info/RECORD +0 -18
nucleus/job.py
CHANGED
@@ -1,47 +1,68 @@
|
|
1
1
|
from dataclasses import dataclass
|
2
2
|
import time
|
3
3
|
from typing import Dict, List
|
4
|
-
|
5
4
|
import requests
|
5
|
+
from nucleus.constants import (
|
6
|
+
JOB_CREATION_TIME_KEY,
|
7
|
+
JOB_ID_KEY,
|
8
|
+
JOB_LAST_KNOWN_STATUS_KEY,
|
9
|
+
JOB_TYPE_KEY,
|
10
|
+
STATUS_KEY,
|
11
|
+
)
|
6
12
|
|
7
13
|
JOB_POLLING_INTERVAL = 5
|
8
14
|
|
9
15
|
|
10
16
|
@dataclass
|
11
17
|
class AsyncJob:
|
12
|
-
|
18
|
+
job_id: str
|
19
|
+
job_last_known_status: str
|
20
|
+
job_type: str
|
21
|
+
job_creation_time: str
|
13
22
|
client: "NucleusClient" # type: ignore # noqa: F821
|
14
23
|
|
15
24
|
def status(self) -> Dict[str, str]:
|
16
|
-
|
25
|
+
response = self.client.make_request(
|
17
26
|
payload={},
|
18
|
-
route=f"job/{self.
|
27
|
+
route=f"job/{self.job_id}",
|
19
28
|
requests_command=requests.get,
|
20
29
|
)
|
30
|
+
self.job_last_known_status = response[STATUS_KEY]
|
31
|
+
return response
|
21
32
|
|
22
33
|
def errors(self) -> List[str]:
|
23
34
|
return self.client.make_request(
|
24
35
|
payload={},
|
25
|
-
route=f"job/{self.
|
36
|
+
route=f"job/{self.job_id}/errors",
|
26
37
|
requests_command=requests.get,
|
27
38
|
)
|
28
39
|
|
29
40
|
def sleep_until_complete(self, verbose_std_out=True):
|
30
41
|
while 1:
|
31
42
|
status = self.status()
|
32
|
-
|
33
43
|
time.sleep(JOB_POLLING_INTERVAL)
|
34
44
|
|
35
45
|
if verbose_std_out:
|
36
46
|
print(f"Status at {time.ctime()}: {status}")
|
37
47
|
if status["status"] == "Running":
|
38
48
|
continue
|
49
|
+
|
39
50
|
break
|
40
51
|
|
41
52
|
final_status = status
|
42
53
|
if final_status["status"] == "Errored":
|
43
54
|
raise JobError(final_status, self)
|
44
55
|
|
56
|
+
@classmethod
|
57
|
+
def from_json(cls, payload: dict, client):
|
58
|
+
return cls(
|
59
|
+
job_id=payload[JOB_ID_KEY],
|
60
|
+
job_last_known_status=payload[JOB_LAST_KNOWN_STATUS_KEY],
|
61
|
+
job_type=payload[JOB_TYPE_KEY],
|
62
|
+
job_creation_time=payload[JOB_CREATION_TIME_KEY],
|
63
|
+
client=client,
|
64
|
+
)
|
65
|
+
|
45
66
|
|
46
67
|
class JobError(Exception):
|
47
68
|
def __init__(self, job_status: Dict[str, str], job: AsyncJob):
|
nucleus/model.py
CHANGED
@@ -2,6 +2,7 @@ from typing import List, Optional, Dict, Union
|
|
2
2
|
from .dataset import Dataset
|
3
3
|
from .prediction import (
|
4
4
|
BoxPrediction,
|
5
|
+
CuboidPrediction,
|
5
6
|
PolygonPrediction,
|
6
7
|
SegmentationPrediction,
|
7
8
|
)
|
@@ -32,17 +33,37 @@ class Model:
|
|
32
33
|
return f"Model(model_id='{self.id}', name='{self.name}', reference_id='{self.reference_id}', metadata={self.metadata}, client={self._client})"
|
33
34
|
|
34
35
|
def __eq__(self, other):
|
35
|
-
return
|
36
|
+
return (
|
37
|
+
(self.id == other.id)
|
38
|
+
and (self.name == other.name)
|
39
|
+
and (self.metadata == other.metadata)
|
40
|
+
and (self._client == other._client)
|
41
|
+
)
|
36
42
|
|
37
43
|
def __hash__(self):
|
38
44
|
return hash(self.id)
|
39
45
|
|
46
|
+
@classmethod
|
47
|
+
def from_json(cls, payload: dict, client):
|
48
|
+
return cls(
|
49
|
+
model_id=payload["id"],
|
50
|
+
name=payload["name"],
|
51
|
+
reference_id=payload["ref_id"],
|
52
|
+
metadata=payload["metadata"] or None,
|
53
|
+
client=client,
|
54
|
+
)
|
55
|
+
|
40
56
|
def create_run(
|
41
57
|
self,
|
42
58
|
name: str,
|
43
59
|
dataset: Dataset,
|
44
60
|
predictions: List[
|
45
|
-
Union[
|
61
|
+
Union[
|
62
|
+
BoxPrediction,
|
63
|
+
PolygonPrediction,
|
64
|
+
CuboidPrediction,
|
65
|
+
SegmentationPrediction,
|
66
|
+
]
|
46
67
|
],
|
47
68
|
metadata: Optional[Dict] = None,
|
48
69
|
asynchronous: bool = False,
|
nucleus/model_run.py
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
from typing import Dict, List, Optional, Type, Union
|
2
|
-
|
3
|
-
from nucleus.annotation import
|
2
|
+
import requests
|
3
|
+
from nucleus.annotation import check_all_mask_paths_remote
|
4
4
|
from nucleus.job import AsyncJob
|
5
5
|
from nucleus.utils import serialize_and_write_to_presigned_url
|
6
6
|
|
7
7
|
from .constants import (
|
8
8
|
ANNOTATIONS_KEY,
|
9
9
|
BOX_TYPE,
|
10
|
+
CUBOID_TYPE,
|
10
11
|
DEFAULT_ANNOTATION_UPDATE_MODE,
|
11
|
-
JOB_ID_KEY,
|
12
12
|
POLYGON_TYPE,
|
13
13
|
REQUEST_ID_KEY,
|
14
14
|
SEGMENTATION_TYPE,
|
@@ -16,8 +16,10 @@ from .constants import (
|
|
16
16
|
)
|
17
17
|
from .prediction import (
|
18
18
|
BoxPrediction,
|
19
|
+
CuboidPrediction,
|
19
20
|
PolygonPrediction,
|
20
21
|
SegmentationPrediction,
|
22
|
+
from_json,
|
21
23
|
)
|
22
24
|
|
23
25
|
|
@@ -30,10 +32,10 @@ class ModelRun:
|
|
30
32
|
def __init__(self, model_run_id: str, dataset_id: str, client):
|
31
33
|
self.model_run_id = model_run_id
|
32
34
|
self._client = client
|
33
|
-
self.
|
35
|
+
self.dataset_id = dataset_id
|
34
36
|
|
35
37
|
def __repr__(self):
|
36
|
-
return f"ModelRun(model_run_id='{self.model_run_id}', dataset_id='{self.
|
38
|
+
return f"ModelRun(model_run_id='{self.model_run_id}', dataset_id='{self.dataset_id}', client={self._client})"
|
37
39
|
|
38
40
|
def __eq__(self, other):
|
39
41
|
if self.model_run_id == other.model_run_id:
|
@@ -90,14 +92,19 @@ class ModelRun:
|
|
90
92
|
def predict(
|
91
93
|
self,
|
92
94
|
annotations: List[
|
93
|
-
Union[
|
95
|
+
Union[
|
96
|
+
BoxPrediction,
|
97
|
+
PolygonPrediction,
|
98
|
+
CuboidPrediction,
|
99
|
+
SegmentationPrediction,
|
100
|
+
]
|
94
101
|
],
|
95
102
|
update: Optional[bool] = DEFAULT_ANNOTATION_UPDATE_MODE,
|
96
103
|
asynchronous: bool = False,
|
97
104
|
) -> Union[dict, AsyncJob]:
|
98
105
|
"""
|
99
106
|
Uploads model outputs as predictions for a model_run. Returns info about the upload.
|
100
|
-
:param annotations: List[Union[BoxPrediction, PolygonPrediction]],
|
107
|
+
:param annotations: List[Union[BoxPrediction, PolygonPrediction, CuboidPrediction, SegmentationPrediction]],
|
101
108
|
:return:
|
102
109
|
{
|
103
110
|
"model_run_id": str,
|
@@ -106,17 +113,16 @@ class ModelRun:
|
|
106
113
|
}
|
107
114
|
"""
|
108
115
|
if asynchronous:
|
109
|
-
|
116
|
+
check_all_mask_paths_remote(annotations)
|
110
117
|
|
111
118
|
request_id = serialize_and_write_to_presigned_url(
|
112
|
-
annotations, self.
|
119
|
+
annotations, self.dataset_id, self._client
|
113
120
|
)
|
114
121
|
response = self._client.make_request(
|
115
122
|
payload={REQUEST_ID_KEY: request_id, UPDATE_KEY: update},
|
116
123
|
route=f"modelRun/{self.model_run_id}/predict?async=1",
|
117
124
|
)
|
118
|
-
|
119
|
-
return AsyncJob(response[JOB_ID_KEY], self._client)
|
125
|
+
return AsyncJob.from_json(response, self._client)
|
120
126
|
else:
|
121
127
|
return self._client.predict(self.model_run_id, annotations, update)
|
122
128
|
|
@@ -124,7 +130,7 @@ class ModelRun:
|
|
124
130
|
"""
|
125
131
|
Returns Model Run Info For Dataset Item by its number.
|
126
132
|
:param i: absolute number of Dataset Item for a dataset corresponding to the model run.
|
127
|
-
:return: List[Union[BoxPrediction, PolygonPrediction]],
|
133
|
+
:return: List[Union[BoxPrediction, PolygonPrediction, CuboidPrediction, SegmentationPrediction]],
|
128
134
|
}
|
129
135
|
"""
|
130
136
|
response = self._client.predictions_iloc(self.model_run_id, i)
|
@@ -134,7 +140,7 @@ class ModelRun:
|
|
134
140
|
"""
|
135
141
|
Returns Model Run Info For Dataset Item by its reference_id.
|
136
142
|
:param reference_id: reference_id of a dataset item.
|
137
|
-
:return: List[Union[BoxPrediction, PolygonPrediction]],
|
143
|
+
:return: List[Union[BoxPrediction, PolygonPrediction, CuboidPrediction, SegmentationPrediction]],
|
138
144
|
"""
|
139
145
|
response = self._client.predictions_ref_id(
|
140
146
|
self.model_run_id, reference_id
|
@@ -155,11 +161,45 @@ class ModelRun:
|
|
155
161
|
)
|
156
162
|
return self._format_prediction_response(response)
|
157
163
|
|
164
|
+
def prediction_loc(self, reference_id: str, annotation_id: str):
|
165
|
+
"""
|
166
|
+
Returns info for single Prediction by its reference id and annotation id.
|
167
|
+
:param reference_id: the user specified id for the image
|
168
|
+
:param annotation_id: the user specified id for the prediction, or if one was not provided, the Scale internally generated id for the prediction
|
169
|
+
:return:
|
170
|
+
BoxPrediction | PolygonPrediction | CuboidPrediction
|
171
|
+
"""
|
172
|
+
|
173
|
+
response = self._client.make_request(
|
174
|
+
{},
|
175
|
+
f"modelRun/{self.model_run_id}/prediction/loc/{reference_id}/{annotation_id}",
|
176
|
+
requests.get,
|
177
|
+
)
|
178
|
+
|
179
|
+
return from_json(response)
|
180
|
+
|
181
|
+
def ungrouped_export(self):
|
182
|
+
json_response = self._client.make_request(
|
183
|
+
payload={},
|
184
|
+
route=f"modelRun/{self.model_run_id}/ungrouped",
|
185
|
+
requests_command=requests.get,
|
186
|
+
)
|
187
|
+
return self._format_prediction_response(
|
188
|
+
{ANNOTATIONS_KEY: json_response}
|
189
|
+
)
|
190
|
+
|
158
191
|
def _format_prediction_response(
|
159
192
|
self, response: dict
|
160
193
|
) -> Union[
|
161
194
|
dict,
|
162
|
-
List[
|
195
|
+
List[
|
196
|
+
Union[
|
197
|
+
BoxPrediction,
|
198
|
+
PolygonPrediction,
|
199
|
+
CuboidPrediction,
|
200
|
+
SegmentationPrediction,
|
201
|
+
]
|
202
|
+
],
|
163
203
|
]:
|
164
204
|
annotation_payload = response.get(ANNOTATIONS_KEY, None)
|
165
205
|
if not annotation_payload:
|
@@ -171,11 +211,13 @@ class ModelRun:
|
|
171
211
|
Union[
|
172
212
|
Type[BoxPrediction],
|
173
213
|
Type[PolygonPrediction],
|
214
|
+
Type[CuboidPrediction],
|
174
215
|
Type[SegmentationPrediction],
|
175
216
|
],
|
176
217
|
] = {
|
177
218
|
BOX_TYPE: BoxPrediction,
|
178
219
|
POLYGON_TYPE: PolygonPrediction,
|
220
|
+
CUBOID_TYPE: CuboidPrediction,
|
179
221
|
SEGMENTATION_TYPE: SegmentationPrediction,
|
180
222
|
}
|
181
223
|
for type_key in annotation_payload:
|
nucleus/payload_constructor.py
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
from typing import List, Optional, Dict, Union
|
2
2
|
from .dataset_item import DatasetItem
|
3
|
+
from .scene import LidarScene
|
3
4
|
from .annotation import (
|
4
5
|
BoxAnnotation,
|
6
|
+
CuboidAnnotation,
|
5
7
|
PolygonAnnotation,
|
8
|
+
CategoryAnnotation,
|
6
9
|
SegmentationAnnotation,
|
7
10
|
)
|
8
11
|
from .prediction import (
|
9
12
|
BoxPrediction,
|
13
|
+
CuboidPrediction,
|
10
14
|
PolygonPrediction,
|
11
15
|
SegmentationPrediction,
|
12
16
|
)
|
@@ -17,10 +21,14 @@ from .constants import (
|
|
17
21
|
REFERENCE_ID_KEY,
|
18
22
|
ANNOTATIONS_KEY,
|
19
23
|
ITEMS_KEY,
|
24
|
+
SCENES_KEY,
|
20
25
|
UPDATE_KEY,
|
21
26
|
MODEL_ID_KEY,
|
22
27
|
ANNOTATION_METADATA_SCHEMA_KEY,
|
23
28
|
SEGMENTATIONS_KEY,
|
29
|
+
TAXONOMY_NAME_KEY,
|
30
|
+
TYPE_KEY,
|
31
|
+
LABELS_KEY,
|
24
32
|
)
|
25
33
|
|
26
34
|
|
@@ -38,8 +46,25 @@ def construct_append_payload(
|
|
38
46
|
)
|
39
47
|
|
40
48
|
|
49
|
+
def construct_append_scenes_payload(
|
50
|
+
scene_list: List[LidarScene], update: Optional[bool] = False
|
51
|
+
) -> dict:
|
52
|
+
scenes = []
|
53
|
+
for scene in scene_list:
|
54
|
+
scenes.append(scene.to_payload())
|
55
|
+
return {SCENES_KEY: scenes, UPDATE_KEY: update}
|
56
|
+
|
57
|
+
|
41
58
|
def construct_annotation_payload(
|
42
|
-
annotation_items: List[
|
59
|
+
annotation_items: List[
|
60
|
+
Union[
|
61
|
+
BoxAnnotation,
|
62
|
+
PolygonAnnotation,
|
63
|
+
CuboidAnnotation,
|
64
|
+
CategoryAnnotation,
|
65
|
+
SegmentationAnnotation,
|
66
|
+
]
|
67
|
+
],
|
43
68
|
update: bool,
|
44
69
|
) -> dict:
|
45
70
|
annotations = []
|
@@ -63,7 +88,9 @@ def construct_segmentation_payload(
|
|
63
88
|
|
64
89
|
|
65
90
|
def construct_box_predictions_payload(
|
66
|
-
box_predictions: List[
|
91
|
+
box_predictions: List[
|
92
|
+
Union[BoxPrediction, PolygonPrediction, CuboidPrediction]
|
93
|
+
],
|
67
94
|
update: bool,
|
68
95
|
) -> dict:
|
69
96
|
predictions = []
|
@@ -104,3 +131,13 @@ def construct_model_run_creation_payload(
|
|
104
131
|
METADATA_KEY: metadata if metadata else {},
|
105
132
|
ANNOTATION_METADATA_SCHEMA_KEY: annotation_metadata_schema,
|
106
133
|
}
|
134
|
+
|
135
|
+
|
136
|
+
def construct_taxonomy_payload(
|
137
|
+
taxonomy_name: str, taxonomy_type: str, labels: List[str]
|
138
|
+
) -> dict:
|
139
|
+
return {
|
140
|
+
TAXONOMY_NAME_KEY: taxonomy_name,
|
141
|
+
TYPE_KEY: taxonomy_type,
|
142
|
+
LABELS_KEY: labels,
|
143
|
+
}
|
nucleus/prediction.py
CHANGED
@@ -5,14 +5,19 @@ from .annotation import (
|
|
5
5
|
PolygonAnnotation,
|
6
6
|
Segment,
|
7
7
|
SegmentationAnnotation,
|
8
|
+
CuboidAnnotation,
|
9
|
+
Point3D,
|
8
10
|
)
|
9
11
|
from .constants import (
|
10
12
|
ANNOTATION_ID_KEY,
|
11
|
-
|
13
|
+
BOX_TYPE,
|
14
|
+
CUBOID_TYPE,
|
15
|
+
POLYGON_TYPE,
|
12
16
|
REFERENCE_ID_KEY,
|
13
17
|
METADATA_KEY,
|
14
18
|
GEOMETRY_KEY,
|
15
19
|
LABEL_KEY,
|
20
|
+
TYPE_KEY,
|
16
21
|
X_KEY,
|
17
22
|
Y_KEY,
|
18
23
|
WIDTH_KEY,
|
@@ -21,11 +26,24 @@ from .constants import (
|
|
21
26
|
CONFIDENCE_KEY,
|
22
27
|
VERTICES_KEY,
|
23
28
|
ANNOTATIONS_KEY,
|
24
|
-
ITEM_ID_KEY,
|
25
29
|
MASK_URL_KEY,
|
30
|
+
POSITION_KEY,
|
31
|
+
DIMENSIONS_KEY,
|
32
|
+
YAW_KEY,
|
26
33
|
)
|
27
34
|
|
28
35
|
|
36
|
+
def from_json(payload: dict):
|
37
|
+
if payload.get(TYPE_KEY, None) == BOX_TYPE:
|
38
|
+
return BoxPrediction.from_json(payload)
|
39
|
+
elif payload.get(TYPE_KEY, None) == POLYGON_TYPE:
|
40
|
+
return PolygonPrediction.from_json(payload)
|
41
|
+
elif payload.get(TYPE_KEY, None) == CUBOID_TYPE:
|
42
|
+
return CuboidPrediction.from_json(payload)
|
43
|
+
else:
|
44
|
+
return SegmentationPrediction.from_json(payload)
|
45
|
+
|
46
|
+
|
29
47
|
class SegmentationPrediction(SegmentationAnnotation):
|
30
48
|
# No need to define init or to_payload methods because
|
31
49
|
# we default to functions defined in the parent class
|
@@ -37,8 +55,7 @@ class SegmentationPrediction(SegmentationAnnotation):
|
|
37
55
|
Segment.from_json(ann)
|
38
56
|
for ann in payload.get(ANNOTATIONS_KEY, [])
|
39
57
|
],
|
40
|
-
reference_id=payload
|
41
|
-
item_id=payload.get(ITEM_ID_KEY, None),
|
58
|
+
reference_id=payload[REFERENCE_ID_KEY],
|
42
59
|
annotation_id=payload.get(ANNOTATION_ID_KEY, None),
|
43
60
|
)
|
44
61
|
|
@@ -51,8 +68,7 @@ class BoxPrediction(BoxAnnotation):
|
|
51
68
|
y: int,
|
52
69
|
width: int,
|
53
70
|
height: int,
|
54
|
-
reference_id:
|
55
|
-
item_id: Optional[str] = None,
|
71
|
+
reference_id: str,
|
56
72
|
confidence: Optional[float] = None,
|
57
73
|
annotation_id: Optional[str] = None,
|
58
74
|
metadata: Optional[Dict] = None,
|
@@ -65,7 +81,6 @@ class BoxPrediction(BoxAnnotation):
|
|
65
81
|
width=width,
|
66
82
|
height=height,
|
67
83
|
reference_id=reference_id,
|
68
|
-
item_id=item_id,
|
69
84
|
annotation_id=annotation_id,
|
70
85
|
metadata=metadata,
|
71
86
|
)
|
@@ -90,8 +105,7 @@ class BoxPrediction(BoxAnnotation):
|
|
90
105
|
y=geometry.get(Y_KEY, 0),
|
91
106
|
width=geometry.get(WIDTH_KEY, 0),
|
92
107
|
height=geometry.get(HEIGHT_KEY, 0),
|
93
|
-
reference_id=payload
|
94
|
-
item_id=payload.get(DATASET_ITEM_ID_KEY, None),
|
108
|
+
reference_id=payload[REFERENCE_ID_KEY],
|
95
109
|
confidence=payload.get(CONFIDENCE_KEY, None),
|
96
110
|
annotation_id=payload.get(ANNOTATION_ID_KEY, None),
|
97
111
|
metadata=payload.get(METADATA_KEY, {}),
|
@@ -104,8 +118,7 @@ class PolygonPrediction(PolygonAnnotation):
|
|
104
118
|
self,
|
105
119
|
label: str,
|
106
120
|
vertices: List[Point],
|
107
|
-
reference_id:
|
108
|
-
item_id: Optional[str] = None,
|
121
|
+
reference_id: str,
|
109
122
|
confidence: Optional[float] = None,
|
110
123
|
annotation_id: Optional[str] = None,
|
111
124
|
metadata: Optional[Dict] = None,
|
@@ -115,7 +128,6 @@ class PolygonPrediction(PolygonAnnotation):
|
|
115
128
|
label=label,
|
116
129
|
vertices=vertices,
|
117
130
|
reference_id=reference_id,
|
118
|
-
item_id=item_id,
|
119
131
|
annotation_id=annotation_id,
|
120
132
|
metadata=metadata,
|
121
133
|
)
|
@@ -139,8 +151,57 @@ class PolygonPrediction(PolygonAnnotation):
|
|
139
151
|
vertices=[
|
140
152
|
Point.from_json(_) for _ in geometry.get(VERTICES_KEY, [])
|
141
153
|
],
|
142
|
-
reference_id=payload
|
143
|
-
|
154
|
+
reference_id=payload[REFERENCE_ID_KEY],
|
155
|
+
confidence=payload.get(CONFIDENCE_KEY, None),
|
156
|
+
annotation_id=payload.get(ANNOTATION_ID_KEY, None),
|
157
|
+
metadata=payload.get(METADATA_KEY, {}),
|
158
|
+
class_pdf=payload.get(CLASS_PDF_KEY, None),
|
159
|
+
)
|
160
|
+
|
161
|
+
|
162
|
+
class CuboidPrediction(CuboidAnnotation):
|
163
|
+
def __init__(
|
164
|
+
self,
|
165
|
+
label: str,
|
166
|
+
position: Point3D,
|
167
|
+
dimensions: Point3D,
|
168
|
+
yaw: float,
|
169
|
+
reference_id: str,
|
170
|
+
confidence: Optional[float] = None,
|
171
|
+
annotation_id: Optional[str] = None,
|
172
|
+
metadata: Optional[Dict] = None,
|
173
|
+
class_pdf: Optional[Dict] = None,
|
174
|
+
):
|
175
|
+
super().__init__(
|
176
|
+
label=label,
|
177
|
+
position=position,
|
178
|
+
dimensions=dimensions,
|
179
|
+
yaw=yaw,
|
180
|
+
reference_id=reference_id,
|
181
|
+
annotation_id=annotation_id,
|
182
|
+
metadata=metadata,
|
183
|
+
)
|
184
|
+
self.confidence = confidence
|
185
|
+
self.class_pdf = class_pdf
|
186
|
+
|
187
|
+
def to_payload(self) -> dict:
|
188
|
+
payload = super().to_payload()
|
189
|
+
if self.confidence is not None:
|
190
|
+
payload[CONFIDENCE_KEY] = self.confidence
|
191
|
+
if self.class_pdf is not None:
|
192
|
+
payload[CLASS_PDF_KEY] = self.class_pdf
|
193
|
+
|
194
|
+
return payload
|
195
|
+
|
196
|
+
@classmethod
|
197
|
+
def from_json(cls, payload: dict):
|
198
|
+
geometry = payload.get(GEOMETRY_KEY, {})
|
199
|
+
return cls(
|
200
|
+
label=payload.get(LABEL_KEY, 0),
|
201
|
+
position=Point3D.from_json(geometry.get(POSITION_KEY, {})),
|
202
|
+
dimensions=Point3D.from_json(geometry.get(DIMENSIONS_KEY, {})),
|
203
|
+
yaw=geometry.get(YAW_KEY, 0),
|
204
|
+
reference_id=payload[REFERENCE_ID_KEY],
|
144
205
|
confidence=payload.get(CONFIDENCE_KEY, None),
|
145
206
|
annotation_id=payload.get(ANNOTATION_ID_KEY, None),
|
146
207
|
metadata=payload.get(METADATA_KEY, {}),
|