|
1 | 1 | from contextlib import ExitStack as DoesNotRaise |
| 2 | +from unittest.mock import patch |
2 | 3 |
|
3 | 4 | import numpy as np |
4 | 5 | import numpy.typing as npt |
@@ -78,6 +79,33 @@ def test_compact_masks_to_roi_single_detection_coordinates(self): |
78 | 79 | assert x2 >= 8 |
79 | 80 | assert y2 >= 10 |
80 | 81 |
|
| 82 | + def test_all_false_compact_masks_have_no_roi(self) -> None: |
| 83 | + """A nonempty compact collection without foreground has no ROI.""" |
| 84 | + masks = np.zeros((1, 60, 80), dtype=bool) |
| 85 | + xyxy = np.array([[0, 0, 79, 59]], dtype=np.float32) |
| 86 | + compact = CompactMask.from_dense(masks, xyxy, image_shape=(60, 80)) |
| 87 | + |
| 88 | + result = _compact_masks_to_roi(compact, (60, 80)) |
| 89 | + |
| 90 | + assert result is None |
| 91 | + |
| 92 | + @pytest.mark.parametrize("empty_index", [0, 1]) |
| 93 | + def test_empty_compact_crops_do_not_expand_roi(self, empty_index: int) -> None: |
| 94 | + """An empty full-frame crop leaves the foreground crop's bounds unchanged.""" |
| 95 | + masks = np.zeros((2, 60, 80), dtype=bool) |
| 96 | + masks[1 - empty_index, 40:45, 60:65] = True |
| 97 | + xyxy = np.array([[0, 0, 79, 59], [0, 0, 79, 59]], dtype=np.float32) |
| 98 | + xyxy[1 - empty_index] = [60, 40, 64, 44] |
| 99 | + compact = CompactMask.from_dense(masks, xyxy, image_shape=(60, 80)) |
| 100 | + |
| 101 | + with ( |
| 102 | + patch.object(CompactMask, "to_dense", side_effect=AssertionError), |
| 103 | + patch.object(CompactMask, "crop", side_effect=AssertionError), |
| 104 | + ): |
| 105 | + result = _compact_masks_to_roi(compact, (60, 80)) |
| 106 | + |
| 107 | + assert result == (60, 40, 65, 45) |
| 108 | + |
81 | 109 | def test_compact_masks_to_roi_two_detections_union(self): |
82 | 110 | """Two disjoint compact masks union should span both regions.""" |
83 | 111 | masks = np.zeros((2, 30, 40), dtype=bool) |
@@ -153,6 +181,20 @@ def test_masks_to_roi_dense_with_xyxy_all_false_returns_none(self): |
153 | 181 | result = _masks_to_roi(masks, (30, 40), xyxy) |
154 | 182 | assert result is None |
155 | 183 |
|
| 184 | + @pytest.mark.parametrize("empty_index", [0, 1]) |
| 185 | + def test_masks_to_roi_dense_with_xyxy_ignores_empty_mask_boxes( |
| 186 | + self, empty_index: int |
| 187 | + ) -> None: |
| 188 | + """An all-False mask's full-frame box does not widen the dense box union.""" |
| 189 | + masks = np.zeros((2, 60, 80), dtype=bool) |
| 190 | + masks[1 - empty_index, 40:45, 60:65] = True |
| 191 | + xyxy = np.array([[0, 0, 79, 59], [0, 0, 79, 59]], dtype=np.float32) |
| 192 | + xyxy[1 - empty_index] = [60, 40, 64, 44] |
| 193 | + |
| 194 | + result = _masks_to_roi(masks, (60, 80), xyxy) |
| 195 | + |
| 196 | + assert result == (60, 40, 65, 45) |
| 197 | + |
156 | 198 |
|
157 | 199 | def test_resize_masks_does_not_upscale_small_masks() -> None: |
158 | 200 | """resize_masks returns small masks unchanged instead of upscaling.""" |
|
0 commit comments