Unverified Commit 227e7a73 authored by Tong Gao's avatar Tong Gao Committed by GitHub
Browse files

Support image reading while ignoring EXIF orientation info (#1091)

* Support image reading while ignoring EXIF orientation info

Add unit test for ignore_orientation flags in imread()

* add documentation for imread

* Add test cases
parent 94818ad1
......@@ -5,7 +5,8 @@ from pathlib import Path
import cv2
import numpy as np
from cv2 import IMREAD_COLOR, IMREAD_GRAYSCALE, IMREAD_UNCHANGED
from cv2 import (IMREAD_COLOR, IMREAD_GRAYSCALE, IMREAD_IGNORE_ORIENTATION,
IMREAD_UNCHANGED)
from mmcv.utils import check_file_exist, is_str, mkdir_or_exist
......@@ -30,7 +31,10 @@ supported_backends = ['cv2', 'turbojpeg', 'pillow', 'tifffile']
imread_flags = {
'color': IMREAD_COLOR,
'grayscale': IMREAD_GRAYSCALE,
'unchanged': IMREAD_UNCHANGED
'unchanged': IMREAD_UNCHANGED,
'color_ignore_orientation': IMREAD_IGNORE_ORIENTATION | IMREAD_COLOR,
'grayscale_ignore_orientation':
IMREAD_IGNORE_ORIENTATION | IMREAD_GRAYSCALE
}
imread_backend = 'cv2'
......@@ -102,7 +106,8 @@ def _pillow2array(img, flag='color', channel_order='bgr'):
array[:, :, :3] = array[:, :, (2, 1, 0)] # RGB to BGR
else:
# Handle exif orientation tag
img = ImageOps.exif_transpose(img)
if flag in ['color', 'grayscale']:
img = ImageOps.exif_transpose(img)
# If the image mode is not 'RGB', convert it to 'RGB' first.
if img.mode != 'RGB':
if img.mode != 'LA':
......@@ -117,17 +122,18 @@ def _pillow2array(img, flag='color', channel_order='bgr'):
img_rgba = img.convert('RGBA')
img = Image.new('RGB', img_rgba.size, (124, 117, 104))
img.paste(img_rgba, mask=img_rgba.split()[3]) # 3 is alpha
if flag == 'color':
if flag in ['color', 'color_ignore_orientation']:
array = np.array(img)
if channel_order != 'rgb':
array = array[:, :, ::-1] # RGB to BGR
elif flag == 'grayscale':
elif flag in ['grayscale', 'grayscale_ignore_orientation']:
img = img.convert('L')
array = np.array(img)
else:
raise ValueError(
'flag must be "color", "grayscale" or "unchanged", '
f'but got {flag}')
'flag must be "color", "grayscale", "unchanged", '
f'"color_ignore_orientation" or "grayscale_ignore_orientation"'
f' but got {flag}')
return array
......@@ -139,8 +145,13 @@ def imread(img_or_path, flag='color', channel_order='bgr', backend=None):
pathlib.Path. If it is a numpy array (loaded image), then
it will be returned as is.
flag (str): Flags specifying the color type of a loaded image,
candidates are `color`, `grayscale` and `unchanged`.
Note that the `turbojpeg` backend does not support `unchanged`.
candidates are `color`, `grayscale`, `unchanged`,
`color_ignore_orientation` and `grayscale_ignore_orientation`.
By default, `cv2` and `pillow` backend would rotate the image
according to its EXIF info unless called with `unchanged` or
`*_ignore_orientation` flags. `turbojpeg` and `tifffile` backend
always ignore image's EXIF info regardless of the flag.
The `turbojpeg` backend only supports `color` and `grayscale`.
channel_order (str): Order of channel, candidates are `bgr` and `rgb`.
backend (str | None): The image decoding backend type. Options are
`cv2`, `pillow`, `turbojpeg`, `tifffile`, `None`.
......
......@@ -184,12 +184,30 @@ class TestIO:
# consistent exif behaviour
img_cv2_exif = mmcv.imread(self.exif_img_path)
img_pil_exif = mmcv.imread(self.exif_img_path, backend='pillow')
assert img_cv2_exif.shape == img_pil_exif.shape
assert img_cv2_exif.shape == (400, 300, 3)
assert img_pil_exif.shape == (400, 300, 3)
img_cv2_exif_unchanged = mmcv.imread(
self.exif_img_path, flag='unchanged')
img_pil_exif_unchanged = mmcv.imread(
self.exif_img_path, backend='pillow', flag='unchanged')
assert img_cv2_exif_unchanged.shape == img_pil_exif_unchanged.shape
assert img_cv2_exif_unchanged.shape == (300, 400, 3)
assert img_pil_exif_unchanged.shape == (300, 400, 3)
img_cv2_color_ignore_exif = mmcv.imread(
self.exif_img_path, flag='color_ignore_orientation')
img_pil_color_ignore_exif = mmcv.imread(
self.exif_img_path,
backend='pillow',
flag='color_ignore_orientation')
assert img_cv2_color_ignore_exif.shape == (300, 400, 3)
assert img_pil_color_ignore_exif.shape == (300, 400, 3)
img_cv2_grayscale_ignore_exif = mmcv.imread(
self.exif_img_path, flag='grayscale_ignore_orientation')
img_pil_grayscale_ignore_exif = mmcv.imread(
self.exif_img_path,
backend='pillow',
flag='grayscale_ignore_orientation')
assert img_cv2_grayscale_ignore_exif.shape == (300, 400)
assert img_pil_grayscale_ignore_exif.shape == (300, 400)
def test_imfrombytes(self):
# backend cv2, channel order: bgr
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment