diff --git a/test/test_transforms_v2.py b/test/test_transforms_v2.py index 6d9f9732552..30473a0c496 100644 --- a/test/test_transforms_v2.py +++ b/test/test_transforms_v2.py @@ -4456,6 +4456,17 @@ def test_xywh_cxcywh_direct_conversion_parity(self, old_format, dtype, device): torch.testing.assert_close(actual, expected) + @pytest.mark.parametrize("dtype, values, expected", [ + (torch.uint8, [[200, 10, 220, 30]], [[210, 20, 20, 20]]), + (torch.float16, [[32768, 0, 49152, 32]], [[40960, 16, 16384, 32]]), + ]) + def test_xyxy_to_cxcywh_no_intermediate_overflow(self, dtype, values, expected): + boxes = tv_tensors.BoundingBoxes( + values, format=tv_tensors.BoundingBoxFormat.XYXY, canvas_size=(65536, 65536), dtype=dtype + ) + actual = F.convert_bounding_box_format(boxes, new_format=tv_tensors.BoundingBoxFormat.CXCYWH) + torch.testing.assert_close(actual, torch.tensor(expected, dtype=dtype)) + def test_cxcywh_to_xyxy_odd_dimensions(self): # Non-regression test for https://github.com/pytorch/vision/issues/8887 # Integer bounding boxes with odd width/height produced incorrect results diff --git a/torchvision/transforms/v2/functional/_meta.py b/torchvision/transforms/v2/functional/_meta.py index 80bd23a926d..9424f2e9b7f 100644 --- a/torchvision/transforms/v2/functional/_meta.py +++ b/torchvision/transforms/v2/functional/_meta.py @@ -228,8 +228,11 @@ def _xyxy_to_cxcywh(xyxy: torch.Tensor, inplace: bool) -> torch.Tensor: # (x2 - x1) = width, same for height xyxy[..., 2:].sub_(xyxy[..., :2]) - # (x1 * 2 + width) / 2 = x1 + width / 2 = x1 + (x2-x1)/2 = (x1 + x2)/2 = cx, same for cy - xyxy[..., :2].mul_(2).add_(xyxy[..., 2:]).div_(2, rounding_mode=None if xyxy.is_floating_point() else "floor") + # x1 + width / 2 avoids overflowing the x1 * 2 intermediate. + if xyxy.is_floating_point(): + xyxy[..., :2].add_(xyxy[..., 2:] / 2) + else: + xyxy[..., :2].add_(xyxy[..., 2:].div(2, rounding_mode="floor")) return xyxy