Skip to content

Commit faccb5a

Browse files
Rajioba1vikashg
andauthored
Fix clipping boxes with large coordinates (#9047)
Fixes #9045. ### Description `spatial_crop_boxes` converted crop ROI bounds to `torch.int16`, which overflows for coordinates above 32767. This could cause valid boxes in large images to be clamped incorrectly and silently removed when `remove_empty=True`. This PR keeps the ROI bounds in the same tensor dtype as the boxes during clipping and adds a regression test covering both `spatial_crop_boxes` and the public `clip_boxes_to_image` path for large coordinates. ### Types of changes - [x] Non-breaking change (fix or new feature that would not break existing functionality). - [ ] Breaking change (fix or new feature that would cause existing functionality to change). - [x] New tests added to cover the changes. - [ ] Integration tests passed locally by running `./runtests.sh -f -u --net --coverage`. - [ ] Quick tests passed locally by running `./runtests.sh --quick --unittests --disttests`. - [ ] In-line docstrings updated. - [ ] Documentation updated, tested `make html` command in the `docs/` folder. Local validation: - `python -m tests.data.test_box_utils` - `python -m ruff check monai/data/box_utils.py tests/data/test_box_utils.py` `black` and `isort` were not installed in my local Python environment, so I could not run those checks directly. --------- Signed-off-by: Rajioba1 <raji.lukmon@gmail.com> Co-authored-by: Vikash Gupta <write2vikash@gmail.com>
1 parent 87060c4 commit faccb5a

2 files changed

Lines changed: 17 additions & 2 deletions

File tree

monai/data/box_utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1035,8 +1035,8 @@ def spatial_crop_boxes(
10351035
# convert to float32 since torch.clamp_ does not support float16
10361036
boxes_t = boxes_t.to(dtype=COMPUTE_DTYPE)
10371037

1038-
roi_start_t = convert_to_dst_type(src=roi_start, dst=boxes_t, wrap_sequence=True)[0].to(torch.int16)
1039-
roi_end_t = convert_to_dst_type(src=roi_end, dst=boxes_t, wrap_sequence=True)[0].to(torch.int16)
1038+
roi_start_t = convert_to_dst_type(src=roi_start, dst=boxes_t, wrap_sequence=True)[0]
1039+
roi_end_t = convert_to_dst_type(src=roi_end, dst=boxes_t, wrap_sequence=True)[0]
10401040
roi_end_t = torch.maximum(roi_end_t, roi_start_t)
10411041

10421042
# makes sure the bounding boxes are within the patch

tests/data/test_box_utils.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
convert_box_mode,
3636
convert_box_to_standard_mode,
3737
non_max_suppression,
38+
spatial_crop_boxes,
3839
)
3940
from monai.utils.type_conversion import convert_data_type
4041
from tests.test_utils import TEST_NDARRAYS, assert_allclose
@@ -269,6 +270,20 @@ def test_integer_truncation_bug(self):
269270
self.assertTrue(np.issubdtype(iou.dtype, np.floating))
270271
self.assertGreater(iou[0, 0], 0.0, "IoU should not be truncated to 0")
271272

273+
def test_large_coordinates_are_not_dropped(self):
274+
"""Verify large-coordinate boxes are preserved by cropping and clipping."""
275+
boxes = torch.tensor([[41000.0, 5000.0, 45000.0, 15000.0]], dtype=torch.float32)
276+
277+
cropped_boxes, keep = spatial_crop_boxes(
278+
boxes=boxes, roi_start=[40000, 0], roi_end=[50000, 20000], remove_empty=True
279+
)
280+
assert_allclose(keep, torch.tensor([True]))
281+
assert_allclose(cropped_boxes, torch.tensor([[1000.0, 5000.0, 5000.0, 15000.0]]))
282+
283+
clipped_boxes, keep = clip_boxes_to_image(boxes=boxes, spatial_size=[50000, 50000], remove_empty=True)
284+
assert_allclose(keep, torch.tensor([True]))
285+
assert_allclose(clipped_boxes, boxes)
286+
272287

273288
class TestBatchedNms(unittest.TestCase):
274289
@parameterized.expand(TEST_NDARRAYS)

0 commit comments

Comments
 (0)