Skip to content

Update transforms for PIL deprecation #5898

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 11 commits into from
May 9, 2022
3 changes: 2 additions & 1 deletion test/test_onnx.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,11 +413,12 @@ def get_image(self, rel_path: str, size: Tuple[int, int]) -> torch.Tensor:
import os

from PIL import Image
import torchvision.transforms._pil_constants as _pil_constants
from torchvision.transforms import functional as F

data_dir = os.path.join(os.path.dirname(__file__), "assets")
path = os.path.join(data_dir, *rel_path.split("/"))
image = Image.open(path).convert("RGB").resize(size, Image.BILINEAR)
image = Image.open(path).convert("RGB").resize(size, _pil_constants.BILINEAR)

return F.convert_image_dtype(F.pil_to_tensor(image))

Expand Down
3 changes: 2 additions & 1 deletion test/test_transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import torchvision.transforms.functional_tensor as F_t
from PIL import Image
from torch._utils_internal import get_file_path_2
import torchvision.transforms._pil_constants as _pil_constants

try:
import accimage
Expand Down Expand Up @@ -173,7 +174,7 @@ def test_accimage_pil_to_tensor(self):
def test_accimage_resize(self):
trans = transforms.Compose(
[
transforms.Resize(256, interpolation=Image.LINEAR),
transforms.Resize(256, interpolation=_pil_constants.LINEAR),
transforms.PILToTensor(),
transforms.ConvertImageDtype(dtype=torch.float),
]
Expand Down
9 changes: 5 additions & 4 deletions test/test_transforms_tensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,12 @@
cpu_and_gpu,
assert_equal,
)
from PIL import Image

from torchvision import transforms as T
from torchvision.transforms import InterpolationMode
from torchvision.transforms import functional as F
from torchvision.transforms.autoaugment import _apply_op
import torchvision.transforms._pil_constants as _pil_constants

NEAREST, BILINEAR, BICUBIC = InterpolationMode.NEAREST, InterpolationMode.BILINEAR, InterpolationMode.BICUBIC

Expand Down Expand Up @@ -771,13 +772,13 @@ def shear(pil_img, level, mode, resample):
matrix = (1, level, 0, 0, 1, 0)
elif mode == "Y":
matrix = (1, 0, 0, level, 1, 0)
return pil_img.transform((image_size, image_size), Image.AFFINE, matrix, resample=resample)
return pil_img.transform((image_size, image_size), _pil_constants.AFFINE, matrix, resample=resample)

t_img, pil_img = _create_data(image_size, image_size)

resample_pil = {
F.InterpolationMode.NEAREST: Image.NEAREST,
F.InterpolationMode.BILINEAR: Image.BILINEAR,
F.InterpolationMode.NEAREST: _pil_constants.NEAREST,
F.InterpolationMode.BILINEAR: _pil_constants.BILINEAR,
}[interpolation]

level = 0.3
Expand Down
22 changes: 22 additions & 0 deletions torchvision/transforms/_pil_constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@

import PIL
from PIL import Image

if tuple(int(part) for part in PIL.__version__.split(".")) >= (9, 1, 0):
FLIP_LEFT_RIGHT = Image.Transpose.FLIP_LEFT_RIGHT
FLIP_TOP_BOTTOM = Image.Transpose.FLIP_TOP_BOTTOM
BILINEAR = Image.Resampling.BILINEAR
NEAREST = Image.Resampling.NEAREST
AFFINE = Image.Transform.AFFINE
BICUBIC = Image.Resampling.BICUBIC
PERSPECTIVE = Image.Transform.PERSPECTIVE
LINEAR = Image.Resampling.BILINEAR
else:
FLIP_LEFT_RIGHT = Image.FLIP_LEFT_RIGHT
FLIP_TOP_BOTTOM = Image.FLIP_TOP_BOTTOM
BILINEAR = Image.BILINEAR
NEAREST = Image.NEAREST
AFFINE = Image.AFFINE
BICUBIC = Image.BICUBIC
PERSPECTIVE = Image.PERSPECTIVE
LINEAR = Image.LINEAR
10 changes: 5 additions & 5 deletions torchvision/transforms/functional.py
Original file line number Diff line number Diff line change
Expand Up @@ -392,7 +392,7 @@ def resize(
:class:`torchvision.transforms.InterpolationMode`.
Default is ``InterpolationMode.BILINEAR``. If input is Tensor, only ``InterpolationMode.NEAREST``,
``InterpolationMode.BILINEAR`` and ``InterpolationMode.BICUBIC`` are supported.
For backward compatibility integer values (e.g. ``PIL.Image.NEAREST``) are still acceptable.
For backward compatibility integer values (e.g. ``PIL.Image(.Resampling).NEAREST``) are still acceptable.
max_size (int, optional): The maximum allowed for the longer edge of
the resized image: if the longer edge of the image is greater
than ``max_size`` after being resized according to ``size``, then
Expand Down Expand Up @@ -572,7 +572,7 @@ def resized_crop(
:class:`torchvision.transforms.InterpolationMode`.
Default is ``InterpolationMode.BILINEAR``. If input is Tensor, only ``InterpolationMode.NEAREST``,
``InterpolationMode.BILINEAR`` and ``InterpolationMode.BICUBIC`` are supported.
For backward compatibility integer values (e.g. ``PIL.Image.NEAREST``) are still acceptable.
For backward compatibility integer values (e.g. ``PIL.Image(.Resampling).NEAREST``) are still acceptable.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm ok with this style in the docstring. Any objections?

Copy link
Member

@NicolasHug NicolasHug May 4, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

() is fine, although as a nit, I think brackets [] are more common (typically in man pages)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kylematoba Could you address this in all docstrings?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, so replace instances of () with [] in my changes thusfar, and a second PR that just removes all of the lines about For backward compatibility integer values?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure, so replace instances of () with [] in my changes thusfar,

Yes.

and a second PR that just removes all of the lines about For backward compatibility integer values?

No. The docstring need to be changed indicating that passing int's is actually deprecated, e.g.

.. warning::
This parameter was deprecated in ``0.12`` and will be removed in ``0.14``. Please use ``interpolation``
instead.

Furthermore, we need to change the warning

if isinstance(interpolation, int):
warnings.warn(
"Argument interpolation should be of type InterpolationMode instead of int. "
"Please, use InterpolationMode enum."
)

to include the concrete deprecation date, e.g.

warnings.warn(
"The parameter 'resample' is deprecated since 0.12 and will be removed 0.14. "
"Please use 'interpolation' instead."
)

For this we will be deprecating in 0.13 and remove in 0.15.


Returns:
PIL Image or Tensor: Cropped image.
Expand Down Expand Up @@ -652,7 +652,7 @@ def perspective(
interpolation (InterpolationMode): Desired interpolation enum defined by
:class:`torchvision.transforms.InterpolationMode`. Default is ``InterpolationMode.BILINEAR``.
If input is Tensor, only ``InterpolationMode.NEAREST``, ``InterpolationMode.BILINEAR`` are supported.
For backward compatibility integer values (e.g. ``PIL.Image.NEAREST``) are still acceptable.
For backward compatibility integer values (e.g. ``PIL.Image(.Resampling).NEAREST``) are still acceptable.
fill (sequence or number, optional): Pixel fill value for the area outside the transformed
image. If given a number, the value is used for all bands respectively.

Expand Down Expand Up @@ -1012,7 +1012,7 @@ def rotate(
interpolation (InterpolationMode): Desired interpolation enum defined by
:class:`torchvision.transforms.InterpolationMode`. Default is ``InterpolationMode.NEAREST``.
If input is Tensor, only ``InterpolationMode.NEAREST``, ``InterpolationMode.BILINEAR`` are supported.
For backward compatibility integer values (e.g. ``PIL.Image.NEAREST``) are still acceptable.
For backward compatibility integer values (e.g. ``PIL.Image(.Resampling).NEAREST``) are still acceptable.
expand (bool, optional): Optional expansion flag.
If true, expands the output image to make it large enough to hold the entire rotated image.
If false or omitted, make the output image the same size as the input image.
Expand Down Expand Up @@ -1105,7 +1105,7 @@ def affine(
interpolation (InterpolationMode): Desired interpolation enum defined by
:class:`torchvision.transforms.InterpolationMode`. Default is ``InterpolationMode.NEAREST``.
If input is Tensor, only ``InterpolationMode.NEAREST``, ``InterpolationMode.BILINEAR`` are supported.
For backward compatibility integer values (e.g. ``PIL.Image.NEAREST``) are still acceptable.
For backward compatibility integer values (e.g. ``PIL.Image(.Resampling).NEAREST``) are still acceptable.
fill (sequence or number, optional): Pixel fill value for the area outside the transformed
image. If given a number, the value is used for all bands respectively.

Expand Down
17 changes: 9 additions & 8 deletions torchvision/transforms/functional_pil.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import accimage
except ImportError:
accimage = None
from . import _pil_constants


@torch.jit.unused
Expand Down Expand Up @@ -54,15 +55,15 @@ def hflip(img: Image.Image) -> Image.Image:
if not _is_pil_image(img):
raise TypeError(f"img should be PIL Image. Got {type(img)}")

return img.transpose(Image.FLIP_LEFT_RIGHT)
return img.transpose(_pil_constants.FLIP_LEFT_RIGHT)


@torch.jit.unused
def vflip(img: Image.Image) -> Image.Image:
if not _is_pil_image(img):
raise TypeError(f"img should be PIL Image. Got {type(img)}")

return img.transpose(Image.FLIP_TOP_BOTTOM)
return img.transpose(_pil_constants.FLIP_TOP_BOTTOM)


@torch.jit.unused
Expand Down Expand Up @@ -240,7 +241,7 @@ def crop(
def resize(
img: Image.Image,
size: Union[Sequence[int], int],
interpolation: int = Image.BILINEAR,
interpolation: int = _pil_constants.BILINEAR,
max_size: Optional[int] = None,
) -> Image.Image:

Expand Down Expand Up @@ -314,7 +315,7 @@ def _parse_fill(
def affine(
img: Image.Image,
matrix: List[float],
interpolation: int = Image.NEAREST,
interpolation: int = _pil_constants.NEAREST,
fill: Optional[Union[float, List[float], Tuple[float, ...]]] = 0,
) -> Image.Image:

Expand All @@ -323,14 +324,14 @@ def affine(

output_size = img.size
opts = _parse_fill(fill, img)
return img.transform(output_size, Image.AFFINE, matrix, interpolation, **opts)
return img.transform(output_size, _pil_constants.AFFINE, matrix, interpolation, **opts)


@torch.jit.unused
def rotate(
img: Image.Image,
angle: float,
interpolation: int = Image.NEAREST,
interpolation: int = _pil_constants.NEAREST,
expand: bool = False,
center: Optional[Tuple[int, int]] = None,
fill: Optional[Union[float, List[float], Tuple[float, ...]]] = 0,
Expand All @@ -347,7 +348,7 @@ def rotate(
def perspective(
img: Image.Image,
perspective_coeffs: float,
interpolation: int = Image.BICUBIC,
interpolation: int = _pil_constants.BICUBIC,
fill: Optional[Union[float, List[float], Tuple[float, ...]]] = 0,
) -> Image.Image:

Expand All @@ -356,7 +357,7 @@ def perspective(

opts = _parse_fill(fill, img)

return img.transform(img.size, Image.PERSPECTIVE, perspective_coeffs, interpolation, **opts)
return img.transform(img.size, _pil_constants.PERSPECTIVE, perspective_coeffs, interpolation, **opts)


@torch.jit.unused
Expand Down
11 changes: 5 additions & 6 deletions torchvision/transforms/transforms.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
from . import functional as F
from .functional import InterpolationMode, _interpolation_modes_from_int


__all__ = [
"Compose",
"ToTensor",
Expand Down Expand Up @@ -298,7 +297,7 @@ class Resize(torch.nn.Module):
:class:`torchvision.transforms.InterpolationMode`. Default is ``InterpolationMode.BILINEAR``.
If input is Tensor, only ``InterpolationMode.NEAREST``, ``InterpolationMode.BILINEAR`` and
``InterpolationMode.BICUBIC`` are supported.
For backward compatibility integer values (e.g. ``PIL.Image.NEAREST``) are still acceptable.
For backward compatibility integer values (e.g. ``PIL.Image(.Resampling).NEAREST``) are still acceptable.
max_size (int, optional): The maximum allowed for the longer edge of
the resized image: if the longer edge of the image is greater
than ``max_size`` after being resized according to ``size``, then
Expand Down Expand Up @@ -755,7 +754,7 @@ class RandomPerspective(torch.nn.Module):
interpolation (InterpolationMode): Desired interpolation enum defined by
:class:`torchvision.transforms.InterpolationMode`. Default is ``InterpolationMode.BILINEAR``.
If input is Tensor, only ``InterpolationMode.NEAREST``, ``InterpolationMode.BILINEAR`` are supported.
For backward compatibility integer values (e.g. ``PIL.Image.NEAREST``) are still acceptable.
For backward compatibility integer values (e.g. ``PIL.Image(.Resampling).NEAREST``) are still acceptable.
fill (sequence or number): Pixel fill value for the area outside the transformed
image. Default is ``0``. If given a number, the value is used for all bands respectively.
"""
Expand Down Expand Up @@ -869,7 +868,7 @@ class RandomResizedCrop(torch.nn.Module):
:class:`torchvision.transforms.InterpolationMode`. Default is ``InterpolationMode.BILINEAR``.
If input is Tensor, only ``InterpolationMode.NEAREST``, ``InterpolationMode.BILINEAR`` and
``InterpolationMode.BICUBIC`` are supported.
For backward compatibility integer values (e.g. ``PIL.Image.NEAREST``) are still acceptable.
For backward compatibility integer values (e.g. ``PIL.Image(.Resampling).NEAREST``) are still acceptable.

"""

Expand Down Expand Up @@ -1268,7 +1267,7 @@ class RandomRotation(torch.nn.Module):
interpolation (InterpolationMode): Desired interpolation enum defined by
:class:`torchvision.transforms.InterpolationMode`. Default is ``InterpolationMode.NEAREST``.
If input is Tensor, only ``InterpolationMode.NEAREST``, ``InterpolationMode.BILINEAR`` are supported.
For backward compatibility integer values (e.g. ``PIL.Image.NEAREST``) are still acceptable.
For backward compatibility integer values (e.g. ``PIL.Image(.Resampling).NEAREST``) are still acceptable.
expand (bool, optional): Optional expansion flag.
If true, expands the output to make it large enough to hold the entire rotated image.
If false or omitted, make the output image the same size as the input image.
Expand Down Expand Up @@ -1389,7 +1388,7 @@ class RandomAffine(torch.nn.Module):
interpolation (InterpolationMode): Desired interpolation enum defined by
:class:`torchvision.transforms.InterpolationMode`. Default is ``InterpolationMode.NEAREST``.
If input is Tensor, only ``InterpolationMode.NEAREST``, ``InterpolationMode.BILINEAR`` are supported.
For backward compatibility integer values (e.g. ``PIL.Image.NEAREST``) are still acceptable.
For backward compatibility integer values (e.g. ``PIL.Image(.Resampling).NEAREST``) are still acceptable.
fill (sequence or number): Pixel fill value for the area outside the transformed
image. Default is ``0``. If given a number, the value is used for all bands respectively.
fillcolor (sequence or number, optional):
Expand Down