diff --git a/detectron2/data/detection_utils.py b/detectron2/data/detection_utils.py index ea1e41e2a0..7f125340b0 100644 --- a/detectron2/data/detection_utils.py +++ b/detectron2/data/detection_utils.py @@ -10,7 +10,7 @@ import pycocotools.mask as mask_util import torch from fvcore.common.file_io import PathManager -from PIL import Image, ImageOps +from PIL import Image from detectron2.structures import ( BitMasks, @@ -37,6 +37,9 @@ class SizeMismatchError(ValueError): _M_RGB2YUV = [[0.299, 0.587, 0.114], [-0.14713, -0.28886, 0.436], [0.615, -0.51499, -0.10001]] _M_YUV2RGB = [[1.0, 0.0, 1.13983], [1.0, -0.39465, -0.58060], [1.0, 2.03211, 0.0]] +# https://www.exiv2.org/tags.html +_EXIF_ORIENT = 274 # exif 'Orientation' tag + def convert_PIL_to_numpy(image, format): """ @@ -97,6 +100,50 @@ def convert_image_to_rgb(image, format): return image +def _apply_exif_orientation(image): + """ + Applies the exif orientation correctly. + + This code exists per the bug: + https://github.com/python-pillow/Pillow/issues/3973 + with the function `ImageOps.exif_transpose`. The Pillow source raises errors with + various methods, especially `tobytes` + + Function based on: + https://github.com/wkentaro/labelme/blob/v4.5.4/labelme/utils/image.py#L59 + https://github.com/python-pillow/Pillow/blob/7.1.2/src/PIL/ImageOps.py#L527 + + Args: + image (PIL.Image): a PIL image + + Returns: + (PIL.Image): the PIL image with exif orientation applied, if applicable + """ + if not hasattr(image, "getexif"): + return image + + exif = image.getexif() + + if exif is None: + return image + + orientation = exif.get(_EXIF_ORIENT) + + method = { + 2: Image.FLIP_LEFT_RIGHT, + 3: Image.ROTATE_180, + 4: Image.FLIP_TOP_BOTTOM, + 5: Image.TRANSPOSE, + 6: Image.ROTATE_270, + 7: Image.TRANSVERSE, + 8: Image.ROTATE_90, + }.get(orientation) + + if method is not None: + return image.transpose(method) + return image + + def read_image(file_name, format=None): """ Read an image into the given format. @@ -113,11 +160,8 @@ def read_image(file_name, format=None): with PathManager.open(file_name, "rb") as f: image = Image.open(f) - # capture and ignore this bug: https://github.com/python-pillow/Pillow/issues/3973 - try: - image = ImageOps.exif_transpose(image) - except Exception: - pass + # work around this bug: https://github.com/python-pillow/Pillow/issues/3973 + image = _apply_exif_orientation(image) return convert_PIL_to_numpy(image, format)