Skip to content

Commit b3bf569

Browse files
committed
ability to run to_common to convert back to common labelbox format
1 parent 60ab2a0 commit b3bf569

File tree

2 files changed

+46
-61
lines changed

2 files changed

+46
-61
lines changed

labelbox/data/serialization/ndjson/label.py

Lines changed: 17 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -15,41 +15,48 @@
1515

1616
from .metric import NDScalarMetric, NDMetricAnnotation, NDConfusionMatrixMetric
1717
from .classification import NDChecklistSubclass, NDClassification, NDClassificationType, NDRadioSubclass
18-
from .objects import NDObject, NDObjectType
18+
from .objects import NDObject, NDObjectType, NDFrameObjectType, NDSegments
1919

2020

2121
class NDLabel(BaseModel):
2222
annotations: List[Union[NDObjectType, NDClassificationType,
23-
NDConfusionMatrixMetric, NDScalarMetric]]
23+
NDConfusionMatrixMetric, NDScalarMetric,
24+
NDSegments]]
2425

2526
def to_common(self) -> LabelGenerator:
2627
grouped_annotations = defaultdict(list)
2728
for annotation in self.annotations:
2829
grouped_annotations[annotation.data_row.id].append(annotation)
2930
return LabelGenerator(
3031
data=self._generate_annotations(grouped_annotations))
32+
# c = LabelGenerator(data=self._generate_annotations(grouped_annotations))
33+
# print(next(c), "Wefwefweefw\n")
3134

3235
@classmethod
3336
def from_common(cls,
3437
data: LabelCollection) -> Generator["NDLabel", None, None]:
3538
for label in data:
36-
# print(f"label in data:{label}")
3739
yield from cls._create_non_video_annotations(label)
3840
yield from cls._create_video_annotations(label)
3941

4042
def _generate_annotations(
41-
self, grouped_annotations: Dict[str, List[Union[NDObjectType,
42-
NDClassificationType,
43-
NDConfusionMatrixMetric,
44-
NDScalarMetric]]]
43+
self,
44+
grouped_annotations: Dict[str,
45+
List[Union[NDObjectType, NDClassificationType,
46+
NDConfusionMatrixMetric,
47+
NDScalarMetric, NDSegments]]]
4548
) -> Generator[Label, None, None]:
4649
for data_row_id, annotations in grouped_annotations.items():
4750
annots = []
4851
for annotation in annotations:
52+
if isinstance(annotation, NDSegments):
53+
# b = NDSegments.to_common(annotation, annotation.schema_id)
54+
# print(type(b), b)
55+
annots.extend(
56+
NDSegments.to_common(annotation, annotation.schema_id))
4957

50-
if isinstance(annotation, NDObjectType.__args__):
58+
elif isinstance(annotation, NDObjectType.__args__):
5159
annots.append(NDObject.to_common(annotation))
52-
#TODO: have a check on if the return type needs to extend or not
5360
elif isinstance(annotation, NDClassificationType.__args__):
5461
annots.extend(NDClassification.to_common(annotation))
5562
elif isinstance(annotation,
@@ -58,7 +65,7 @@ def _generate_annotations(
5865
else:
5966
raise TypeError(
6067
f"Unsupported annotation. {type(annotation)}")
61-
68+
# print(type(annots[0]), annots[0])
6269
data = self._infer_media_type(annotations)(uid=data_row_id)
6370
yield Label(annotations=annots, data=data)
6471

@@ -115,31 +122,7 @@ def _create_video_annotations(
115122
if annotation.keyframe and start_frame <= annotation.frame <= end_frame:
116123
segment.append(annotation)
117124
segments.append(segment)
118-
119-
print(segments[0], "\n")
120-
print(segments[1], "\n")
121-
print(consecutive_frames)
122125
yield NDObject.from_common(segments, label.data)
123-
# segments = []
124-
# seg_frames = []
125-
# for cframes in consecutive_frames:
126-
# seg_frames.append(cframes[0])
127-
# seg_frames.append(cframes[1])
128-
# print(seg_frames)
129-
# for annotation in annotation_group:
130-
# if annotation.frame in seg_frames:
131-
# segments.append(annotation)
132-
# # if annotation.keyframe:
133-
# # segments.append(annotation)
134-
# # print(consecutive_frames)
135-
# #TODO: current issue is that the way the code is written doesn't account for
136-
# #which frames are consecutive. maybe we should just have list of segments
137-
# annotations = []
138-
# for annotation in segments:
139-
# annotations.append(
140-
# NDObject.from_common(annotation, label.data))
141-
# yield annotations[0]
142-
# yield {}
143126

144127
@classmethod
145128
def _create_non_video_annotations(cls, label: Label):

labelbox/data/serialization/ndjson/objects.py

Lines changed: 29 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,15 @@ def from_common(cls, rectangle: Rectangle,
129129
class NDFrameRectangle(VideoSupported):
130130
bbox: Bbox
131131

132+
def to_common(self, feature_schema_id: Cuid) -> VideoObjectAnnotation:
133+
return VideoObjectAnnotation(
134+
frame=self.frame,
135+
keyframe=True,
136+
feature_schema_id=feature_schema_id,
137+
value=Rectangle(start=Point(x=self.bbox.left, y=self.bbox.top),
138+
end=Point(x=self.bbox.left + self.bbox.width,
139+
y=self.bbox.top + self.bbox.height)))
140+
132141
@classmethod
133142
def from_common(cls, frame: int, rectangle: Rectangle):
134143
return cls(frame=frame,
@@ -143,9 +152,17 @@ class NDSegment(BaseModel):
143152

144153
@staticmethod
145154
def lookup_segment_object_type(segment: List) -> "NDFrameObjectType":
155+
"""Used for determining which object type the annotation contains
156+
returns the object type"""
146157
result = {Rectangle: NDFrameRectangle}.get(type(segment[0].value))
147158
return result
148159

160+
def to_common(self, feature_schema_id: Cuid):
161+
# print(f"\n to_common in ndsegment {self.keyframes}\n")
162+
return [
163+
keyframe.to_common(feature_schema_id) for keyframe in self.keyframes
164+
]
165+
149166
@classmethod
150167
def from_common(cls, segment):
151168
nd_frame_object_type = cls.lookup_segment_object_type(segment)
@@ -160,8 +177,11 @@ def from_common(cls, segment):
160177
class NDSegments(NDBaseObject):
161178
segments: List[NDSegment]
162179

163-
def to_common(self):
164-
pass
180+
def to_common(self, feature_schema_id: Cuid):
181+
result = []
182+
for segment in self.segments:
183+
result.extend(NDSegment.to_common(segment, feature_schema_id))
184+
return result
165185

166186
@classmethod
167187
def from_common(cls, segments: List[VideoObjectAnnotation], data: VideoData,
@@ -170,16 +190,10 @@ def from_common(cls, segments: List[VideoObjectAnnotation], data: VideoData,
170190

171191
segments = [NDSegment.from_common(segment) for segment in segments]
172192

173-
# print("\nbefore class instantiation\n", segments,
174-
# "\nbefore class instantiation\n")
175-
176-
a = cls(segments=segments,
177-
dataRow=DataRow(id=data.uid),
178-
schema_id=feature_schema_id,
179-
uuid=extra.get('uuid'))
180-
# print("\nI am from_common ndsegments", a,
181-
# "\nI am from_common ndsegments\n")
182-
return a
193+
return cls(segments=segments,
194+
dataRow=DataRow(id=data.uid),
195+
schema_id=feature_schema_id,
196+
uuid=extra.get('uuid'))
183197

184198

185199
class _URIMask(BaseModel):
@@ -278,11 +292,8 @@ def from_common(
278292

279293
#if it is video segments
280294
if (obj == NDSegments):
281-
print("hello i am ndsegment")
282-
#look into segment of segments
283-
#look into annotations of segment
284-
#check and validate that there are no subclasses
285-
#new method for processing segments ?
295+
#TODO: need to process segments' classifications
296+
#unsure if here or will be elsewhere
286297

287298
return obj.from_common(
288299
annotation,
@@ -317,17 +328,8 @@ def lookup_object(annotation: ObjectAnnotation) -> "NDObjectType":
317328
)
318329
return result
319330

320-
# @staticmethod
321-
# def process_segments(segments: List[List[VideoObjectAnnotation]]):
322-
# for segment in segments:
323-
# for annotation in segment:
324-
# subclasses = [
325-
# NDSubclassification.from_common(annot)
326-
# for annot in annotation.classifications
327-
# ]
328-
329331

330332
NDObjectType = Union[NDLine, NDPolygon, NDPoint, NDRectangle, NDMask,
331333
NDTextEntity]
332334

333-
NDFrameObjectType = NDFrameRectangle
335+
NDFrameObjectType = NDFrameRectangle

0 commit comments

Comments
 (0)