Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/supervision/annotators/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,8 +585,15 @@ def annotate(
if detections.mask is None:
return scene

masks = detections.mask
compact_mask = masks if isinstance(masks, CompactMask) else None
for detection_idx in range(len(detections)):
mask = cast(npt.NDArray[np.bool_], detections.mask[detection_idx])
if compact_mask is None:
mask = cast(npt.NDArray[np.bool_], masks[detection_idx])
offset = None
else:
mask = compact_mask.crop(detection_idx)
offset = compact_mask.offsets[detection_idx]
color = resolve_color(
color=self.color,
detections=detections,
Expand All @@ -596,6 +603,8 @@ def annotate(
else custom_color_lookup,
)
for polygon in mask_to_polygons(mask=mask):
if offset is not None:
polygon = polygon + offset
scene = draw_polygon(
scene=scene,
polygon=cast(npt.NDArray[np.int_], polygon),
Expand Down
37 changes: 37 additions & 0 deletions tests/annotators/test_core.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,43 @@ def test_annotate_with_single_mask(self, test_image, test_mask):
result = annotator.annotate(scene=test_image.copy(), detections=detections)
assert_image_mostly_same(test_image, result, similarity_threshold=0.85)

def test_compact_mask_uses_crops_and_matches_dense_mask(self, monkeypatch):
"""CompactMask polygons use crops without full-frame mask indexing."""
height, width = 80, 90
scene = np.zeros((height, width, 3), dtype=np.uint8)
masks = np.zeros((3, height, width), dtype=bool)
masks[0, 10:20, 15:30] = True
masks[0, 32:45, 40:55] = True
masks[1] = False
masks[2, 50:70, 5:25] = True
xyxy = np.array(
[[15, 10, 54, 44], [60, 5, 70, 15], [5, 50, 24, 69]],
dtype=np.float32,
)
dense = Detections(xyxy=xyxy, mask=masks, class_id=np.array([0, 1, 2]))
compact = Detections(
xyxy=xyxy,
mask=CompactMask.from_dense(masks, xyxy, (height, width)),
class_id=np.array([0, 1, 2]),
)
annotator = PolygonAnnotator(
color=Color.WHITE, thickness=1, color_lookup=ColorLookup.INDEX
)
expected = annotator.annotate(scene=scene.copy(), detections=dense)

original_getitem = CompactMask.__getitem__

def fail_int_index(self, index):
if isinstance(index, (int, np.integer)):
raise AssertionError("PolygonAnnotator must use CompactMask.crop")
return original_getitem(self, index)

monkeypatch.setattr(CompactMask, "__getitem__", fail_int_index)
result = annotator.annotate(scene=scene.copy(), detections=compact)

assert not np.array_equal(result, scene), "annotator painted nothing"
np.testing.assert_array_equal(result, expected)


class TestColorAnnotator:
"""Tests for ColorAnnotator class"""
Expand Down
Loading