Source code for visual.transforms

import random
import math

import torch
import torch.nn.functional as F

from .images import FFTImage


[docs]class Compose(object): """ Composes a number of Image transforms, similar to torchvision.transforms.Compose for torchvision transforms Args: transforms (list / tuple): Transforms to compose """ def __init__(self, transforms): super(Compose, self).__init__() self._transforms = transforms def __call__(self, x): for transform in self._transforms: x = transform(x) return x
def _rand_select(xs, seed=None): xs = list(xs) if seed is not None: random.seed(a=seed) idx = random.randint(0, len(xs) - 1) return xs[idx] def _as_4d(x): if x.dim() == 3: return x.unsqueeze(0) else: return x def _as_3d(x): if x.dim() == 4: return x.squeeze(0) else: return x
[docs]class RandomScale(object): """ Transform that randomly scales the input from a set list of scales Args: scales (list / tuple): Set of scales that can be chosen mode (str): Interpolation mode. See `torch.nn.functional.interpolate <https://pytorch.org/docs/stable/nn.html?highlight=interpolate#torch.nn.functional.interpolate>`_ align_corners (bool, optional): See `torch.nn.functional.interpolate`_ seed: Random seed """ def __init__(self, scales, mode='bilinear', align_corners=None, seed=None): self._scales = scales self._mode = mode self._align_corners = align_corners self._seed = seed
[docs] @staticmethod def get_params(scales, seed=None): return _rand_select(scales, seed)
def __call__(self, x): return _as_3d(F.interpolate( _as_4d(x), scale_factor=self.get_params(self._scales, self._seed), mode=self._mode, align_corners=self._align_corners ))
[docs]class RandomRotate(object): """ Image transform that randomly rotates the input from a set of possible angles Args: angles: Set and possible angles units: Rotation units. If 'degrees' ,'degs', 'deg' the use degrees, Else use radians mode: Interpolation mode. See `torch.nn.functional.grid_sample <https://pytorch.org/docs/stable/nn.html?highlight=grid%20sample#torch.nn.functional.grid_sample>`_ padding_mode: Padding mode. See `torch.nn.functional.grid_sample`_ seed: Random seed """ def __init__(self, angles, units='degrees', mode='bilinear', padding_mode='zeros', seed=None): if units.lower() in ['degrees', 'degs', 'deg']: for i in range(len(angles)): angles[i] = math.pi * angles[i] / 180. self._angles = angles self._mode = mode self._padding_mode = padding_mode self._seed = seed
[docs] @staticmethod def get_params(angles, seed=None): return _rand_select(angles, seed)
def __call__(self, x): x = _as_4d(x) angle = self.get_params(self._angles, self._seed) theta = torch.zeros((1, 2, 3), device=x.device, dtype=x.dtype) theta[0, 0, 0] = math.cos(angle) theta[0, 1, 1] = math.cos(angle) theta[0, 0, 1] = math.sin(angle) theta[0, 1, 0] = -math.sin(angle) grid = F.affine_grid(theta, x.size()) return _as_3d(F.grid_sample( x, grid, mode=self._mode, padding_mode=self._padding_mode ))
[docs]class RandomAlpha(object): """ Image transform that creates a random alpha mask Args: sd: decay_power: colour: If True: Create a mask for each colour channel. Else create a single alpha channel """ def __init__(self, sd=0.5, decay_power=1, colour=True): self._sd = sd self._decay_power = decay_power self._colour = colour def __call__(self, x): x = _as_3d(x) size = list(x.size()) size[0] = size[0] - 1 if self._colour else 1 random_image = FFTImage(size, correlate=self._colour, sd=self._sd, decay_power=self._decay_power, requires_grad=False).to(x.device).sigmoid().get_valid_image() alpha = x[-1].repeat(x.size(0) - 1, 1, 1) image = x[:-1] * alpha random_image = random_image * (1 - alpha) return image + random_image
[docs]class SpatialJitter(object): def __init__(self, pixels, seed=None): self._pixels = pixels self._seed = seed
[docs] @staticmethod def get_params(pixels, seed=None): if seed is not None: random.seed(seed) return random.randint(0, pixels), random.randint(0, pixels)
def __call__(self, img): img = _as_3d(img) x_offset, y_offset = self.get_params(self._pixels, self._seed) x_end = img.size(1) - (self._pixels - x_offset) y_end = img.size(2) - (self._pixels - y_offset) return img[:, x_offset:x_end, y_offset:y_end]