Commit f872672f authored by Kai Chen's avatar Kai Chen
Browse files

renaming and reorganizing for subpackage

parent eadd1e0f
from .io import * from .io import *
from .processing import * from .transforms import *
...@@ -19,8 +19,10 @@ imread_flags = { ...@@ -19,8 +19,10 @@ imread_flags = {
'unchanged': IMREAD_UNCHANGED 'unchanged': IMREAD_UNCHANGED
} }
__all__ = ['imread', 'imwrite', 'imfrombytes']
def read_img(img_or_path, flag='color'):
def imread(img_or_path, flag='color'):
"""Read an image. """Read an image.
Args: Args:
...@@ -44,12 +46,12 @@ def read_img(img_or_path, flag='color'): ...@@ -44,12 +46,12 @@ def read_img(img_or_path, flag='color'):
raise TypeError('"img" must be a numpy array or a filename') raise TypeError('"img" must be a numpy array or a filename')
def img_from_bytes(content, flag='color'): def imfrombytes(content, flag='color'):
"""Read an image from bytes. """Read an image from bytes.
Args: Args:
content (bytes): Image bytes got from files or other streams. content (bytes): Image bytes got from files or other streams.
flag (str): Same as :func:`read_img`. flag (str): Same as :func:`imread`.
Returns: Returns:
ndarray: Loaded image array. ndarray: Loaded image array.
...@@ -60,11 +62,11 @@ def img_from_bytes(content, flag='color'): ...@@ -60,11 +62,11 @@ def img_from_bytes(content, flag='color'):
return img return img
def write_img(img, file_path, params=None, auto_mkdir=True): def imwrite(img, file_path, params=None, auto_mkdir=True):
"""Write image to file """Write image to file
Args: Args:
img (ndarray): Image to be written to file. img (ndarray): Image array to be written.
file_path (str): Image file path. file_path (str): Image file path.
params (None or list): Same as opencv's :func:`imwrite` interface. params (None or list): Same as opencv's :func:`imwrite` interface.
auto_mkdir (bool): If the parrent folder of `file_path` does not exist, auto_mkdir (bool): If the parrent folder of `file_path` does not exist,
......
from .colorspace import *
from .geometry import *
from .resize import *
import cv2
__all__ = ['bgr2gray', 'gray2bgr', 'bgr2rgb', 'rgb2bgr', 'bgr2hsv', 'hsv2bgr']
def bgr2gray(img, keepdim=False):
"""Convert a BGR image to grayscale image.
Args:
img (ndarray): The input image.
keepdim (bool): If False (by default), then return the grayscale image
with 2 dims, otherwise 3 dims.
Returns:
ndarray: The converted grayscale image.
"""
out_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
if keepdim:
out_img = out_img[..., None]
return out_img
def gray2bgr(img):
"""Convert a grayscale image to BGR image.
Args:
img (ndarray or str): The input image.
Returns:
ndarray: The converted BGR image.
"""
img = img[..., None] if img.ndim == 2 else img
out_img = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)
return out_img
def convert_color_factory(src, dst):
code = getattr(cv2, 'COLOR_{}2{}'.format(src.upper(), dst.upper()))
def convert_color(img):
out_img = cv2.cvtColor(img, code)
return out_img
convert_color.__doc__ = """Convert a {0} image to {1} image.
Args:
img (ndarray or str): The input image.
Returns:
ndarray: The converted {1} image.
""".format(src.upper(), dst.upper())
return convert_color
bgr2rgb = convert_color_factory('bgr', 'rgb')
rgb2bgr = convert_color_factory('rgb', 'bgr')
bgr2hsv = convert_color_factory('bgr', 'hsv')
hsv2bgr = convert_color_factory('hsv', 'bgr')
from __future__ import division
import cv2 import cv2
import numpy as np import numpy as np
from .io import read_img __all__ = ['imrotate', 'imcrop', 'impad']
def bgr2gray(img, keepdim=False):
"""Convert a BGR image to grayscale image.
Args:
img (ndarray or str): The input image or image path.
keepdim (bool): If False (by default), then return the grayscale image
with 2 dims, otherwise 3 dims.
Returns:
ndarray: The converted grayscale image.
"""
in_img = read_img(img)
out_img = cv2.cvtColor(in_img, cv2.COLOR_BGR2GRAY)
if keepdim:
out_img = out_img[..., None]
return out_img
def gray2bgr(img):
"""Convert a grayscale image to BGR image.
Args:
img (ndarray or str): The input image or image path.
Returns:
ndarray: The converted BGR image.
"""
in_img = read_img(img)
in_img = in_img[..., None] if in_img.ndim == 2 else in_img
out_img = cv2.cvtColor(in_img, cv2.COLOR_GRAY2BGR)
return out_img
def convert_color_factory(src, dst):
code = getattr(cv2, 'COLOR_{}2{}'.format(src.upper(), dst.upper()))
def convert_color(img):
in_img = read_img(img)
out_img = cv2.cvtColor(in_img, code)
return out_img
convert_color.__doc__ = """Convert a {0} image to {1} image
Args:
img (ndarray or str): The input image or image path.
Returns:
ndarray: The converted {1} image
""".format(src.upper(), dst.upper())
return convert_color
bgr2rgb = convert_color_factory('bgr', 'rgb')
rgb2bgr = convert_color_factory('rgb', 'bgr')
bgr2hsv = convert_color_factory('bgr', 'hsv')
hsv2bgr = convert_color_factory('hsv', 'bgr')
def scale_size(size, scale):
"""Rescale a size by a ratio.
Args:
size (tuple): w, h.
scale (float): Scaling factor.
Returns:
tuple[int]: scaled size.
"""
w, h = size
return int(w * float(scale) + 0.5), int(h * float(scale) + 0.5)
interp_codes = {
'nearest': cv2.INTER_NEAREST,
'bilinear': cv2.INTER_LINEAR,
'bicubic': cv2.INTER_CUBIC,
'area': cv2.INTER_AREA,
'lanczos': cv2.INTER_LANCZOS4
}
def resize(img, size, return_scale=False, interpolation='bilinear'):
"""Resize image to a given size.
Args:
img (ndarray): The input image or image path.
size (tuple): Target (w, h).
return_scale (bool): Whether to return `w_scale` and `h_scale`.
interpolation (str): Interpolation method, accepted values are
"nearest", "bilinear", "bicubic", "area", "lanczos".
Returns:
tuple or ndarray: (`resized_img`, `w_scale`, `h_scale`) or
`resized_img`.
"""
img = read_img(img)
h, w = img.shape[:2]
resized_img = cv2.resize(
img, size, interpolation=interp_codes[interpolation])
if not return_scale:
return resized_img
else:
w_scale = size[0] / float(w)
h_scale = size[1] / float(h)
return resized_img, w_scale, h_scale
def resize_like(img, dst_img, return_scale=False, interpolation='bilinear'):
"""Resize image to the same size of a given image.
Args:
img (ndarray): The input image or image path.
dst_img (ndarray): The target image.
return_scale (bool): Whether to return `w_scale` and `h_scale`.
interpolation (str): Same as :func:`resize`.
Returns:
tuple or ndarray: (`resized_img`, `w_scale`, `h_scale`) or
`resized_img`.
"""
h, w = dst_img.shape[:2]
return resize(img, (w, h), return_scale, interpolation)
def resize_by_ratio(img, ratio, interpolation='bilinear'): def imrotate(img,
"""Resize image by a ratio. angle,
center=None,
Args: scale=1.0,
img (ndarray): The input image or image path. border_value=0,
ratio (float): Scaling factor. auto_bound=False):
interpolation (str): Same as :func:`resize`. """Rotate an image.
Returns:
ndarray: The resized image
"""
assert isinstance(ratio, (float, int)) and ratio > 0
img = read_img(img)
h, w = img.shape[:2]
new_size = scale_size((w, h), ratio)
return resize(img, new_size, interpolation=interpolation)
def resize_keep_ar(img,
max_long_edge,
max_short_edge,
return_scale=False,
interpolation='bilinear'):
"""Resize image with aspect ratio unchanged.
The long edge of resized image will be no greater than `max_long_edge`,
and the short edge of resized image is no greater than `max_short_edge`.
Args: Args:
img (ndarray): The input image or image path. img (ndarray or str): Image to be rotated.
max_long_edge (int): Max value of the long edge of resized image. angle (float): Rotation angle in degrees, positive values mean
max_short_edge (int): Max value of the short edge of resized image. clockwise rotation.
return_scale (bool): Whether to return scale besides the resized image. center (tuple): Center of the rotation in the source image, by default
interpolation (str): Same as :func:`resize`. it is the center of the image.
scale (float): Isotropic scale factor.
border_value (int): Border value.
auto_bound (bool): Whether to adjust the image size to cover the whole
rotated image.
Returns: Returns:
tuple or ndarray: (resized_img, scale_factor) or resized_img. ndarray: The rotated image.
""" """
if max_long_edge < max_short_edge: if center is not None and auto_bound:
raise ValueError( raise ValueError('`auto_bound` conflicts with `center`')
'"max_long_edge" should not be less than "max_short_edge"')
img = read_img(img)
h, w = img.shape[:2] h, w = img.shape[:2]
ratio = min( if center is None:
float(max_long_edge) / max(h, w), center = ((w - 1) * 0.5, (h - 1) * 0.5)
float(max_short_edge) / min(h, w)) assert isinstance(center, tuple)
new_size = scale_size((w, h), ratio)
resized_img = resize(img, new_size, interpolation=interpolation)
if return_scale:
return resized_img, ratio
else:
return resized_img
def limit_size(img, max_edge, return_scale=False, interpolation='bilinear'):
"""Limit the size of an image.
If the long edge of the image is greater than max_edge, resize the image.
Args:
img (ndarray): The input image or image path.
max_edge (int): Maximum value of the long edge.
return_scale (bool): Whether to return scale besides the resized image.
interpolation (str): Same as :func:`resize`.
Returns: matrix = cv2.getRotationMatrix2D(center, -angle, scale)
tuple or ndarray: (resized_img, scale_factor) or resized_img. if auto_bound:
""" cos = np.abs(matrix[0, 0])
img = read_img(img) sin = np.abs(matrix[0, 1])
h, w = img.shape[:2] new_w = h * sin + w * cos
if max(h, w) > max_edge: new_h = h * cos + w * sin
scale = float(max_edge) / max(h, w) matrix[0, 2] += (new_w - w) * 0.5
new_size = scale_size((w, h), scale) matrix[1, 2] += (new_h - h) * 0.5
resized_img = resize(img, new_size, interpolation=interpolation) w = int(np.round(new_w))
else: h = int(np.round(new_h))
scale = 1.0 rotated = cv2.warpAffine(img, matrix, (w, h), borderValue=border_value)
resized_img = img return rotated
if return_scale:
return resized_img, scale
else:
return resized_img
def bbox_clip(bboxes, img_shape): def bbox_clip(bboxes, img_shape):
...@@ -229,16 +58,12 @@ def bbox_clip(bboxes, img_shape): ...@@ -229,16 +58,12 @@ def bbox_clip(bboxes, img_shape):
ndarray: Clipped bboxes. ndarray: Clipped bboxes.
""" """
assert bboxes.shape[-1] % 4 == 0 assert bboxes.shape[-1] % 4 == 0
cliped_bboxes = np.empty_like(bboxes, dtype=bboxes.dtype) clipped_bboxes = np.empty_like(bboxes, dtype=bboxes.dtype)
cliped_bboxes[..., 0::4] = np.maximum( clipped_bboxes[..., 0::2] = np.maximum(
np.minimum(bboxes[..., 0::4], img_shape[1] - 1), 0) np.minimum(bboxes[..., 0::2], img_shape[1] - 1), 0)
cliped_bboxes[..., 1::4] = np.maximum( clipped_bboxes[..., 1::2] = np.maximum(
np.minimum(bboxes[..., 1::4], img_shape[0] - 1), 0) np.minimum(bboxes[..., 1::2], img_shape[0] - 1), 0)
cliped_bboxes[..., 2::4] = np.maximum( return clipped_bboxes
np.minimum(bboxes[..., 2::4], img_shape[1] - 1), 0)
cliped_bboxes[..., 3::4] = np.maximum(
np.minimum(bboxes[..., 3::4], img_shape[0] - 1), 0)
return cliped_bboxes
def bbox_scaling(bboxes, scale, clip_shape=None): def bbox_scaling(bboxes, scale, clip_shape=None):
...@@ -267,7 +92,7 @@ def bbox_scaling(bboxes, scale, clip_shape=None): ...@@ -267,7 +92,7 @@ def bbox_scaling(bboxes, scale, clip_shape=None):
return scaled_bboxes return scaled_bboxes
def crop_img(img, bboxes, scale_ratio=1.0, pad_fill=None): def imcrop(img, bboxes, scale_ratio=1.0, pad_fill=None):
"""Crop image patches. """Crop image patches.
3 steps: scale the bboxes -> clip bboxes -> crop and pad. 3 steps: scale the bboxes -> clip bboxes -> crop and pad.
...@@ -288,17 +113,18 @@ def crop_img(img, bboxes, scale_ratio=1.0, pad_fill=None): ...@@ -288,17 +113,18 @@ def crop_img(img, bboxes, scale_ratio=1.0, pad_fill=None):
if isinstance(pad_fill, (int, float)): if isinstance(pad_fill, (int, float)):
pad_fill = [pad_fill for _ in range(chn)] pad_fill = [pad_fill for _ in range(chn)]
assert len(pad_fill) == chn assert len(pad_fill) == chn
img = read_img(img)
_bboxes = bboxes[None, ...] if bboxes.ndim == 1 else bboxes _bboxes = bboxes[None, ...] if bboxes.ndim == 1 else bboxes
scaled_bboxes = bbox_scaling(_bboxes, scale_ratio).astype(np.int32) scaled_bboxes = bbox_scaling(_bboxes, scale_ratio).astype(np.int32)
clipped_bbox = bbox_clip(scaled_bboxes, img.shape) clipped_bbox = bbox_clip(scaled_bboxes, img.shape)
patches = [] patches = []
for i in range(clipped_bbox.shape[0]): for i in range(clipped_bbox.shape[0]):
x1, y1, x2, y2 = tuple(clipped_bbox[i, :].tolist()) x1, y1, x2, y2 = tuple(clipped_bbox[i, :])
if pad_fill is None: if pad_fill is None:
patch = img[y1:y2 + 1, x1:x2 + 1, ...] patch = img[y1:y2 + 1, x1:x2 + 1, ...]
else: else:
_x1, _y1, _x2, _y2 = tuple(scaled_bboxes[i, :].tolist()) _x1, _y1, _x2, _y2 = tuple(scaled_bboxes[i, :])
if chn == 2: if chn == 2:
patch_shape = (_y2 - _y1 + 1, _x2 - _x1 + 1) patch_shape = (_y2 - _y1 + 1, _x2 - _x1 + 1)
else: else:
...@@ -313,13 +139,14 @@ def crop_img(img, bboxes, scale_ratio=1.0, pad_fill=None): ...@@ -313,13 +139,14 @@ def crop_img(img, bboxes, scale_ratio=1.0, pad_fill=None):
patch[y_start:y_start + h, x_start:x_start + patch[y_start:y_start + h, x_start:x_start +
w, ...] = img[y1:y1 + h, x1:x1 + w, ...] w, ...] = img[y1:y1 + h, x1:x1 + w, ...]
patches.append(patch) patches.append(patch)
if bboxes.ndim == 1: if bboxes.ndim == 1:
return patches[0] return patches[0]
else: else:
return patches return patches
def pad_img(img, shape, pad_val): def impad(img, shape, pad_val):
"""Pad an image to a certain shape. """Pad an image to a certain shape.
Args: Args:
...@@ -341,46 +168,3 @@ def pad_img(img, shape, pad_val): ...@@ -341,46 +168,3 @@ def pad_img(img, shape, pad_val):
pad[...] = pad_val pad[...] = pad_val
pad[:img.shape[0], :img.shape[1], ...] = img pad[:img.shape[0], :img.shape[1], ...] = img
return pad return pad
def rotate_img(img,
angle,
center=None,
scale=1.0,
border_value=0,
auto_bound=False):
"""Rotate an image.
Args:
img (ndarray or str): Image to be rotated.
angle (float): Rotation angle in degrees, positive values mean
clockwise rotation.
center (tuple): Center of the rotation in the source image, by default
it is the center of the image.
scale (float): Isotropic scale factor.
border_value (int): Border value.
auto_bound (bool): Whether to adjust the image size to cover the whole
rotated image.
Returns:
ndarray: The rotated image.
"""
if center is not None and auto_bound:
raise ValueError('`auto_bound` conflicts with `center`')
img = read_img(img)
h, w = img.shape[:2]
if center is None:
center = ((w - 1) / 2, (h - 1) / 2)
assert isinstance(center, tuple)
matrix = cv2.getRotationMatrix2D(center, -angle, scale)
if auto_bound:
cos = np.abs(matrix[0, 0])
sin = np.abs(matrix[0, 1])
new_w = h * sin + w * cos
new_h = h * cos + w * sin
matrix[0, 2] += (new_w - w) / 2
matrix[1, 2] += (new_h - h) / 2
w = int(np.round(new_w))
h = int(np.round(new_h))
rotated = cv2.warpAffine(img, matrix, (w, h), borderValue=border_value)
return rotated
from __future__ import division
import cv2
def scale_size(size, scale):
"""Rescale a size by a ratio.
Args:
size (tuple): w, h.
scale (float): Scaling factor.
Returns:
tuple[int]: scaled size.
"""
w, h = size
return int(w * float(scale) + 0.5), int(h * float(scale) + 0.5)
interp_codes = {
'nearest': cv2.INTER_NEAREST,
'bilinear': cv2.INTER_LINEAR,
'bicubic': cv2.INTER_CUBIC,
'area': cv2.INTER_AREA,
'lanczos': cv2.INTER_LANCZOS4
}
def imresize(img, size, return_scale=False, interpolation='bilinear'):
"""Resize image to a given size.
Args:
img (ndarray): The input image.
size (tuple): Target (w, h).
return_scale (bool): Whether to return `w_scale` and `h_scale`.
interpolation (str): Interpolation method, accepted values are
"nearest", "bilinear", "bicubic", "area", "lanczos".
Returns:
tuple or ndarray: (`resized_img`, `w_scale`, `h_scale`) or
`resized_img`.
"""
h, w = img.shape[:2]
resized_img = cv2.resize(
img, size, interpolation=interp_codes[interpolation])
if not return_scale:
return resized_img
else:
w_scale = size[0] / w
h_scale = size[1] / h
return resized_img, w_scale, h_scale
def imresize_like(img, dst_img, return_scale=False, interpolation='bilinear'):
"""Resize image to the same size of a given image.
Args:
img (ndarray): The input image.
dst_img (ndarray): The target image.
return_scale (bool): Whether to return `w_scale` and `h_scale`.
interpolation (str): Same as :func:`resize`.
Returns:
tuple or ndarray: (`resized_img`, `w_scale`, `h_scale`) or
`resized_img`.
"""
h, w = dst_img.shape[:2]
return imresize(img, (w, h), return_scale, interpolation)
def imrescale(img, scale, return_scale=False, interpolation='bilinear'):
"""Resize image while keeping the aspect ratio.
Args:
img (ndarray): The input image.
scale (float or tuple[int]): The scaling factor or maximum size.
If it is a float number, then the image will be rescaled by this
factor, else if it is a tuple of 2 integers, then the image will
be rescaled as large as possible within the scale.
return_scale (bool): Whether to return the scaling factor besides the
rescaled image.
interpolation (str): Same as :func:`resize`.
Returns:
ndarray: The rescaled image.
"""
h, w = img.shape[:2]
if isinstance(scale, (float, int)):
if scale <= 0:
raise ValueError(
'Invalid scale {}, must be positive.'.format(scale))
scale_factor = scale
elif isinstance(scale, tuple):
max_long_edge = max(scale)
max_short_edge = min(scale)
scale_factor = min(max_long_edge / max(h, w),
max_short_edge / min(h, w))
else:
raise TypeError(
'Scale must be a number or tuple of int, but got {}'.format(
type(scale)))
new_size = scale_size((w, h), scale_factor)
rescaled_img = imresize(img, new_size, interpolation=interpolation)
if return_scale:
return rescaled_img, scale_factor
else:
return rescaled_img
def limit_size(img, max_edge, return_scale=False, interpolation='bilinear'):
"""Limit the size of an image.
If the long edge of the image is greater than max_edge, resize the image.
Args:
img (ndarray): The input image.
max_edge (int): Maximum value of the long edge.
return_scale (bool): Whether to return scale besides the resized image.
interpolation (str): Same as :func:`resize`.
Returns:
tuple or ndarray: (resized_img, scale_factor) or resized_img.
"""
h, w = img.shape[:2]
if max(h, w) > max_edge:
scale = float(max_edge) / max(h, w)
new_size = scale_size((w, h), scale)
resized_img = imresize(img, new_size, interpolation=interpolation)
else:
scale = 1.0
resized_img = img
if return_scale:
return resized_img, scale
else:
return resized_img
import numpy as np import numpy as np
from mmcv.image import read_img, write_img from mmcv.image import imread, imwrite
from mmcv.utils import is_str from mmcv.utils import is_str
...@@ -52,8 +52,8 @@ def read_flow(flow_or_path, quantize=False, *args, **kwargs): ...@@ -52,8 +52,8 @@ def read_flow(flow_or_path, quantize=False, *args, **kwargs):
flow = np.fromfile(f, np.float32, w * h * 2).reshape((h, w, 2)) flow = np.fromfile(f, np.float32, w * h * 2).reshape((h, w, 2))
else: else:
dx_filename, dy_filename = _pair_name(flow_or_path) dx_filename, dy_filename = _pair_name(flow_or_path)
dx = read_img(dx_filename, flag='unchanged') dx = imread(dx_filename, flag='unchanged')
dy = read_img(dy_filename, flag='unchanged') dy = imread(dy_filename, flag='unchanged')
flow = dequantize_flow(dx, dy, *args, **kwargs) flow = dequantize_flow(dx, dy, *args, **kwargs)
return flow.astype(np.float32) return flow.astype(np.float32)
...@@ -79,8 +79,8 @@ def write_flow(flow, filename, quantize=False, *args, **kwargs): ...@@ -79,8 +79,8 @@ def write_flow(flow, filename, quantize=False, *args, **kwargs):
else: else:
dx, dy = quantize_flow(flow, *args, **kwargs) dx, dy = quantize_flow(flow, *args, **kwargs)
dx_filename, dy_filename = _pair_name(filename) dx_filename, dy_filename = _pair_name(filename)
write_img(dx, dx_filename) imwrite(dx, dx_filename)
write_img(dy, dy_filename) imwrite(dy, dy_filename)
def quantize_flow(flow, max_val=0.02, norm=True): def quantize_flow(flow, max_val=0.02, norm=True):
......
import cv2 import cv2
import numpy as np import numpy as np
from mmcv.image import read_img, write_img from mmcv.image import imread, imwrite
from .color import color_val from .color import color_val
...@@ -13,7 +13,7 @@ def show_img(img, win_name='', wait_time=0): ...@@ -13,7 +13,7 @@ def show_img(img, win_name='', wait_time=0):
win_name (str): The window name. win_name (str): The window name.
wait_time (int): Value of waitKey param. wait_time (int): Value of waitKey param.
""" """
cv2.imshow(win_name, read_img(img)) cv2.imshow(win_name, imread(img))
cv2.waitKey(wait_time) cv2.waitKey(wait_time)
...@@ -39,7 +39,7 @@ def draw_bboxes(img, ...@@ -39,7 +39,7 @@ def draw_bboxes(img,
wait_time (int): Value of waitKey param. wait_time (int): Value of waitKey param.
out_file (str, optional): The filename to write the image. out_file (str, optional): The filename to write the image.
""" """
img = read_img(img) img = imread(img)
if isinstance(bboxes, np.ndarray): if isinstance(bboxes, np.ndarray):
bboxes = [bboxes] bboxes = [bboxes]
...@@ -63,4 +63,4 @@ def draw_bboxes(img, ...@@ -63,4 +63,4 @@ def draw_bboxes(img,
if show: if show:
show_img(img, win_name, wait_time) show_img(img, win_name, wait_time)
if out_file is not None: if out_file is not None:
write_img(img, out_file) imwrite(img, out_file)
...@@ -2,6 +2,7 @@ import os ...@@ -2,6 +2,7 @@ import os
import os.path as osp import os.path as osp
import tempfile import tempfile
import cv2
import mmcv import mmcv
import numpy as np import numpy as np
import pytest import pytest
...@@ -16,6 +17,7 @@ class TestImage(object): ...@@ -16,6 +17,7 @@ class TestImage(object):
cls.img_path = osp.join(osp.dirname(__file__), 'data/color.jpg') cls.img_path = osp.join(osp.dirname(__file__), 'data/color.jpg')
cls.gray_img_path = osp.join( cls.gray_img_path = osp.join(
osp.dirname(__file__), 'data/grayscale.jpg') osp.dirname(__file__), 'data/grayscale.jpg')
cls.img = cv2.imread(cls.img_path)
def assert_img_equal(self, img, ref_img, ratio_thr=0.999): def assert_img_equal(self, img, ref_img, ratio_thr=0.999):
assert img.shape == ref_img.shape assert img.shape == ref_img.shape
...@@ -24,31 +26,31 @@ class TestImage(object): ...@@ -24,31 +26,31 @@ class TestImage(object):
diff = np.abs(img.astype('int32') - ref_img.astype('int32')) diff = np.abs(img.astype('int32') - ref_img.astype('int32'))
assert np.sum(diff <= 1) / float(area) > ratio_thr assert np.sum(diff <= 1) / float(area) > ratio_thr
def test_read_img(self): def test_imread(self):
img = mmcv.read_img(self.img_path) img = mmcv.imread(self.img_path)
assert img.shape == (300, 400, 3) assert img.shape == (300, 400, 3)
img = mmcv.read_img(self.img_path, 'grayscale') img = mmcv.imread(self.img_path, 'grayscale')
assert img.shape == (300, 400) assert img.shape == (300, 400)
img = mmcv.read_img(self.gray_img_path) img = mmcv.imread(self.gray_img_path)
assert img.shape == (300, 400, 3) assert img.shape == (300, 400, 3)
img = mmcv.read_img(self.gray_img_path, 'unchanged') img = mmcv.imread(self.gray_img_path, 'unchanged')
assert img.shape == (300, 400) assert img.shape == (300, 400)
img = mmcv.read_img(img) img = mmcv.imread(img)
assert_array_equal(img, mmcv.read_img(img)) assert_array_equal(img, mmcv.imread(img))
with pytest.raises(TypeError): with pytest.raises(TypeError):
mmcv.read_img(1) mmcv.imread(1)
def test_img_from_bytes(self): def test_imfrombytes(self):
with open(self.img_path, 'rb') as f: with open(self.img_path, 'rb') as f:
img_bytes = f.read() img_bytes = f.read()
img = mmcv.img_from_bytes(img_bytes) img = mmcv.imfrombytes(img_bytes)
assert img.shape == (300, 400, 3) assert img.shape == (300, 400, 3)
def test_write_img(self): def test_imwrite(self):
img = mmcv.read_img(self.img_path) img = mmcv.imread(self.img_path)
out_file = osp.join(tempfile.gettempdir(), 'mmcv_test.jpg') out_file = osp.join(tempfile.gettempdir(), 'mmcv_test.jpg')
mmcv.write_img(img, out_file) mmcv.imwrite(img, out_file)
rewrite_img = mmcv.read_img(out_file) rewrite_img = mmcv.imread(out_file)
os.remove(out_file) os.remove(out_file)
self.assert_img_equal(img, rewrite_img) self.assert_img_equal(img, rewrite_img)
...@@ -112,66 +114,71 @@ class TestImage(object): ...@@ -112,66 +114,71 @@ class TestImage(object):
assert mmcv.scale_size((300, 200), 0.5) == (150, 100) assert mmcv.scale_size((300, 200), 0.5) == (150, 100)
assert mmcv.scale_size((11, 22), 0.7) == (8, 15) assert mmcv.scale_size((11, 22), 0.7) == (8, 15)
def test_resize(self): def test_imresize(self):
resized_img = mmcv.resize(self.img_path, (1000, 600)) resized_img = mmcv.imresize(self.img, (1000, 600))
assert resized_img.shape == (600, 1000, 3) assert resized_img.shape == (600, 1000, 3)
resized_img, w_scale, h_scale = mmcv.resize(self.img_path, (1000, 600), resized_img, w_scale, h_scale = mmcv.imresize(self.img, (1000, 600),
True) True)
assert (resized_img.shape == (600, 1000, 3) and w_scale == 2.5 assert (resized_img.shape == (600, 1000, 3) and w_scale == 2.5
and h_scale == 2.0) and h_scale == 2.0)
for mode in ['nearest', 'bilinear', 'bicubic', 'area', 'lanczos']: for mode in ['nearest', 'bilinear', 'bicubic', 'area', 'lanczos']:
resized_img = mmcv.resize( resized_img = mmcv.imresize(
self.img_path, (1000, 600), interpolation=mode) self.img, (1000, 600), interpolation=mode)
assert resized_img.shape == (600, 1000, 3) assert resized_img.shape == (600, 1000, 3)
def test_resize_like(self): def test_imresize_like(self):
a = np.zeros((100, 200, 3)) a = np.zeros((100, 200, 3))
resized_img = mmcv.resize_like(self.img_path, a) resized_img = mmcv.imresize_like(self.img, a)
assert resized_img.shape == (100, 200, 3) assert resized_img.shape == (100, 200, 3)
def test_resize_by_ratio(self): def test_imrescale(self):
resized_img = mmcv.resize_by_ratio(self.img_path, 1.5) # rescale by a certain factor
resized_img = mmcv.imrescale(self.img, 1.5)
assert resized_img.shape == (450, 600, 3) assert resized_img.shape == (450, 600, 3)
resized_img = mmcv.resize_by_ratio(self.img_path, 0.934) resized_img = mmcv.imrescale(self.img, 0.934)
assert resized_img.shape == (280, 374, 3) assert resized_img.shape == (280, 374, 3)
def test_resize_keep_ar(self): # rescale by a certain max_size
# resize (400, 300) to (max_1000, max_600) # resize (400, 300) to (max_1000, max_600)
resized_img = mmcv.resize_keep_ar(self.img_path, 1000, 600) resized_img = mmcv.imrescale(self.img, (1000, 600))
assert resized_img.shape == (600, 800, 3) assert resized_img.shape == (600, 800, 3)
resized_img, scale = mmcv.resize_keep_ar(self.img_path, 1000, 600, resized_img, scale = mmcv.imrescale(
True) self.img, (1000, 600), return_scale=True)
assert resized_img.shape == (600, 800, 3) and scale == 2.0 assert resized_img.shape == (600, 800, 3) and scale == 2.0
# resize (400, 300) to (max_200, max_180) # resize (400, 300) to (max_200, max_180)
img = mmcv.read_img(self.img_path) resized_img = mmcv.imrescale(self.img, (180, 200))
resized_img = mmcv.resize_keep_ar(img, 200, 180)
assert resized_img.shape == (150, 200, 3) assert resized_img.shape == (150, 200, 3)
resized_img, scale = mmcv.resize_keep_ar(self.img_path, 200, 180, True) resized_img, scale = mmcv.imrescale(
self.img, (180, 200), return_scale=True)
assert resized_img.shape == (150, 200, 3) and scale == 0.5 assert resized_img.shape == (150, 200, 3) and scale == 0.5
# max_long_edge cannot be less than max_short_edge
# test exceptions
with pytest.raises(ValueError): with pytest.raises(ValueError):
mmcv.resize_keep_ar(self.img_path, 500, 600) mmcv.imrescale(self.img, -0.5)
with pytest.raises(TypeError):
mmcv.imrescale(self.img, [100, 100])
def test_limit_size(self): def test_limit_size(self):
# limit to 800 # limit to 800
resized_img = mmcv.limit_size(self.img_path, 800) resized_img = mmcv.limit_size(self.img, 800)
assert resized_img.shape == (300, 400, 3) assert resized_img.shape == (300, 400, 3)
resized_img, scale = mmcv.limit_size(self.img_path, 800, True) resized_img, scale = mmcv.limit_size(self.img, 800, True)
assert resized_img.shape == (300, 400, 3) and scale == 1 assert resized_img.shape == (300, 400, 3) and scale == 1
# limit to 200 # limit to 200
resized_img = mmcv.limit_size(self.img_path, 200) resized_img = mmcv.limit_size(self.img, 200)
assert resized_img.shape == (150, 200, 3) assert resized_img.shape == (150, 200, 3)
resized_img, scale = mmcv.limit_size(self.img_path, 200, True) resized_img, scale = mmcv.limit_size(self.img, 200, True)
assert resized_img.shape == (150, 200, 3) and scale == 0.5 assert resized_img.shape == (150, 200, 3) and scale == 0.5
# test with img rather than img path # test with img rather than img path
img = mmcv.read_img(self.img_path) img = mmcv.imread(self.img)
resized_img = mmcv.limit_size(img, 200) resized_img = mmcv.limit_size(img, 200)
assert resized_img.shape == (150, 200, 3) assert resized_img.shape == (150, 200, 3)
resized_img, scale = mmcv.limit_size(img, 200, True) resized_img, scale = mmcv.limit_size(img, 200, True)
assert resized_img.shape == (150, 200, 3) and scale == 0.5 assert resized_img.shape == (150, 200, 3) and scale == 0.5
def test_crop_img(self): def test_imcrop(self):
img = mmcv.read_img(self.img_path)
# yapf: disable # yapf: disable
bboxes = np.array([[100, 100, 199, 199], # center bboxes = np.array([[100, 100, 199, 199], # center
[0, 0, 150, 100], # left-top corner [0, 0, 150, 100], # left-top corner
...@@ -179,46 +186,51 @@ class TestImage(object): ...@@ -179,46 +186,51 @@ class TestImage(object):
[0, 100, 399, 199], # wide [0, 100, 399, 199], # wide
[150, 0, 299, 299]]) # tall [150, 0, 299, 299]]) # tall
# yapf: enable # yapf: enable
# crop one bbox # crop one bbox
patch = mmcv.crop_img(img, bboxes[0, :]) patch = mmcv.imcrop(self.img, bboxes[0, :])
patches = mmcv.crop_img(img, bboxes[[0], :]) patches = mmcv.imcrop(self.img, bboxes[[0], :])
assert patch.shape == (100, 100, 3) assert patch.shape == (100, 100, 3)
patch_path = osp.join(osp.dirname(__file__), 'data/patches') patch_path = osp.join(osp.dirname(__file__), 'data/patches')
ref_patch = np.load(patch_path + '/0.npy') ref_patch = np.load(patch_path + '/0.npy')
self.assert_img_equal(patch, ref_patch) self.assert_img_equal(patch, ref_patch)
assert isinstance(patches, list) and len(patches) == 1 assert isinstance(patches, list) and len(patches) == 1
self.assert_img_equal(patches[0], ref_patch) self.assert_img_equal(patches[0], ref_patch)
# crop with no scaling and padding # crop with no scaling and padding
patches = mmcv.crop_img(img, bboxes) patches = mmcv.imcrop(self.img, bboxes)
assert len(patches) == bboxes.shape[0] assert len(patches) == bboxes.shape[0]
for i in range(len(patches)): for i in range(len(patches)):
ref_patch = np.load(patch_path + '/{}.npy'.format(i)) ref_patch = np.load(patch_path + '/{}.npy'.format(i))
self.assert_img_equal(patches[i], ref_patch) self.assert_img_equal(patches[i], ref_patch)
# crop with scaling and no padding # crop with scaling and no padding
patches = mmcv.crop_img(img, bboxes, 1.2) patches = mmcv.imcrop(self.img, bboxes, 1.2)
for i in range(len(patches)): for i in range(len(patches)):
ref_patch = np.load(patch_path + '/scale_{}.npy'.format(i)) ref_patch = np.load(patch_path + '/scale_{}.npy'.format(i))
self.assert_img_equal(patches[i], ref_patch) self.assert_img_equal(patches[i], ref_patch)
# crop with scaling and padding # crop with scaling and padding
patches = mmcv.crop_img(img, bboxes, 1.2, pad_fill=[255, 255, 0]) patches = mmcv.imcrop(self.img, bboxes, 1.2, pad_fill=[255, 255, 0])
for i in range(len(patches)): for i in range(len(patches)):
ref_patch = np.load(patch_path + '/pad_{}.npy'.format(i)) ref_patch = np.load(patch_path + '/pad_{}.npy'.format(i))
self.assert_img_equal(patches[i], ref_patch) self.assert_img_equal(patches[i], ref_patch)
patches = mmcv.crop_img(img, bboxes, 1.2, pad_fill=0) patches = mmcv.imcrop(self.img, bboxes, 1.2, pad_fill=0)
for i in range(len(patches)): for i in range(len(patches)):
ref_patch = np.load(patch_path + '/pad0_{}.npy'.format(i)) ref_patch = np.load(patch_path + '/pad0_{}.npy'.format(i))
self.assert_img_equal(patches[i], ref_patch) self.assert_img_equal(patches[i], ref_patch)
def test_pad_img(self): def test_impad(self):
img = np.random.rand(10, 10, 3).astype(np.float32) img = np.random.rand(10, 10, 3).astype(np.float32)
padded_img = mmcv.pad_img(img, (15, 12), 0) padded_img = mmcv.impad(img, (15, 12), 0)
assert_array_equal(img, padded_img[:10, :10, :]) assert_array_equal(img, padded_img[:10, :10, :])
assert_array_equal( assert_array_equal(
np.zeros((5, 12, 3), dtype='float32'), padded_img[10:, :, :]) np.zeros((5, 12, 3), dtype='float32'), padded_img[10:, :, :])
assert_array_equal( assert_array_equal(
np.zeros((15, 2, 3), dtype='float32'), padded_img[:, 10:, :]) np.zeros((15, 2, 3), dtype='float32'), padded_img[:, 10:, :])
img = np.random.randint(256, size=(10, 10, 3)).astype('uint8') img = np.random.randint(256, size=(10, 10, 3)).astype('uint8')
padded_img = mmcv.pad_img(img, (15, 12, 3), [100, 110, 120]) padded_img = mmcv.impad(img, (15, 12, 3), [100, 110, 120])
assert_array_equal(img, padded_img[:10, :10, :]) assert_array_equal(img, padded_img[:10, :10, :])
assert_array_equal( assert_array_equal(
np.array([100, 110, 120], dtype='uint8') * np.ones( np.array([100, 110, 120], dtype='uint8') * np.ones(
...@@ -226,27 +238,31 @@ class TestImage(object): ...@@ -226,27 +238,31 @@ class TestImage(object):
assert_array_equal( assert_array_equal(
np.array([100, 110, 120], dtype='uint8') * np.ones( np.array([100, 110, 120], dtype='uint8') * np.ones(
(15, 2, 3), dtype='uint8'), padded_img[:, 10:, :]) (15, 2, 3), dtype='uint8'), padded_img[:, 10:, :])
with pytest.raises(AssertionError): with pytest.raises(AssertionError):
mmcv.pad_img(img, (15, ), 0) mmcv.impad(img, (15, ), 0)
with pytest.raises(AssertionError): with pytest.raises(AssertionError):
mmcv.pad_img(img, (5, 5), 0) mmcv.impad(img, (5, 5), 0)
with pytest.raises(AssertionError): with pytest.raises(AssertionError):
mmcv.pad_img(img, (5, 5), [0, 1]) mmcv.impad(img, (5, 5), [0, 1])
def test_rotate_img(self): def test_imrotate(self):
img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).astype(np.uint8) img = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]).astype(np.uint8)
assert_array_equal(mmcv.rotate_img(img, 0), img) assert_array_equal(mmcv.imrotate(img, 0), img)
img_r = np.array([[7, 4, 1], [8, 5, 2], [9, 6, 3]]) img_r = np.array([[7, 4, 1], [8, 5, 2], [9, 6, 3]])
assert_array_equal(mmcv.rotate_img(img, 90), img_r) assert_array_equal(mmcv.imrotate(img, 90), img_r)
img_r = np.array([[3, 6, 9], [2, 5, 8], [1, 4, 7]]) img_r = np.array([[3, 6, 9], [2, 5, 8], [1, 4, 7]])
assert_array_equal(mmcv.rotate_img(img, -90), img_r) assert_array_equal(mmcv.imrotate(img, -90), img_r)
img = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]).astype(np.uint8) img = np.array([[1, 2, 3, 4], [5, 6, 7, 8]]).astype(np.uint8)
img_r = np.array([[0, 6, 2, 0], [0, 7, 3, 0]]) img_r = np.array([[0, 6, 2, 0], [0, 7, 3, 0]])
assert_array_equal(mmcv.rotate_img(img, 90), img_r) assert_array_equal(mmcv.imrotate(img, 90), img_r)
img_r = np.array([[1, 0, 0, 0], [2, 0, 0, 0]]) img_r = np.array([[1, 0, 0, 0], [2, 0, 0, 0]])
assert_array_equal(mmcv.rotate_img(img, 90, center=(0, 0)), img_r) assert_array_equal(mmcv.imrotate(img, 90, center=(0, 0)), img_r)
img_r = np.array([[255, 6, 2, 255], [255, 7, 3, 255]]) img_r = np.array([[255, 6, 2, 255], [255, 7, 3, 255]])
assert_array_equal(mmcv.rotate_img(img, 90, border_value=255), img_r) assert_array_equal(mmcv.imrotate(img, 90, border_value=255), img_r)
img_r = np.array([[5, 1], [6, 2], [7, 3], [8, 4]]) img_r = np.array([[5, 1], [6, 2], [7, 3], [8, 4]])
assert_array_equal(mmcv.rotate_img(img, 90, auto_bound=True), img_r) assert_array_equal(mmcv.imrotate(img, 90, auto_bound=True), img_r)
with pytest.raises(ValueError):
mmcv.imrotate(img, 90, center=(0, 0), auto_bound=True)
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