Resizing utilities
@@ -7,6 +7,7 @@ import logging
from collections import OrderedDict
import numpy as np
+import cv2
from .constants import FeatureType
@@ -475,3 +476,79 @@ def constant_pad(X, multiple_of, up_down_rule='even', left_right_rule='even', pa
def bgr_to_rgb(bgr):
"""Converts Blue, Green, Red to Red, Green, Blue."""
return bgr[..., [2, 1, 0]]
+
+def map_image_slices(data, func2d):
+ """Iterate over time and band dimensions and apply a function to each slice.
+
+ Returns a new array with the combined results.
+
+ :param data: input array
+ :type data: array of shape (timestamps, rows, columns, channels)
+ :param func2d: Mapping function that is applied on each 2d image slice. All outputs must have the same shape.
+ :type func2d: function (rows, columns) -> (new_rows, new_columns)
+ """
+
+ idx = np.ndindex(data.shape[0], data.shape[3])
+ output = None
+ for i,j in idx:
+ res = func2d(data[i,...,j])
+ if output is None:
+ output = np.zeros((data.shape[0],) + res.shape + (data.shape[3],), dtype=res.dtype)
+
+ output[i,...,j] = res
+
+ return output
+
+def resize_images(data, new_size=None, scale_factors=None, anti_alias=True, interpolation='linear'):
+ """Resizes the images acording to given size or scale factors.
+
+ To specify the new scale use one of `new_size` or `scale_factors` parameters.
+
+ :param data: input array
+ :type data: array of shape (timestamps, rows, columns, channels)
+ :param new_size: New size of the data (width, height)
+ :type new_size: (int, int)
+ :param scale_factors: Factors (fx,fy) by which to resize the image
+ :type scale_factors: (float, float)
+ :param anti_alias: Use anti aliasing smoothing operation when downsampling.
+ :type anti_alias: bool
+ :param interpolation: Interpolation method used for resampling. One of 'nearest', 'linear', 'cubic'.
+ :type interpolation: bool
+ """
+
+ INTER_METHODS = {
+ 'nearest': cv2.INTER_NEAREST,
+ 'linear': cv2.INTER_LINEAR,
+ 'cubic': cv2.INTER_CUBIC
+ }
+
+ # Old width and height
+ old_size = (data.shape[2], data.shape[1])
+
+ if new_size is not None and scale_factors is None:
+ scale_factors = [new/old for old, new in zip(old_size, new_size)]
+ elif scale_factors is not None and new_size is None:
+ new_size = [int(d * f) for d,f in zip(old_size, scale_factors)]
+ else:
+ raise ValueError('Exactly one of the arguments new_size, scale_factors must be given.')
+
+ if interpolation not in INTER_METHODS:
+ raise ValueError('Invalid interpolation method: %s' % interpolation)
+
+ interpolation_method = INTER_METHODS[interpolation]
+ downscaling = scale_factors[0] < 1 or scale_factors[0] < 1
+
+ def _resize(image):
+ # Perform anti-alias smoothing if downscaling
+ if downscaling and anti_alias:
+ sx, sy = [((1/s) - 1)/2 for s in scale_factors]
+ blured = cv2.GaussianBlur(image, (0,0), sigmaX=sx, sigmaY=sy, borderType=cv2.BORDER_REFLECT)
+
+ resized = cv2.resize(blured, new_size, interpolation=interpolation_method)
+
+ return resized
+
+ # Apply _resize function to each image slice
+ resized = map_image_slices(data, _resize)
+
+ return resized
