Source code for gluoncv.data.transforms.presets.ssd
"""Transforms described in https://arxiv.org/abs/1512.02325."""
from __future__ import absolute_import
import numpy as np
import mxnet as mx
from .. import bbox as tbbox
from .. import image as timage
from .. import experimental
__all__ = ['load_test', 'SSDDefaultTrainTransform', 'SSDDefaultValTransform']
[docs]def load_test(filenames, short, max_size=1024, mean=(0.485, 0.456, 0.406),
std=(0.229, 0.224, 0.225)):
"""A util function to load all images, transform them to tensor by applying
normalizations. This function support 1 filename or list of filenames.
Parameters
----------
filenames : str or list of str
Image filename(s) to be loaded.
short : int
Resize image short side to this `short` and keep aspect ratio.
max_size : int, optional
Maximum longer side length to fit image.
This is to limit the input image shape. Aspect ratio is intact because we
support arbitrary input size in our SSD implementation.
mean : iterable of float
Mean pixel values.
std : iterable of float
Standard deviations of pixel values.
Returns
-------
(mxnet.NDArray, numpy.ndarray) or list of such tuple
A (1, 3, H, W) mxnet NDArray as input to network, and a numpy ndarray as
original un-normalized color image for display.
If multiple image names are supplied, return two lists. You can use
`zip()`` to collapse it.
"""
if isinstance(filenames, str):
filenames = [filenames]
tensors = []
origs = []
for f in filenames:
img = mx.image.imread(f)
img = mx.image.resize_short(img, short)
if isinstance(max_size, int) and max(img.shape) > max_size:
img = timage.resize_long(img, max_size)
orig_img = img.asnumpy().astype('uint8')
img = mx.nd.image.to_tensor(img)
img = mx.nd.image.normalize(img, mean=mean, std=std)
tensors.append(img.expand_dims(0))
origs.append(orig_img)
if len(tensors) == 1:
return tensors[0], origs[0]
return tensors, origs
[docs]class SSDDefaultTrainTransform(object):
"""Default SSD training transform which includes tons of image augmentations.
Parameters
----------
width : int
Image width.
height : int
Image height.
mean : array-like of size 3
Mean pixel values to be subtracted from image tensor. Default is [0.485, 0.456, 0.406].
std : array-like of size 3
Standard deviation to be divided from image. Default is [0.229, 0.224, 0.225].
"""
def __init__(self, width, height, mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)):
self._width = width
self._height = height
self._mean = mean
self._std = std
def __call__(self, src, label):
# random color jittering
img = experimental.image.random_color_distort(src)
# random expansion with prob 0.5
if np.random.uniform(0, 1) > 0.5:
img, expand = timage.random_expand(img, fill=[m * 255 for m in self._mean])
bbox = tbbox.translate(label, x_offset=expand[0], y_offset=expand[1])
else:
img, bbox = img, label
# random cropping
h, w, _ = img.shape
bbox, crop = experimental.bbox.random_crop_with_constraints(bbox, (w, h))
x0, y0, w, h = crop
img = mx.image.fixed_crop(img, x0, y0, w, h)
# resize with random interpolation
h, w, _ = img.shape
interp = np.random.randint(0, 5)
img = timage.imresize(img, self._width, self._height, interp=interp)
bbox = tbbox.resize(bbox, (w, h), (self._width, self._height))
# random horizontal flip
h, w, _ = img.shape
img, flips = timage.random_flip(img, px=0.5)
bbox = tbbox.flip(bbox, (w, h), flip_x=flips[0])
# to tensor
img = mx.nd.image.to_tensor(img)
img = mx.nd.image.normalize(img, mean=self._mean, std=self._std)
return img, bbox.astype('float32')
[docs]class SSDDefaultValTransform(object):
"""Default SSD validation transform.
Parameters
----------
width : int
Image width.
height : int
Image height.
mean : array-like of size 3
Mean pixel values to be subtracted from image tensor. Default is [0.485, 0.456, 0.406].
std : array-like of size 3
Standard deviation to be divided from image. Default is [0.229, 0.224, 0.225].
"""
def __init__(self, width, height, mean=(0.485, 0.456, 0.406), std=(0.229, 0.224, 0.225)):
self._width = width
self._height = height
self._mean = mean
self._std = std
def __call__(self, src, label):
# resize
h, w, _ = src.shape
img = timage.imresize(src, self._width, self._height)
bbox = tbbox.resize(label, in_size=(w, h), out_size=(self._width, self._height))
img = mx.nd.image.to_tensor(img)
img = mx.nd.image.normalize(img, mean=self._mean, std=self._std)
return img, bbox.astype('float32')