Skip to content

Commit c9f309a

Browse files
author
Anthony Krivonos
authored
Support for Tracks (#373)
* Support for Tracks * wip * Removed track linking * Remove unneeded key * Make arg more explicit * make consistent with be * Change update endpoint * Setting aside tests to marinate * Version bump * Added repr * Fix tests * Remove track_reference_id from segmentation
1 parent aa84c8a commit c9f309a

File tree

13 files changed

+455
-36
lines changed

13 files changed

+455
-36
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,17 @@ All notable changes to the [Nucleus Python Client](https://github.com/scaleapi/n
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.14.29](https://github.com/scaleapi/nucleus-python-client/releases/tag/v0.14.29) - 2022-11-22
9+
10+
### Added
11+
- Support for `Track`s, enabling ground truth annotations and model predictions to be grouped across dataset items and scenes
12+
- Helpers to update track metadata, as well as to create and delete tracks at the dataset level
13+
814

915
## [0.14.28](https://github.com/scaleapi/nucleus-python-client/releases/tag/v0.14.28) - 2022-11-17
1016

1117
### Added
12-
- Support for appending to slice with Scene reference IDs
18+
- Support for appending to slice with scene reference IDs
1319
- Better error handling when appending to a slice with non-existent reference IDs
1420

1521

nucleus/annotation.py

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
POSITION_KEY,
3232
REFERENCE_ID_KEY,
3333
TAXONOMY_NAME_KEY,
34+
TRACK_REFERENCE_ID_KEY,
3435
TYPE_KEY,
3536
VERTICES_KEY,
3637
VISIBLE_KEY,
@@ -109,6 +110,7 @@ class BoxAnnotation(Annotation): # pylint: disable=R0902
109110
annotation_id="image_1_car_box_1",
110111
metadata={"vehicle_color": "red"},
111112
embedding_vector=[0.1423, 1.432, ..., 3.829],
113+
track_reference_id="car_a",
112114
)
113115
114116
Parameters:
@@ -135,10 +137,12 @@ class BoxAnnotation(Annotation): # pylint: disable=R0902
135137
136138
Coordinate metadata may be provided to enable the Map Chart in the Nucleus Dataset charts page.
137139
These values can be specified as `{ "lat": 52.5, "lon": 13.3, ... }`.
138-
139140
embedding_vector: Custom embedding vector for this object annotation.
140141
If any custom object embeddings have been uploaded previously to this dataset,
141142
this vector must match the dimensions of the previously ingested vectors.
143+
track_reference_id: A unique string to identify the annotation as part of a group.
144+
For instance, multiple "car" annotations across several dataset items may have
145+
the same `track_reference_id` such as "red_car".
142146
"""
143147

144148
label: str
@@ -150,6 +154,7 @@ class BoxAnnotation(Annotation): # pylint: disable=R0902
150154
annotation_id: Optional[str] = None
151155
metadata: Optional[Dict] = None
152156
embedding_vector: Optional[list] = None
157+
track_reference_id: Optional[str] = None
153158

154159
def __post_init__(self):
155160
self.metadata = self.metadata if self.metadata else {}
@@ -169,6 +174,7 @@ def from_json(cls, payload: dict):
169174
annotation_id=payload.get(ANNOTATION_ID_KEY, None),
170175
metadata=payload.get(METADATA_KEY, {}),
171176
embedding_vector=payload.get(EMBEDDING_VECTOR_KEY, None),
177+
track_reference_id=payload.get(TRACK_REFERENCE_ID_KEY, None),
172178
)
173179

174180
def to_payload(self) -> dict:
@@ -185,6 +191,7 @@ def to_payload(self) -> dict:
185191
ANNOTATION_ID_KEY: self.annotation_id,
186192
METADATA_KEY: self.metadata,
187193
EMBEDDING_VECTOR_KEY: self.embedding_vector,
194+
TRACK_REFERENCE_ID_KEY: self.track_reference_id,
188195
}
189196

190197
def __eq__(self, other):
@@ -198,6 +205,7 @@ def __eq__(self, other):
198205
and self.annotation_id == other.annotation_id
199206
and sorted(self.metadata.items()) == sorted(other.metadata.items())
200207
and self.embedding_vector == other.embedding_vector
208+
and self.track_reference_id == other.track_reference_id
201209
)
202210

203211

@@ -237,6 +245,7 @@ class LineAnnotation(Annotation):
237245
reference_id="person_image_1",
238246
annotation_id="person_image_1_line_1",
239247
metadata={"camera_mode": "portrait"},
248+
track_reference_id="face_human",
240249
)
241250
242251
Parameters:
@@ -252,13 +261,17 @@ class LineAnnotation(Annotation):
252261
attach to this annotation. Strings, floats and ints are supported best
253262
by querying and insights features within Nucleus. For more details see
254263
our `metadata guide <https://nucleus.scale.com/docs/upload-metadata>`_.
264+
track_reference_id: A unique string to identify the annotation as part of a group.
265+
For instance, multiple "car" annotations across several dataset items may have
266+
the same `track_reference_id` such as "red_car".
255267
"""
256268

257269
label: str
258270
vertices: List[Point]
259271
reference_id: str
260272
annotation_id: Optional[str] = None
261273
metadata: Optional[Dict] = None
274+
track_reference_id: Optional[str] = None
262275

263276
def __post_init__(self):
264277
self.metadata = self.metadata if self.metadata else {}
@@ -287,6 +300,7 @@ def from_json(cls, payload: dict):
287300
reference_id=payload[REFERENCE_ID_KEY],
288301
annotation_id=payload.get(ANNOTATION_ID_KEY, None),
289302
metadata=payload.get(METADATA_KEY, {}),
303+
track_reference_id=payload.get(TRACK_REFERENCE_ID_KEY, None),
290304
)
291305

292306
def to_payload(self) -> dict:
@@ -299,6 +313,7 @@ def to_payload(self) -> dict:
299313
REFERENCE_ID_KEY: self.reference_id,
300314
ANNOTATION_ID_KEY: self.annotation_id,
301315
METADATA_KEY: self.metadata,
316+
TRACK_REFERENCE_ID_KEY: self.track_reference_id,
302317
}
303318
return payload
304319

@@ -318,6 +333,7 @@ class PolygonAnnotation(Annotation):
318333
annotation_id="image_2_bus_polygon_1",
319334
metadata={"vehicle_color": "yellow"},
320335
embedding_vector=[0.1423, 1.432, ..., 3.829],
336+
track_reference_id="school_bus",
321337
)
322338
323339
Parameters:
@@ -336,6 +352,9 @@ class PolygonAnnotation(Annotation):
336352
embedding_vector: Custom embedding vector for this object annotation.
337353
If any custom object embeddings have been uploaded previously to this dataset,
338354
this vector must match the dimensions of the previously ingested vectors.
355+
track_reference_id: A unique string to identify the annotation as part of a group.
356+
For instance, multiple "car" annotations across several dataset items may have
357+
the same `track_reference_id` such as "red_car".
339358
"""
340359

341360
label: str
@@ -344,6 +363,7 @@ class PolygonAnnotation(Annotation):
344363
annotation_id: Optional[str] = None
345364
metadata: Optional[Dict] = None
346365
embedding_vector: Optional[list] = None
366+
track_reference_id: Optional[str] = None
347367

348368
def __post_init__(self):
349369
self.metadata = self.metadata if self.metadata else {}
@@ -373,6 +393,7 @@ def from_json(cls, payload: dict):
373393
annotation_id=payload.get(ANNOTATION_ID_KEY, None),
374394
metadata=payload.get(METADATA_KEY, {}),
375395
embedding_vector=payload.get(EMBEDDING_VECTOR_KEY, None),
396+
track_reference_id=payload.get(TRACK_REFERENCE_ID_KEY, None),
376397
)
377398

378399
def to_payload(self) -> dict:
@@ -386,6 +407,7 @@ def to_payload(self) -> dict:
386407
ANNOTATION_ID_KEY: self.annotation_id,
387408
METADATA_KEY: self.metadata,
388409
EMBEDDING_VECTOR_KEY: self.embedding_vector,
410+
TRACK_REFERENCE_ID_KEY: self.track_reference_id,
389411
}
390412
return payload
391413

@@ -450,6 +472,7 @@ class KeypointsAnnotation(Annotation):
450472
reference_id="image_2",
451473
annotation_id="image_2_face_keypoints_1",
452474
metadata={"face_direction": "forward"},
475+
track_reference_id="face_1",
453476
)
454477
455478
Parameters:
@@ -468,6 +491,9 @@ class KeypointsAnnotation(Annotation):
468491
attach to this annotation. Strings, floats and ints are supported best
469492
by querying and insights features within Nucleus. For more details see
470493
our `metadata guide <https://nucleus.scale.com/docs/upload-metadata>`_.
494+
track_reference_id: A unique string to identify the annotation as part of a group.
495+
For instance, multiple "car" annotations across several dataset items may have
496+
the same `track_reference_id` such as "red_car".
471497
"""
472498

473499
label: str
@@ -477,6 +503,7 @@ class KeypointsAnnotation(Annotation):
477503
reference_id: str
478504
annotation_id: Optional[str] = None
479505
metadata: Optional[Dict] = None
506+
track_reference_id: Optional[str] = None
480507

481508
def __post_init__(self):
482509
self.metadata = self.metadata or {}
@@ -518,6 +545,7 @@ def from_json(cls, payload: dict):
518545
reference_id=payload[REFERENCE_ID_KEY],
519546
annotation_id=payload.get(ANNOTATION_ID_KEY, None),
520547
metadata=payload.get(METADATA_KEY, {}),
548+
track_reference_id=payload.get(TRACK_REFERENCE_ID_KEY, None),
521549
)
522550

523551
def to_payload(self) -> dict:
@@ -532,6 +560,7 @@ def to_payload(self) -> dict:
532560
REFERENCE_ID_KEY: self.reference_id,
533561
ANNOTATION_ID_KEY: self.annotation_id,
534562
METADATA_KEY: self.metadata,
563+
TRACK_REFERENCE_ID_KEY: self.track_reference_id,
535564
}
536565
return payload
537566

@@ -573,7 +602,8 @@ class CuboidAnnotation(Annotation): # pylint: disable=R0902
573602
yaw=0,
574603
reference_id="pointcloud_1",
575604
annotation_id="pointcloud_1_car_cuboid_1",
576-
metadata={"vehicle_color": "green"}
605+
metadata={"vehicle_color": "green"},
606+
track_reference_id="red_car",
577607
)
578608
579609
Parameters:
@@ -590,6 +620,9 @@ class CuboidAnnotation(Annotation): # pylint: disable=R0902
590620
annotation. Strings, floats and ints are supported best by querying
591621
and insights features within Nucleus. For more details see our `metadata
592622
guide <https://nucleus.scale.com/docs/upload-metadata>`_.
623+
track_reference_id: A unique string to identify the annotation as part of a group.
624+
For instance, multiple "car" annotations across several dataset items may have
625+
the same `track_reference_id` such as "red_car".
593626
"""
594627

595628
label: str
@@ -599,6 +632,7 @@ class CuboidAnnotation(Annotation): # pylint: disable=R0902
599632
reference_id: str
600633
annotation_id: Optional[str] = None
601634
metadata: Optional[Dict] = None
635+
track_reference_id: Optional[str] = None
602636

603637
def __post_init__(self):
604638
self.metadata = self.metadata if self.metadata else {}
@@ -614,6 +648,7 @@ def from_json(cls, payload: dict):
614648
reference_id=payload[REFERENCE_ID_KEY],
615649
annotation_id=payload.get(ANNOTATION_ID_KEY, None),
616650
metadata=payload.get(METADATA_KEY, {}),
651+
track_reference_id=payload.get(TRACK_REFERENCE_ID_KEY, None),
617652
)
618653

619654
def to_payload(self) -> dict:
@@ -631,6 +666,8 @@ def to_payload(self) -> dict:
631666
payload[ANNOTATION_ID_KEY] = self.annotation_id
632667
if self.metadata:
633668
payload[METADATA_KEY] = self.metadata
669+
if self.track_reference_id:
670+
payload[TRACK_REFERENCE_ID_KEY] = self.track_reference_id
634671

635672
return payload
636673

@@ -772,11 +809,10 @@ def to_payload(self) -> dict:
772809
MASK_URL_KEY: self.mask_url,
773810
ANNOTATIONS_KEY: [ann.to_payload() for ann in self.annotations],
774811
ANNOTATION_ID_KEY: self.annotation_id,
812+
REFERENCE_ID_KEY: self.reference_id,
775813
# METADATA_KEY: self.metadata, # TODO(sc: 422637)
776814
}
777815

778-
payload[REFERENCE_ID_KEY] = self.reference_id
779-
780816
return payload
781817

782818
def has_local_files_to_upload(self) -> bool:
@@ -822,7 +858,8 @@ class CategoryAnnotation(Annotation):
822858
label="dress",
823859
reference_id="image_1",
824860
taxonomy_name="clothing_type",
825-
metadata={"dress_color": "navy"}
861+
metadata={"dress_color": "navy"},
862+
track_reference_id="blue_and_black_dress",
826863
)
827864
828865
Parameters:
@@ -834,12 +871,16 @@ class CategoryAnnotation(Annotation):
834871
Strings, floats and ints are supported best by querying and insights
835872
features within Nucleus. For more details see our `metadata guide
836873
<https://nucleus.scale.com/docs/upload-metadata>`_.
874+
track_reference_id: A unique string to identify the annotation as part of a group.
875+
For instance, multiple "car" annotations across several dataset items may have
876+
the same `track_reference_id` such as "red_car".
837877
"""
838878

839879
label: str
840880
reference_id: str
841881
taxonomy_name: Optional[str] = None
842882
metadata: Optional[Dict] = None
883+
track_reference_id: Optional[str] = None
843884

844885
def __post_init__(self):
845886
self.metadata = self.metadata if self.metadata else {}
@@ -851,6 +892,7 @@ def from_json(cls, payload: dict):
851892
reference_id=payload[REFERENCE_ID_KEY],
852893
taxonomy_name=payload.get(TAXONOMY_NAME_KEY, None),
853894
metadata=payload.get(METADATA_KEY, {}),
895+
track_reference_id=payload.get(TRACK_REFERENCE_ID_KEY, None),
854896
)
855897

856898
def to_payload(self) -> dict:
@@ -860,6 +902,7 @@ def to_payload(self) -> dict:
860902
GEOMETRY_KEY: {},
861903
REFERENCE_ID_KEY: self.reference_id,
862904
METADATA_KEY: self.metadata,
905+
TRACK_REFERENCE_ID_KEY: self.track_reference_id,
863906
}
864907
if self.taxonomy_name is not None:
865908
payload[TAXONOMY_NAME_KEY] = self.taxonomy_name
@@ -874,6 +917,7 @@ class MultiCategoryAnnotation(Annotation):
874917
reference_id: str
875918
taxonomy_name: Optional[str] = None
876919
metadata: Optional[Dict] = None
920+
track_reference_id: Optional[str] = None
877921

878922
def __post_init__(self):
879923
self.metadata = self.metadata if self.metadata else {}
@@ -885,6 +929,7 @@ def from_json(cls, payload: dict):
885929
reference_id=payload[REFERENCE_ID_KEY],
886930
taxonomy_name=payload.get(TAXONOMY_NAME_KEY, None),
887931
metadata=payload.get(METADATA_KEY, {}),
932+
track_reference_id=payload.get(TRACK_REFERENCE_ID_KEY, None),
888933
)
889934

890935
def to_payload(self) -> dict:
@@ -894,6 +939,7 @@ def to_payload(self) -> dict:
894939
GEOMETRY_KEY: {},
895940
REFERENCE_ID_KEY: self.reference_id,
896941
METADATA_KEY: self.metadata,
942+
TRACK_REFERENCE_ID_KEY: self.track_reference_id,
897943
}
898944
if self.taxonomy_name is not None:
899945
payload[TAXONOMY_NAME_KEY] = self.taxonomy_name

nucleus/constants.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@
102102
PAGE_SIZE_KEY = "pageSize"
103103
PAGE_TOKEN_KEY = "pageToken"
104104
NEXT_TOKEN_KEY = "nextPageToken"
105+
OVERWRITE_KEY = "overwrite"
105106
P1_KEY = "p1"
106107
P2_KEY = "p2"
107108
POINTCLOUD_KEY = "pointcloud"
@@ -125,6 +126,9 @@
125126
STATUS_KEY = "status"
126127
SUCCESS_STATUS_CODES = [200, 201, 202]
127128
TAXONOMY_NAME_KEY = "taxonomy_name"
129+
TRACK_REFERENCE_ID_KEY = "track_reference_id"
130+
TRACK_REFERENCE_IDS_KEY = "track_reference_ids"
131+
TRACKS_KEY = "tracks"
128132
TYPE_KEY = "type"
129133
UPDATED_ITEMS = "updated_items"
130134
UPDATE_KEY = "update"

0 commit comments

Comments
 (0)