From fba5ff21a378550199a90c7cb348810838d48f6b Mon Sep 17 00:00:00 2001 From: Aditya Oke Date: Thu, 23 Sep 2021 19:57:22 +0530 Subject: [PATCH 1/4] Update test and fix docstring --- test/test_masks_to_boxes.py | 34 -------------------------------- test/test_ops.py | 39 +++++++++++++++++++++++++++++++++++++ torchvision/ops/boxes.py | 12 ++++++------ 3 files changed, 45 insertions(+), 40 deletions(-) delete mode 100644 test/test_masks_to_boxes.py diff --git a/test/test_masks_to_boxes.py b/test/test_masks_to_boxes.py deleted file mode 100644 index 7182ebcae9f..00000000000 --- a/test/test_masks_to_boxes.py +++ /dev/null @@ -1,34 +0,0 @@ -import os.path - -import PIL.Image -import numpy -import torch - -from torchvision.ops import masks_to_boxes - -ASSETS_DIRECTORY = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets") - - -def test_masks_to_boxes(): - with PIL.Image.open(os.path.join(ASSETS_DIRECTORY, "masks.tiff")) as image: - masks = torch.zeros((image.n_frames, image.height, image.width), dtype=torch.int) - - for index in range(image.n_frames): - image.seek(index) - - frame = numpy.array(image) - - masks[index] = torch.tensor(frame) - - expected = torch.tensor( - [[127, 2, 165, 40], - [2, 50, 44, 92], - [56, 63, 98, 100], - [139, 68, 175, 104], - [160, 112, 198, 145], - [49, 138, 99, 182], - [108, 148, 152, 213]], - dtype=torch.int32 - ) - - torch.testing.assert_close(masks_to_boxes(masks), expected) diff --git a/test/test_ops.py b/test/test_ops.py index c64ba1fd0bb..b45f114dcd0 100644 --- a/test/test_ops.py +++ b/test/test_ops.py @@ -4,7 +4,9 @@ import pytest import numpy as np +import os +from PIL import Image import torch from functools import lru_cache from torch import Tensor @@ -1000,6 +1002,43 @@ def gen_iou_check(box, expected, tolerance=1e-4): gen_iou_check(box_tensor, expected, tolerance=0.002 if dtype == torch.float16 else 1e-3) +class TestMasksToBoxes: + def test_masks_box(self): + def masks_box_check(masks, expected, tolerance=1e-4): + out = ops.masks_to_boxes(masks) + torch.testing.assert_close(out, expected, rtol=0.0, check_dtype=False, atol=tolerance) + + # Check for int type boxes. + def _get_image(): + assets_directory = os.path.join(os.path.dirname(os.path.abspath(__file__)), "assets") + mask_path = os.path.join(assets_directory, "masks.tiff") + image = Image.open(mask_path) + return image + + def _create_masks(image, masks): + for index in range(image.n_frames): + image.seek(index) + frame = np.array(image) + masks[index] = torch.tensor(frame) + + return masks + + image = _get_image() + expected = torch.tensor([[127, 2, 165, 40], [2, 50, 44, 92], [56, 63, 98, 100], [139, 68, 175, 104], + [160, 112, 198, 145], [49, 138, 99, 182], [108, 148, 152, 213]]) + + for dtype in [torch.int16, torch.int32, torch.int64]: + masks = torch.zeros((image.n_frames, image.height, image.width), dtype=dtype) + masks = _create_masks(image, masks) + masks_box_check(masks, expected) + + image2 = _get_image() + for dtype in [torch.float16, torch.float32, torch.float64]: + masks = torch.zeros((image2.n_frames, image2.height, image2.width), dtype=dtype) + masks = _create_masks(image, masks) + masks_box_check(masks, expected) + + class TestStochasticDepth: @pytest.mark.parametrize('p', [0.2, 0.5, 0.8]) @pytest.mark.parametrize('mode', ["batch", "row"]) diff --git a/torchvision/ops/boxes.py b/torchvision/ops/boxes.py index 6dafcf1c190..2c0cfd84eac 100644 --- a/torchvision/ops/boxes.py +++ b/torchvision/ops/boxes.py @@ -301,24 +301,24 @@ def generalized_box_iou(boxes1: Tensor, boxes2: Tensor) -> Tensor: def masks_to_boxes(masks: torch.Tensor) -> torch.Tensor: """ - Compute the bounding boxes around the provided masks + Compute the bounding boxes around the provided masks. - Returns a [N, 4] tensor. Both sets of boxes are expected to be in ``(x1, y1, x2, y2)`` format with + Returns a [N, 4] tensor containing bounding boxes. The boxes are in ``(x1, y1, x2, y2)`` format with ``0 <= x1 < x2`` and ``0 <= y1 < y2``. Args: - masks (Tensor[N, H, W]): masks to transform where N is the number of - masks and (H, W) are the spatial dimensions. + masks (Tensor[N, H, W]): masks to transform where N is the number of masks + and (H, W) are the spatial dimensions. Returns: Tensor[N, 4]: bounding boxes """ if masks.numel() == 0: - return torch.zeros((0, 4)) + return torch.zeros((0, 4), device=masks.device, dtype=torch.float) n = masks.shape[0] - bounding_boxes = torch.zeros((n, 4), device=masks.device, dtype=torch.int) + bounding_boxes = torch.zeros((n, 4), device=masks.device, dtype=torch.float) for index, mask in enumerate(masks): y, x = torch.where(masks[index] != 0) From 749467c91f067798aa5f4e7dfedb0eeac2411433 Mon Sep 17 00:00:00 2001 From: Aditya Oke Date: Thu, 23 Sep 2021 22:00:27 +0530 Subject: [PATCH 2/4] Remove int test, check float dtype --- test/test_ops.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/test_ops.py b/test/test_ops.py index b45f114dcd0..4fbbe3204b4 100644 --- a/test/test_ops.py +++ b/test/test_ops.py @@ -1006,6 +1006,7 @@ class TestMasksToBoxes: def test_masks_box(self): def masks_box_check(masks, expected, tolerance=1e-4): out = ops.masks_to_boxes(masks) + assert out.dtype == torch.float torch.testing.assert_close(out, expected, rtol=0.0, check_dtype=False, atol=tolerance) # Check for int type boxes. @@ -1025,12 +1026,7 @@ def _create_masks(image, masks): image = _get_image() expected = torch.tensor([[127, 2, 165, 40], [2, 50, 44, 92], [56, 63, 98, 100], [139, 68, 175, 104], - [160, 112, 198, 145], [49, 138, 99, 182], [108, 148, 152, 213]]) - - for dtype in [torch.int16, torch.int32, torch.int64]: - masks = torch.zeros((image.n_frames, image.height, image.width), dtype=dtype) - masks = _create_masks(image, masks) - masks_box_check(masks, expected) + [160, 112, 198, 145], [49, 138, 99, 182], [108, 148, 152, 213]], dtype=torch.float) image2 = _get_image() for dtype in [torch.float16, torch.float32, torch.float64]: From 39cd48028795e8fe4d6042e29f5129b167e20150 Mon Sep 17 00:00:00 2001 From: Aditya Oke Date: Thu, 23 Sep 2021 22:17:36 +0530 Subject: [PATCH 3/4] Cleaup code --- test/test_ops.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/test_ops.py b/test/test_ops.py index 4fbbe3204b4..9d194d09f80 100644 --- a/test/test_ops.py +++ b/test/test_ops.py @@ -1024,14 +1024,13 @@ def _create_masks(image, masks): return masks - image = _get_image() expected = torch.tensor([[127, 2, 165, 40], [2, 50, 44, 92], [56, 63, 98, 100], [139, 68, 175, 104], [160, 112, 198, 145], [49, 138, 99, 182], [108, 148, 152, 213]], dtype=torch.float) image2 = _get_image() for dtype in [torch.float16, torch.float32, torch.float64]: masks = torch.zeros((image2.n_frames, image2.height, image2.width), dtype=dtype) - masks = _create_masks(image, masks) + masks = _create_masks(image2, masks) masks_box_check(masks, expected) From 0ae6bdfe353577911307d3aeab526c6b206f0b0c Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Fri, 24 Sep 2021 08:32:06 +0100 Subject: [PATCH 4/4] rename image2 into image --- test/test_ops.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/test_ops.py b/test/test_ops.py index 9d194d09f80..8ab23f3ff64 100644 --- a/test/test_ops.py +++ b/test/test_ops.py @@ -1027,10 +1027,10 @@ def _create_masks(image, masks): expected = torch.tensor([[127, 2, 165, 40], [2, 50, 44, 92], [56, 63, 98, 100], [139, 68, 175, 104], [160, 112, 198, 145], [49, 138, 99, 182], [108, 148, 152, 213]], dtype=torch.float) - image2 = _get_image() + image = _get_image() for dtype in [torch.float16, torch.float32, torch.float64]: - masks = torch.zeros((image2.n_frames, image2.height, image2.width), dtype=dtype) - masks = _create_masks(image2, masks) + masks = torch.zeros((image.n_frames, image.height, image.width), dtype=dtype) + masks = _create_masks(image, masks) masks_box_check(masks, expected)