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
docs
mmcv
image
model_zoo
tests
test_image
|
@ -1,35 +1,35 @@
|
|||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
||||
@ECHO OFF
|
||||
|
||||
pushd %~dp0
|
||||
|
||||
REM Command file for Sphinx documentation
|
||||
|
||||
if "%SPHINXBUILD%" == "" (
|
||||
set SPHINXBUILD=sphinx-build
|
||||
)
|
||||
set SOURCEDIR=.
|
||||
set BUILDDIR=_build
|
||||
|
||||
if "%1" == "" goto help
|
||||
|
||||
%SPHINXBUILD% >NUL 2>NUL
|
||||
if errorlevel 9009 (
|
||||
echo.
|
||||
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||
echo.may add the Sphinx directory to PATH.
|
||||
echo.
|
||||
echo.If you don't have Sphinx installed, grab it from
|
||||
echo.http://sphinx-doc.org/
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
goto end
|
||||
|
||||
:help
|
||||
%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS%
|
||||
|
||||
:end
|
||||
popd
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
# Copyright (c) Open-MMLab. All rights reserved.
|
||||
import io
|
||||
import os.path as osp
|
||||
from pathlib import Path
|
||||
|
||||
|
@ -13,8 +14,13 @@ try:
|
|||
except ImportError:
|
||||
TJCS_RGB = TJPF_GRAY = TJPF_BGR = TurboJPEG = None
|
||||
|
||||
try:
|
||||
from PIL import Image
|
||||
except ImportError:
|
||||
Image = None
|
||||
|
||||
jpeg = None
|
||||
supported_backends = ['cv2', 'turbojpeg']
|
||||
supported_backends = ['cv2', 'turbojpeg', 'pillow']
|
||||
|
||||
imread_flags = {
|
||||
'color': IMREAD_COLOR,
|
||||
|
@ -42,6 +48,9 @@ def use_backend(backend):
|
|||
global jpeg
|
||||
if jpeg is None:
|
||||
jpeg = TurboJPEG()
|
||||
elif imread_backend == 'pillow':
|
||||
if Image is None:
|
||||
raise ImportError('`Pillow` is not installed')
|
||||
|
||||
|
||||
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"')
|
||||
|
||||
|
||||
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'):
|
||||
"""Read an image.
|
||||
|
||||
|
@ -90,6 +150,10 @@ def imread(img_or_path, flag='color', channel_order='bgr'):
|
|||
if img.shape[-1] == 1:
|
||||
img = img[:, :, 0]
|
||||
return img
|
||||
elif imread_backend == 'pillow':
|
||||
img = Image.open(img_or_path)
|
||||
img = _pillow2array(img, flag, channel_order)
|
||||
return img
|
||||
else:
|
||||
flag = imread_flags[flag] if is_str(flag) else 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:
|
||||
img = img[:, :, 0]
|
||||
return img
|
||||
elif imread_backend == 'pillow':
|
||||
buff = io.BytesIO(content)
|
||||
img = Image.open(buff)
|
||||
img = _pillow2array(img, flag, channel_order)
|
||||
return img
|
||||
else:
|
||||
img_np = np.frombuffer(content, np.uint8)
|
||||
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_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"
|
||||
}
|
||||
}
|
||||
|
|
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 numpy as np
|
||||
import pytest
|
||||
from numpy.testing import assert_array_equal
|
||||
from numpy.testing import assert_allclose, assert_array_equal
|
||||
|
||||
import mmcv
|
||||
|
||||
|
@ -65,6 +65,51 @@ class TestIO:
|
|||
with pytest.raises(TypeError):
|
||||
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
|
||||
mmcv.use_backend('turbojpeg')
|
||||
|
||||
|
@ -137,6 +182,15 @@ class TestIO:
|
|||
gray_img_dim3_cv2 = mmcv.imfrombytes(img_bytes, flag='grayscale')
|
||||
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
|
||||
mmcv.use_backend('turbojpeg')
|
||||
with open(self.img_path, 'rb') as f:
|
||||
|
|
Loading…
Reference in New Issue