Skip to content
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

Correctly apply EXIF orientation to images #1666

Closed
wants to merge 4 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 50 additions & 6 deletions detectron2/data/detection_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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):
"""
Expand Down Expand Up @@ -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.
Expand All @@ -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)

Expand Down