Skip to content

Commit d3abffe

Browse files
Fix get object instances
1 parent c644417 commit d3abffe

File tree

5 files changed

+100
-30
lines changed

5 files changed

+100
-30
lines changed

encord/objects/ontology_labels_impl.py

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -948,8 +948,12 @@ def get_object_instances(
948948
filtered_frames_list = list()
949949

950950
# Objects in space
951+
object_hashes: set[str] = set() # Needed to filter out duplicate object instances that exist on multiple spaces
951952
for space in self._space_map.values():
952953
for object_ in space._objects_map.values():
954+
if object_.object_hash in object_hashes:
955+
continue
956+
953957
# filter by ontology object
954958
if not (
955959
filter_ontology_object is None
@@ -976,6 +980,7 @@ def get_object_instances(
976980
break
977981

978982
if append:
983+
object_hashes.add(object_.object_hash)
979984
ret.append(object_)
980985

981986
# Objects on label row
@@ -1254,8 +1259,13 @@ def get_classification_instances(
12541259
if append:
12551260
ret.append(classification)
12561261

1262+
# Needed to remove filter out duplicate classification instances across spaces
1263+
classification_hashes: set[str] = set()
12571264
for space in self._space_map.values():
12581265
for classification in space.get_classifications():
1266+
if classification.classification_hash in classification_hashes:
1267+
continue
1268+
12591269
if not (
12601270
filter_ontology_classification is None
12611271
or classification.ontology_item.feature_node_hash
@@ -1270,11 +1280,24 @@ def get_classification_instances(
12701280
append = False
12711281

12721282
for frame in filtered_frames_list:
1273-
if classification.is_on_frame(frame):
1274-
append = True
1275-
break
1283+
if isinstance(space, VideoSpace):
1284+
# TODO: In VideoSpace, track classificationHash to ranges to improve performance here.
1285+
classifications_on_frames = space._frames_to_classification_hash_to_annotation_data.get(
1286+
frame, {}
1287+
)
1288+
if classification.classification_hash in classifications_on_frames:
1289+
append = True
1290+
break
1291+
elif isinstance(space, ImageSpace):
1292+
if frame != 0:
1293+
continue
1294+
1295+
if classification.classification_hash in space._classifications_map:
1296+
append = True
1297+
break
12761298

12771299
if append:
1300+
classification_hashes.add(classification.classification_hash)
12781301
ret.append(classification)
12791302

12801303
return ret

tests/objects/spaces/test_image_space/test_classifications.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
checklist_option_1 = checklist_classification.get_child_by_hash("fvLjF0qZ", Option)
2525
checklist_option_2 = checklist_classification.get_child_by_hash("a4r7nK9i", Option)
2626

27+
radio_classification = all_types_structure.get_child_by_hash("NzIxNTU1", Classification)
28+
2729

2830
@pytest.fixture
2931
def ontology():
@@ -33,6 +35,36 @@ def ontology():
3335
yield ontology
3436

3537

38+
def test_label_row_get_classification_instances_on_image_space(ontology):
39+
# Arrange
40+
label_row = LabelRowV2(DATA_GROUP_METADATA, Mock(), ontology)
41+
label_row.from_labels_dict(DATA_GROUP_TWO_IMAGES_NO_LABELS)
42+
image_space_1 = label_row.get_space_by_id("image-1-uuid", type_=ImageSpace)
43+
image_space_2 = label_row.get_space_by_id("image-2-uuid", type_=ImageSpace)
44+
45+
# Act
46+
classification_instance_1 = text_classification.create_instance()
47+
classification_instance_2 = checklist_classification.create_instance()
48+
classification_instance_3 = radio_classification.create_instance()
49+
50+
# Place classification on space 1
51+
image_space_1.place_classification(classification=classification_instance_1)
52+
image_space_1.place_classification(classification=classification_instance_2)
53+
54+
# Place classification on space 2
55+
image_space_2.place_classification(classification=classification_instance_3)
56+
57+
# Assert
58+
all_classification_instances = label_row.get_classification_instances()
59+
assert len(all_classification_instances) == 3
60+
61+
classification_instances_on_frame_1 = label_row.get_classification_instances(filter_frames=1)
62+
assert len(classification_instances_on_frame_1) == 0
63+
64+
classification_instances_on_frame_1 = label_row.get_classification_instances(filter_frames=0)
65+
assert len(classification_instances_on_frame_1) == 3
66+
67+
3668
def test_place_classification_on_image_space(ontology):
3769
# Arrange
3870
label_row = LabelRowV2(DATA_GROUP_METADATA, Mock(), ontology)

tests/objects/spaces/test_image_space/test_objects.py

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -43,32 +43,22 @@ def test_label_row_get_object_instances_on_space(ontology):
4343
object_instance_2 = box_ontology_item.create_instance()
4444

4545
# Place objects on space 1
46-
image_space_1.place_object(
47-
object_instance=object_instance_1,
48-
placement=coordinates
49-
)
50-
image_space_1.place_object(
51-
object_instance=object_instance_2,
52-
placement=coordinates
53-
)
46+
image_space_1.place_object(object_instance=object_instance_1, placement=coordinates)
47+
image_space_1.place_object(object_instance=object_instance_2, placement=coordinates)
5448

5549
# Place objects on space 2
56-
image_space_2.place_object(
57-
object_instance=object_instance_1,
58-
placement=coordinates
59-
)
50+
image_space_2.place_object(object_instance=object_instance_1, placement=coordinates)
6051

6152
object_instances = label_row.get_object_instances()
62-
assert len(object_instances) == 3
53+
assert len(object_instances) == 2
6354

6455
object_instances_on_frame_1 = label_row.get_object_instances(filter_frames=[0])
65-
assert len(object_instances_on_frame_1) == 3
56+
assert len(object_instances_on_frame_1) == 2
6657

6758
object_instances_on_frame_1 = label_row.get_object_instances(filter_frames=[1])
6859
assert len(object_instances_on_frame_1) == 0
6960

7061

71-
7262
def test_place_object_on_image_space(ontology):
7363
# Arrange
7464
label_row = LabelRowV2(DATA_GROUP_METADATA, Mock(), ontology)

tests/objects/spaces/test_video_space/test_classifications.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
box_with_attributes_ontology_item = all_types_structure.get_child_by_hash("MTA2MjAx", Object)
2121
box_text_attribute_ontology_item = box_with_attributes_ontology_item.get_child_by_hash("OTkxMjU1", type_=Attribute)
2222
text_classification = all_types_structure.get_child_by_hash("jPOcEsbw", Classification)
23+
checklist_classification = all_types_structure.get_child_by_hash("3DuQbFxo", Classification)
2324

2425

2526
@pytest.fixture
@@ -30,6 +31,32 @@ def ontology():
3031
yield ontology
3132

3233

34+
def test_label_row_get_classification_instances_on_video_space(ontology):
35+
# Arrange
36+
label_row = LabelRowV2(DATA_GROUP_METADATA, Mock(), ontology)
37+
label_row.from_labels_dict(DATA_GROUP_TWO_VIDEOS_NO_LABELS)
38+
video_space_1 = label_row.get_space_by_id("video-1-uuid", type_=VideoSpace)
39+
video_space_2 = label_row.get_space_by_id("video-2-uuid", type_=VideoSpace)
40+
41+
# Act
42+
classification_instance_1 = text_classification.create_instance()
43+
classification_instance_2 = checklist_classification.create_instance()
44+
45+
# Place classification on space 1
46+
video_space_1.place_classification(classification=classification_instance_1, placement=[0, 1, 2])
47+
video_space_1.place_classification(classification=classification_instance_2, placement=[2, 3, 4])
48+
49+
# Place classification on space 2
50+
video_space_2.place_classification(classification=classification_instance_1, placement=[1])
51+
52+
# Assert
53+
all_classification_instances = label_row.get_classification_instances()
54+
assert len(all_classification_instances) == 2
55+
56+
classification_instances_on_frame_1 = label_row.get_classification_instances(filter_frames=1)
57+
assert len(classification_instances_on_frame_1) == 1
58+
59+
3360
def test_place_classification_on_video_space(ontology):
3461
# Arrange
3562
label_row = LabelRowV2(DATA_GROUP_METADATA, Mock(), ontology)

tests/objects/spaces/test_video_space/test_objects.py

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ def ontology():
3030
ontology = Mock(structure=ontology_structure)
3131
yield ontology
3232

33+
3334
def test_label_row_get_object_instances_on_space(ontology):
3435
label_row = LabelRowV2(DATA_GROUP_METADATA, Mock(), ontology)
3536
label_row.from_labels_dict(DATA_GROUP_TWO_VIDEOS_NO_LABELS)
@@ -44,30 +45,27 @@ def test_label_row_get_object_instances_on_space(ontology):
4445
# Place objects on space 1
4546
video_space_1.place_object(
4647
object_instance=object_instance_1,
47-
placement=FramePlacement(
48-
frames=[0, 1, 2], coordinates=coordinates
49-
),
48+
placement=FramePlacement(frames=[0, 1, 2], coordinates=coordinates),
5049
)
5150
video_space_1.place_object(
5251
object_instance=object_instance_2,
53-
placement=FramePlacement(
54-
frames=[2, 3, 4], coordinates=coordinates
55-
),
52+
placement=FramePlacement(frames=[2, 3, 4], coordinates=coordinates),
5653
)
5754

5855
# Place objects on space 2
5956
video_space_2.place_object(
60-
object_instance=object_instance_1,
61-
placement=FramePlacement(
62-
frames=[1], coordinates=coordinates
63-
)
57+
object_instance=object_instance_1, placement=FramePlacement(frames=[1], coordinates=coordinates)
6458
)
6559

6660
object_instances = label_row.get_object_instances()
67-
assert len(object_instances) == 3
61+
assert len(object_instances) == 2
6862

6963
object_instances_on_frame_1 = label_row.get_object_instances(filter_frames=[1])
70-
assert len(object_instances_on_frame_1) == 2
64+
assert len(object_instances_on_frame_1) == 1
65+
66+
object_instances_on_frame_2 = label_row.get_object_instances(filter_frames=[2])
67+
assert len(object_instances_on_frame_2) == 2
68+
7169

7270
def test_place_object_on_video_space(ontology):
7371
# Arrange

0 commit comments

Comments
 (0)