From 7329dec27369bfe3da2769c1bcebf0a7e833b36c Mon Sep 17 00:00:00 2001 From: Jaesun Park Date: Tue, 4 May 2021 23:52:42 +0900 Subject: [PATCH 1/8] Make crop work the same for pil and tensor --- test/test_transforms_tensor.py | 4 ++++ torchvision/transforms/functional_tensor.py | 7 ++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/test/test_transforms_tensor.py b/test/test_transforms_tensor.py index 4a2f59c6a9b..265336462bd 100644 --- a/test/test_transforms_tensor.py +++ b/test/test_transforms_tensor.py @@ -188,6 +188,10 @@ def test_crop(self): 'crop', 'RandomCrop', fn_kwargs=fn_kwargs, meth_kwargs=meth_kwargs ) + # Test transforms.functional.crop including outside the image area + fn_kwargs = {"top": 7, "left": 8, "height": 4, "width": 5} + self._test_functional_op('crop', fn_kwargs=fn_kwargs) + sizes = [5, [5, ], [6, 6]] padding_configs = [ {"padding_mode": "constant", "fill": 0}, diff --git a/torchvision/transforms/functional_tensor.py b/torchvision/transforms/functional_tensor.py index 156d49150bc..f59ea7bfc72 100644 --- a/torchvision/transforms/functional_tensor.py +++ b/torchvision/transforms/functional_tensor.py @@ -122,7 +122,12 @@ def hflip(img: Tensor) -> Tensor: def crop(img: Tensor, top: int, left: int, height: int, width: int) -> Tensor: _assert_image_tensor(img) - return img[..., top:top + height, left:left + width] + w, h = _get_image_size(img) + right = left + width + bottom = top + height + + padding = [max(-left, 0), max(-top, 0), max(right - w, 0), max(bottom - h, 0)] + return pad(img[..., top:top + height, left:left + width], padding) def rgb_to_grayscale(img: Tensor, num_output_channels: int = 1) -> Tensor: From a1907e070b9b3eba64793d71bc5db487d4960b56 Mon Sep 17 00:00:00 2001 From: Jaesun Park Date: Thu, 6 May 2021 10:27:23 +0900 Subject: [PATCH 2/8] Only call pad if needed in functional_tensor.crop --- torchvision/transforms/functional_tensor.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/torchvision/transforms/functional_tensor.py b/torchvision/transforms/functional_tensor.py index f59ea7bfc72..0e2c6f5ac26 100644 --- a/torchvision/transforms/functional_tensor.py +++ b/torchvision/transforms/functional_tensor.py @@ -126,8 +126,11 @@ def crop(img: Tensor, top: int, left: int, height: int, width: int) -> Tensor: right = left + width bottom = top + height - padding = [max(-left, 0), max(-top, 0), max(right - w, 0), max(bottom - h, 0)] - return pad(img[..., top:top + height, left:left + width], padding) + img = img[..., top:bottom, left:right] + if left < 0 or top < 0 or right > w or bottom < h: + padding_ltrb = [max(-left, 0), max(-top, 0), max(right - w, 0), max(bottom - h, 0)] + img = pad(img, padding_ltrb, fill=0) + return img def rgb_to_grayscale(img: Tensor, num_output_channels: int = 1) -> Tensor: From 81821f503fea5d518bc104f8c8f6dab022ea475c Mon Sep 17 00:00:00 2001 From: Jaesun Park Date: Thu, 6 May 2021 10:36:40 +0900 Subject: [PATCH 3/8] Fix top-left functional_tensor.crop --- test/test_transforms_tensor.py | 2 +- torchvision/transforms/functional_tensor.py | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/test/test_transforms_tensor.py b/test/test_transforms_tensor.py index 265336462bd..c5605b7b928 100644 --- a/test/test_transforms_tensor.py +++ b/test/test_transforms_tensor.py @@ -189,7 +189,7 @@ def test_crop(self): ) # Test transforms.functional.crop including outside the image area - fn_kwargs = {"top": 7, "left": 8, "height": 4, "width": 5} + fn_kwargs = {"top": -2, "left": 8, "height": 4, "width": 5} self._test_functional_op('crop', fn_kwargs=fn_kwargs) sizes = [5, [5, ], [6, 6]] diff --git a/torchvision/transforms/functional_tensor.py b/torchvision/transforms/functional_tensor.py index 0e2c6f5ac26..f117690effc 100644 --- a/torchvision/transforms/functional_tensor.py +++ b/torchvision/transforms/functional_tensor.py @@ -126,11 +126,10 @@ def crop(img: Tensor, top: int, left: int, height: int, width: int) -> Tensor: right = left + width bottom = top + height - img = img[..., top:bottom, left:right] if left < 0 or top < 0 or right > w or bottom < h: padding_ltrb = [max(-left, 0), max(-top, 0), max(right - w, 0), max(bottom - h, 0)] - img = pad(img, padding_ltrb, fill=0) - return img + return pad(img[..., max(top, 0):bottom, max(left, 0):right], padding_ltrb, fill=0) + return img[..., top:bottom, left:right] def rgb_to_grayscale(img: Tensor, num_output_channels: int = 1) -> Tensor: From dc226ff02779d9a22637d6830e1c0485b1e257a3 Mon Sep 17 00:00:00 2001 From: Jaesun Park Date: Thu, 6 May 2021 10:40:01 +0900 Subject: [PATCH 4/8] Update document for functional.crop --- torchvision/transforms/functional.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/torchvision/transforms/functional.py b/torchvision/transforms/functional.py index 855ce19bde4..554bf9af90e 100644 --- a/torchvision/transforms/functional.py +++ b/torchvision/transforms/functional.py @@ -453,7 +453,8 @@ def pad(img: Tensor, padding: List[int], fill: int = 0, padding_mode: str = "con def crop(img: Tensor, top: int, left: int, height: int, width: int) -> Tensor: """Crop the given image at specified location and output size. If the image is torch Tensor, it is expected - to have [..., H, W] shape, where ... means an arbitrary number of leading dimensions + to have [..., H, W] shape, where ... means an arbitrary number of leading dimensions. + If image size is smaller than output size along any edge, image is padded with 0 and then cropped. Args: img (PIL Image or Tensor): Image to be cropped. (0,0) denotes the top left corner of the image. From 3906799dfdf7a7abd259ecec1d3251def451819c Mon Sep 17 00:00:00 2001 From: Jaesun Park Date: Sun, 16 May 2021 13:55:41 +0900 Subject: [PATCH 5/8] Add other test cases of functional.crop --- test/test_transforms_tensor.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/test/test_transforms_tensor.py b/test/test_transforms_tensor.py index c5605b7b928..b743f54fa1a 100644 --- a/test/test_transforms_tensor.py +++ b/test/test_transforms_tensor.py @@ -189,7 +189,19 @@ def test_crop(self): ) # Test transforms.functional.crop including outside the image area - fn_kwargs = {"top": -2, "left": 8, "height": 4, "width": 5} + fn_kwargs = {"top": -2, "left": 3, "height": 4, "width": 5} # top + self._test_functional_op('crop', fn_kwargs=fn_kwargs) + + fn_kwargs = {"top": 1, "left": -3, "height": 4, "width": 5} # left + self._test_functional_op('crop', fn_kwargs=fn_kwargs) + + fn_kwargs = {"top": 7, "left": 3, "height": 4, "width": 5} # bottom + self._test_functional_op('crop', fn_kwargs=fn_kwargs) + + fn_kwargs = {"top": 3, "left": 8, "height": 4, "width": 5} # right + self._test_functional_op('crop', fn_kwargs=fn_kwargs) + + fn_kwargs = {"top": -3, "left": -3, "height": 15, "width": 15} # all self._test_functional_op('crop', fn_kwargs=fn_kwargs) sizes = [5, [5, ], [6, 6]] From d319901f86e14e166d3c8205bc610d26a939b197 Mon Sep 17 00:00:00 2001 From: Jaesun Park Date: Sun, 16 May 2021 13:56:16 +0900 Subject: [PATCH 6/8] Fix bug --- torchvision/transforms/functional_tensor.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/torchvision/transforms/functional_tensor.py b/torchvision/transforms/functional_tensor.py index f117690effc..67b905700cd 100644 --- a/torchvision/transforms/functional_tensor.py +++ b/torchvision/transforms/functional_tensor.py @@ -126,7 +126,7 @@ def crop(img: Tensor, top: int, left: int, height: int, width: int) -> Tensor: right = left + width bottom = top + height - if left < 0 or top < 0 or right > w or bottom < h: + if left < 0 or top < 0 or right > w or bottom > h: padding_ltrb = [max(-left, 0), max(-top, 0), max(right - w, 0), max(bottom - h, 0)] return pad(img[..., max(top, 0):bottom, max(left, 0):right], padding_ltrb, fill=0) return img[..., top:bottom, left:right] From 1c4c85c1883feee062343b7db122dd4745cf8821 Mon Sep 17 00:00:00 2001 From: Vasilis Vryniotis Date: Mon, 17 May 2021 13:55:03 +0000 Subject: [PATCH 7/8] Fixing formattter --- test/test_transforms_tensor.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/test_transforms_tensor.py b/test/test_transforms_tensor.py index b743f54fa1a..8c85b66b8dd 100644 --- a/test/test_transforms_tensor.py +++ b/test/test_transforms_tensor.py @@ -189,19 +189,19 @@ def test_crop(self): ) # Test transforms.functional.crop including outside the image area - fn_kwargs = {"top": -2, "left": 3, "height": 4, "width": 5} # top + fn_kwargs = {"top": -2, "left": 3, "height": 4, "width": 5} # top self._test_functional_op('crop', fn_kwargs=fn_kwargs) - fn_kwargs = {"top": 1, "left": -3, "height": 4, "width": 5} # left + fn_kwargs = {"top": 1, "left": -3, "height": 4, "width": 5} # left self._test_functional_op('crop', fn_kwargs=fn_kwargs) - fn_kwargs = {"top": 7, "left": 3, "height": 4, "width": 5} # bottom + fn_kwargs = {"top": 7, "left": 3, "height": 4, "width": 5} # bottom self._test_functional_op('crop', fn_kwargs=fn_kwargs) - fn_kwargs = {"top": 3, "left": 8, "height": 4, "width": 5} # right + fn_kwargs = {"top": 3, "left": 8, "height": 4, "width": 5} # right self._test_functional_op('crop', fn_kwargs=fn_kwargs) - fn_kwargs = {"top": -3, "left": -3, "height": 15, "width": 15} # all + fn_kwargs = {"top": -3, "left": -3, "height": 15, "width": 15} # all self._test_functional_op('crop', fn_kwargs=fn_kwargs) sizes = [5, [5, ], [6, 6]] From fb42e42417412d8fe0109dbe5b2d93798a9c9412 Mon Sep 17 00:00:00 2001 From: Vasilis Vryniotis Date: Mon, 17 May 2021 14:58:52 +0100 Subject: [PATCH 8/8] Fix stylings --- test/test_transforms_tensor.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/test/test_transforms_tensor.py b/test/test_transforms_tensor.py index 8c85b66b8dd..2c598e90833 100644 --- a/test/test_transforms_tensor.py +++ b/test/test_transforms_tensor.py @@ -189,19 +189,19 @@ def test_crop(self): ) # Test transforms.functional.crop including outside the image area - fn_kwargs = {"top": -2, "left": 3, "height": 4, "width": 5} # top + fn_kwargs = {"top": -2, "left": 3, "height": 4, "width": 5} # top self._test_functional_op('crop', fn_kwargs=fn_kwargs) - fn_kwargs = {"top": 1, "left": -3, "height": 4, "width": 5} # left + fn_kwargs = {"top": 1, "left": -3, "height": 4, "width": 5} # left self._test_functional_op('crop', fn_kwargs=fn_kwargs) - fn_kwargs = {"top": 7, "left": 3, "height": 4, "width": 5} # bottom + fn_kwargs = {"top": 7, "left": 3, "height": 4, "width": 5} # bottom self._test_functional_op('crop', fn_kwargs=fn_kwargs) - fn_kwargs = {"top": 3, "left": 8, "height": 4, "width": 5} # right + fn_kwargs = {"top": 3, "left": 8, "height": 4, "width": 5} # right self._test_functional_op('crop', fn_kwargs=fn_kwargs) - fn_kwargs = {"top": -3, "left": -3, "height": 15, "width": 15} # all + fn_kwargs = {"top": -3, "left": -3, "height": 15, "width": 15} # all self._test_functional_op('crop', fn_kwargs=fn_kwargs) sizes = [5, [5, ], [6, 6]]