Skip to content

Commit b6b8432

Browse files
author
Anthony Krivonos
authored
[Nucleus] Scene categorization support (#343)
1 parent aaf00b0 commit b6b8432

File tree

12 files changed

+284
-4
lines changed

12 files changed

+284
-4
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ 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.16](https://github.com/scaleapi/nucleus-python-client/releases/tag/v0.14.15) - 2022-08-12
9+
10+
### Added
11+
- Scene cateogorization support
12+
813
## [0.14.15](https://github.com/scaleapi/nucleus-python-client/releases/tag/v0.14.15) - 2022-08-11
914

1015
### Removed

nucleus/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@
3131
"PolygonAnnotation",
3232
"PolygonPrediction",
3333
"Quaternion",
34+
"SceneCategoryAnnotation",
35+
"SceneCategoryPrediction",
3436
"Segment",
3537
"SegmentationAnnotation",
3638
"SegmentationPrediction",
@@ -61,6 +63,7 @@
6163
Point,
6264
Point3D,
6365
PolygonAnnotation,
66+
SceneCategoryAnnotation,
6467
Segment,
6568
SegmentationAnnotation,
6669
)
@@ -132,6 +135,7 @@
132135
KeypointsPrediction,
133136
LinePrediction,
134137
PolygonPrediction,
138+
SceneCategoryPrediction,
135139
SegmentationPrediction,
136140
)
137141
from .quaternion import Quaternion

nucleus/annotation.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@
4141
Z_KEY,
4242
)
4343

44+
# TODO: refactor to reduce this file to under 1000 lines.
45+
# pylint: disable=C0302
46+
4447

4548
class Annotation:
4649
"""Internal base class, not to be used directly.
@@ -893,6 +896,53 @@ def to_payload(self) -> dict:
893896
return payload
894897

895898

899+
@dataclass
900+
class SceneCategoryAnnotation(Annotation):
901+
"""A scene category annotation.
902+
903+
::
904+
905+
from nucleus import CategoryAnnotation
906+
907+
category = SceneCategoryAnnotation(
908+
label="running",
909+
reference_id="scene_1",
910+
taxonomy_name="action",
911+
)
912+
913+
Parameters:
914+
label (str): The label for this annotation.
915+
reference_id (str): User-defined ID of the scene to which to apply this annotation.
916+
taxonomy_name (Optional[str]): The name of the taxonomy this annotation conforms to.
917+
See :meth:`Dataset.add_taxonomy`.
918+
"""
919+
920+
label: str
921+
reference_id: str
922+
taxonomy_name: Optional[str] = None
923+
# todo(546247): add metadata support when required
924+
metadata: Optional[Dict] = field(default_factory=dict)
925+
926+
@classmethod
927+
def from_json(cls, payload: dict):
928+
return cls(
929+
label=payload[LABEL_KEY],
930+
reference_id=payload[REFERENCE_ID_KEY],
931+
taxonomy_name=payload.get(TAXONOMY_NAME_KEY, None),
932+
)
933+
934+
def to_payload(self) -> dict:
935+
payload = {
936+
LABEL_KEY: self.label,
937+
TYPE_KEY: CATEGORY_TYPE,
938+
GEOMETRY_KEY: {},
939+
REFERENCE_ID_KEY: self.reference_id,
940+
}
941+
if self.taxonomy_name is not None:
942+
payload[TAXONOMY_NAME_KEY] = self.taxonomy_name
943+
return payload
944+
945+
896946
@dataclass
897947
class AnnotationList:
898948
"""Wrapper class separating a list of annotations by type."""
@@ -910,6 +960,9 @@ class AnnotationList:
910960
multi_category_annotations: List[MultiCategoryAnnotation] = field(
911961
default_factory=list
912962
)
963+
scene_category_annotations: List[SceneCategoryAnnotation] = field(
964+
default_factory=list
965+
)
913966
segmentation_annotations: List[SegmentationAnnotation] = field(
914967
default_factory=list
915968
)
@@ -934,6 +987,8 @@ def add_annotations(self, annotations: List[Annotation]):
934987
self.category_annotations.append(annotation)
935988
elif isinstance(annotation, MultiCategoryAnnotation):
936989
self.multi_category_annotations.append(annotation)
990+
elif isinstance(annotation, SceneCategoryAnnotation):
991+
self.scene_category_annotations.append(annotation)
937992
else:
938993
assert isinstance(
939994
annotation, SegmentationAnnotation
@@ -952,6 +1007,7 @@ def __len__(self):
9521007
+ len(self.cuboid_annotations)
9531008
+ len(self.category_annotations)
9541009
+ len(self.multi_category_annotations)
1010+
+ len(self.scene_category_annotations)
9551011
+ len(self.segmentation_annotations)
9561012
)
9571013

nucleus/dataset.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
CategoryPrediction,
1111
CuboidPrediction,
1212
PolygonPrediction,
13+
SceneCategoryPrediction,
1314
SegmentationPrediction,
1415
from_json,
1516
)
@@ -345,8 +346,8 @@ def annotate(
345346
346347
Nucleus supports :class:`Box<BoxAnnotation>`, :class:`Polygon<PolygonAnnotation>`,
347348
:class:`Cuboid<CuboidAnnotation>`, :class:`Segmentation<SegmentationAnnotation>`,
348-
and :class:`Category<CategoryAnnotation>` annotations. Cuboid annotations
349-
can only be uploaded to a :class:`pointcloud DatasetItem<LidarScene>`.
349+
:class:`Category<CategoryAnnotation>`, and :class:`Category<SceneCategoryAnnotation>` annotations.
350+
Cuboid annotations can only be uploaded to a :class:`pointcloud DatasetItem<LidarScene>`.
350351
351352
When uploading an annotation, you need to specify which item you are
352353
annotating via the reference_id you provided when uploading the image
@@ -1474,6 +1475,7 @@ def upload_predictions(
14741475
CuboidPrediction,
14751476
SegmentationPrediction,
14761477
CategoryPrediction,
1478+
SceneCategoryPrediction,
14771479
]
14781480
],
14791481
update: bool = False,
@@ -1492,7 +1494,7 @@ def upload_predictions(
14921494
14931495
Nucleus supports :class:`Box<BoxPrediction>`, :class:`Polygon<PolygonPrediction>`,
14941496
:class:`Cuboid<CuboidPrediction>`, :class:`Segmentation<SegmentationPrediction>`,
1495-
and :class:`Category<CategoryPrediction>` predictions. Cuboid predictions
1497+
:class:`Category<CategoryPrediction>`, and :class:`Category<SceneCategoryPrediction>` predictions. Cuboid predictions
14961498
can only be uploaded to a :class:`pointcloud DatasetItem<LidarScene>`.
14971499
14981500
When uploading an prediction, you need to specify which item you are
@@ -1519,6 +1521,7 @@ def upload_predictions(
15191521
:class:`CuboidPrediction`, \
15201522
:class:`SegmentationPrediction`, \
15211523
:class:`CategoryPrediction` \
1524+
:class:`SceneCategoryPrediction` \
15221525
]]): List of prediction objects to upload.
15231526
update: Whether or not to overwrite metadata or ignore on reference ID
15241527
collision. Default is False.

nucleus/metrics/filtering.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
LinePrediction,
3737
PolygonPrediction,
3838
PredictionList,
39+
SceneCategoryPrediction,
3940
SegmentationPrediction,
4041
)
4142

@@ -90,6 +91,7 @@ class FilterType(str, enum.Enum):
9091
CuboidPrediction,
9192
LinePrediction,
9293
PolygonPrediction,
94+
SceneCategoryPrediction,
9395
SegmentationPrediction,
9496
]
9597

nucleus/payload_constructor.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
CuboidAnnotation,
77
MultiCategoryAnnotation,
88
PolygonAnnotation,
9+
SceneCategoryAnnotation,
910
SegmentationAnnotation,
1011
)
1112
from .constants import (
@@ -32,6 +33,7 @@
3233
CategoryPrediction,
3334
CuboidPrediction,
3435
PolygonPrediction,
36+
SceneCategoryPrediction,
3537
SegmentationPrediction,
3638
)
3739
from .scene import LidarScene, VideoScene
@@ -69,6 +71,7 @@ def construct_annotation_payload(
6971
CuboidAnnotation,
7072
CategoryAnnotation,
7173
MultiCategoryAnnotation,
74+
SceneCategoryAnnotation,
7275
SegmentationAnnotation,
7376
]
7477
],
@@ -112,6 +115,7 @@ def construct_box_predictions_payload(
112115
PolygonPrediction,
113116
CuboidPrediction,
114117
CategoryPrediction,
118+
SceneCategoryPrediction,
115119
]
116120
],
117121
update: bool,

nucleus/prediction.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
Point,
1717
Point3D,
1818
PolygonAnnotation,
19+
SceneCategoryAnnotation,
1920
Segment,
2021
SegmentationAnnotation,
2122
)
@@ -571,13 +572,25 @@ def from_json(cls, payload: dict):
571572
)
572573

573574

575+
class SceneCategoryPrediction(SceneCategoryAnnotation):
576+
"""A prediction of a category for a scene.
577+
578+
Parameters:
579+
label: The label for this annotation (e.g. action, subject, scenario).
580+
reference_id: The reference ID of the scene you wish to apply this annotation to.
581+
taxonomy_name: The name of the taxonomy this annotation conforms to.
582+
See :meth:`Dataset.add_taxonomy`.
583+
"""
584+
585+
574586
Prediction = Union[
575587
BoxPrediction,
576588
LinePrediction,
577589
PolygonPrediction,
578590
KeypointsPrediction,
579591
CuboidPrediction,
580592
CategoryPrediction,
593+
SceneCategoryPrediction,
581594
SegmentationPrediction,
582595
]
583596

@@ -596,6 +609,9 @@ class PredictionList:
596609
category_predictions: List[CategoryPrediction] = field(
597610
default_factory=list
598611
)
612+
scene_category_predictions: List[SceneCategoryPrediction] = field(
613+
default_factory=list
614+
)
599615
segmentation_predictions: List[SegmentationPrediction] = field(
600616
default_factory=list
601617
)
@@ -617,6 +633,8 @@ def add_predictions(self, predictions: List[Prediction]):
617633
self.cuboid_predictions.append(prediction)
618634
elif isinstance(prediction, CategoryPrediction):
619635
self.category_predictions.append(prediction)
636+
elif isinstance(prediction, SceneCategoryPrediction):
637+
self.scene_category_predictions.append(prediction)
620638
else:
621639
assert isinstance(
622640
prediction, SegmentationPrediction
@@ -631,5 +649,6 @@ def __len__(self):
631649
+ len(self.keypoints_predictions)
632650
+ len(self.cuboid_predictions)
633651
+ len(self.category_predictions)
652+
+ len(self.scene_category_predictions)
634653
+ len(self.segmentation_predictions)
635654
)

nucleus/utils.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
KeypointsPrediction,
5353
LinePrediction,
5454
PolygonPrediction,
55+
SceneCategoryPrediction,
5556
SegmentationPrediction,
5657
)
5758
from .scene import LidarScene, VideoScene
@@ -112,6 +113,7 @@ def format_prediction_response(
112113
KeypointsPrediction,
113114
CuboidPrediction,
114115
CategoryPrediction,
116+
SceneCategoryPrediction,
115117
SegmentationPrediction,
116118
]
117119
],
@@ -138,6 +140,7 @@ def format_prediction_response(
138140
Type[CuboidPrediction],
139141
Type[CategoryPrediction],
140142
Type[KeypointsPrediction],
143+
Type[SceneCategoryPrediction],
141144
Type[SegmentationPrediction],
142145
],
143146
] = {

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ exclude = '''
2121

2222
[tool.poetry]
2323
name = "scale-nucleus"
24-
version = "0.14.15"
24+
version = "0.14.16"
2525
description = "The official Python client library for Nucleus, the Data Platform for AI"
2626
license = "MIT"
2727
authors = ["Scale AI Nucleus Team <nucleusapi@scaleapi.com>"]

0 commit comments

Comments
 (0)