added pillow backend in loading (#333)

* added pillow backend in loading

* reformat

* remove auto fill for RGBA

* change according to comments

* change according to comments

* reformat
pull/351/head
Wang Xinjiang 2020-06-17 10:25:48 +08:00 committed by GitHub
parent 3f4c9fd0c8
commit 630b747cb1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 161 additions and 38 deletions

View File

@ -1,35 +1,35 @@
@ECHO OFF @ECHO OFF
pushd %~dp0 pushd %~dp0
REM Command file for Sphinx documentation REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" ( if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build set SPHINXBUILD=sphinx-build
) )
set SOURCEDIR=. set SOURCEDIR=.
set BUILDDIR=_build set BUILDDIR=_build
if "%1" == "" goto help if "%1" == "" goto help
%SPHINXBUILD% >NUL 2>NUL %SPHINXBUILD% >NUL 2>NUL
if errorlevel 9009 ( if errorlevel 9009 (
echo. echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH. echo.may add the Sphinx directory to PATH.
echo. echo.
echo.If you don't have Sphinx installed, grab it from echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/ echo.http://sphinx-doc.org/
exit /b 1 exit /b 1
) )
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
goto end goto end
:help :help
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
:end :end
popd popd

View File

@ -1,4 +1,5 @@
# Copyright (c) Open-MMLab. All rights reserved. # Copyright (c) Open-MMLab. All rights reserved.
import io
import os.path as osp import os.path as osp
from pathlib import Path from pathlib import Path
@ -13,8 +14,13 @@ try:
except ImportError: except ImportError:
TJCS_RGB = TJPF_GRAY = TJPF_BGR = TurboJPEG = None TJCS_RGB = TJPF_GRAY = TJPF_BGR = TurboJPEG = None
try:
from PIL import Image
except ImportError:
Image = None
jpeg = None jpeg = None
supported_backends = ['cv2', 'turbojpeg'] supported_backends = ['cv2', 'turbojpeg', 'pillow']
imread_flags = { imread_flags = {
'color': IMREAD_COLOR, 'color': IMREAD_COLOR,
@ -42,6 +48,9 @@ def use_backend(backend):
global jpeg global jpeg
if jpeg is None: if jpeg is None:
jpeg = TurboJPEG() jpeg = TurboJPEG()
elif imread_backend == 'pillow':
if Image is None:
raise ImportError('`Pillow` is not installed')
def _jpegflag(flag='color', channel_order='bgr'): def _jpegflag(flag='color', channel_order='bgr'):
@ -60,6 +69,57 @@ def _jpegflag(flag='color', channel_order='bgr'):
raise ValueError('flag must be "color" or "grayscale"') raise ValueError('flag must be "color" or "grayscale"')
def _pillow2array(img, flag='color', channel_order='bgr'):
"""Convert a pillow image to numpy array
Args:
img (:obj:`PIL.Image.Image`): The image loaded using PIL
flag (str): Flags specifying the color type of a loaded image,
candidates are 'color', 'grayscale' and 'unchanged'.
Default to 'color'.
channel_order (str): The channel order of the output image array,
candidates are 'bgr' and 'rgb'. Default to 'bgr'.
Returns:
np.ndarray: The converted numpy array
"""
channel_order = channel_order.lower()
if channel_order not in ['rgb', 'bgr']:
raise ValueError('channel order must be either "rgb" or "bgr"')
if flag == 'unchanged':
array = np.array(img)
if array.ndim >= 3 and array.shape[2] >= 3: # color image
array[:, :, :3] = array[:, :, (2, 1, 0)] # RGB to BGR
else:
# If the image mode is not 'RGB', convert it to 'RGB' first.
if img.mode != 'RGB':
if img.mode != 'LA':
# Most formats except 'LA' can be directly converted to RGB
img = img.convert('RGB')
else:
# When the mode is 'LA', the default conversion will fill in
# the canvas with black, which sometimes shadows black objects
# in the foreground.
#
# Therefore, a random color (124, 117, 104) is used for canvas
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':
array = np.array(img)
if channel_order != 'rgb':
array = array[:, :, ::-1] # RGB to BGR
elif flag == 'grayscale':
img = img.convert('L')
array = np.array(img)
else:
raise ValueError(
'flag must be "color", "grayscale" or "unchanged", '
f'but got {flag}')
return array
def imread(img_or_path, flag='color', channel_order='bgr'): def imread(img_or_path, flag='color', channel_order='bgr'):
"""Read an image. """Read an image.
@ -90,6 +150,10 @@ def imread(img_or_path, flag='color', channel_order='bgr'):
if img.shape[-1] == 1: if img.shape[-1] == 1:
img = img[:, :, 0] img = img[:, :, 0]
return img return img
elif imread_backend == 'pillow':
img = Image.open(img_or_path)
img = _pillow2array(img, flag, channel_order)
return img
else: else:
flag = imread_flags[flag] if is_str(flag) else flag flag = imread_flags[flag] if is_str(flag) else flag
img = cv2.imread(img_or_path, flag) img = cv2.imread(img_or_path, flag)
@ -116,6 +180,11 @@ def imfrombytes(content, flag='color', channel_order='bgr'):
if img.shape[-1] == 1: if img.shape[-1] == 1:
img = img[:, :, 0] img = img[:, :, 0]
return img return img
elif imread_backend == 'pillow':
buff = io.BytesIO(content)
img = Image.open(buff)
img = _pillow2array(img, flag, channel_order)
return img
else: else:
img_np = np.frombuffer(content, np.uint8) img_np = np.frombuffer(content, np.uint8)
flag = imread_flags[flag] if is_str(flag) else flag flag = imread_flags[flag] if is_str(flag) else flag

View File

@ -32,4 +32,4 @@
"regnetx_6.4gf": "https://open-mmlab.s3.ap-northeast-2.amazonaws.com/pretrain/third_party/regnetx_6.4gf-006af45d.pth", "regnetx_6.4gf": "https://open-mmlab.s3.ap-northeast-2.amazonaws.com/pretrain/third_party/regnetx_6.4gf-006af45d.pth",
"regnetx_8.0gf": "https://open-mmlab.s3.ap-northeast-2.amazonaws.com/pretrain/third_party/regnetx_8.0gf-3c68abe7.pth", "regnetx_8.0gf": "https://open-mmlab.s3.ap-northeast-2.amazonaws.com/pretrain/third_party/regnetx_8.0gf-3c68abe7.pth",
"regnetx_12gf": "https://open-mmlab.s3.ap-northeast-2.amazonaws.com/pretrain/third_party/regnetx_12gf-4c2a3350.pth" "regnetx_12gf": "https://open-mmlab.s3.ap-northeast-2.amazonaws.com/pretrain/third_party/regnetx_12gf-4c2a3350.pth"
} }

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

View File

@ -8,7 +8,7 @@ from unittest.mock import patch
import cv2 import cv2
import numpy as np import numpy as np
import pytest import pytest
from numpy.testing import assert_array_equal from numpy.testing import assert_allclose, assert_array_equal
import mmcv import mmcv
@ -65,6 +65,51 @@ class TestIO:
with pytest.raises(TypeError): with pytest.raises(TypeError):
mmcv.imread(1) mmcv.imread(1)
# backend pillow
mmcv.use_backend('pillow')
self.gray_alpha_img_path = osp.join(self.data_dir, 'gray_alpha.png')
self.palette_img_path = osp.join(self.data_dir, 'palette.gif')
img_pil_grayscale1 = mmcv.imread(self.img_path, 'grayscale')
assert img_pil_grayscale1.shape == (300, 400)
img_pil_gray_alpha = mmcv.imread(self.gray_alpha_img_path, 'grayscale')
assert img_pil_gray_alpha.shape == (400, 500)
mean = img_pil_gray_alpha[300:, 400:].mean()
assert_allclose(img_pil_gray_alpha[300:, 400:] - mean, 0)
img_pil_gray_alpha = mmcv.imread(self.gray_alpha_img_path)
mean = img_pil_gray_alpha[300:, 400:].mean(axis=(0, 1))
assert_allclose(img_pil_gray_alpha[300:, 400:] - mean, 0)
assert img_pil_gray_alpha.shape == (400, 500, 3)
img_pil_gray_alpha = mmcv.imread(self.gray_alpha_img_path, 'unchanged')
assert img_pil_gray_alpha.shape == (400, 500, 2)
img_pil_palette = mmcv.imread(self.palette_img_path, 'grayscale')
assert img_pil_palette.shape == (300, 400)
img_pil_palette = mmcv.imread(self.palette_img_path)
assert img_pil_palette.shape == (300, 400, 3)
img_pil_palette = mmcv.imread(self.palette_img_path, 'unchanged')
assert img_pil_palette.shape == (300, 400)
img_pil_grayscale2 = mmcv.imread(self.gray_img_path)
assert img_pil_grayscale2.shape == (300, 400, 3)
img_pil_unchanged = mmcv.imread(self.gray_img_path, 'unchanged')
assert img_pil_unchanged.shape == (300, 400)
img_pil_unchanged = mmcv.imread(img_pil_unchanged)
assert_array_equal(img_pil_unchanged, mmcv.imread(img_pil_unchanged))
img_pil_color_bgr = mmcv.imread(self.img_path_obj)
assert img_pil_color_bgr.shape == (300, 400, 3)
img_pil_color_rgb = mmcv.imread(self.img_path_obj, channel_order='rgb')
assert img_pil_color_rgb.shape == (300, 400, 3)
assert (img_pil_color_rgb == img_cv2_color_rgb).sum() / float(
img_cv2_color_rgb.size) > 0.5
assert_array_equal(img_pil_color_rgb[:, :, ::-1], img_pil_color_bgr)
img_pil_grayscale1 = mmcv.imread(self.img_path_obj, 'grayscale')
assert img_pil_grayscale1.shape == (300, 400)
img_pil_grayscale2 = mmcv.imread(self.gray_img_path_obj)
assert img_pil_grayscale2.shape == (300, 400, 3)
img_pil_unchanged = mmcv.imread(self.gray_img_path_obj, 'unchanged')
assert img_pil_unchanged.shape == (300, 400)
with pytest.raises(TypeError):
mmcv.imread(1)
# backend turbojpeg # backend turbojpeg
mmcv.use_backend('turbojpeg') mmcv.use_backend('turbojpeg')
@ -137,6 +182,15 @@ class TestIO:
gray_img_dim3_cv2 = mmcv.imfrombytes(img_bytes, flag='grayscale') gray_img_dim3_cv2 = mmcv.imfrombytes(img_bytes, flag='grayscale')
assert gray_img_dim3_cv2.shape == (300, 400) assert gray_img_dim3_cv2.shape == (300, 400)
# backend pillow, channel order: bgr
mmcv.use_backend('pillow')
with open(self.img_path, 'rb') as f:
img_bytes = f.read()
img_pillow = mmcv.imfrombytes(img_bytes)
assert img_pillow.shape == (300, 400, 3)
# Pillow and opencv decoding may not be the same
assert (img_cv2 == img_pillow).sum() / float(img_cv2.size) > 0.5
# backend turbojpeg, channel order: bgr # backend turbojpeg, channel order: bgr
mmcv.use_backend('turbojpeg') mmcv.use_backend('turbojpeg')
with open(self.img_path, 'rb') as f: with open(self.img_path, 'rb') as f: