mirror of https://github.com/open-mmlab/mmcv.git
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 * reformatpull/351/head
parent
3f4c9fd0c8
commit
630b747cb1
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 |
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue