# ------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License (MIT). See LICENSE in the repo root for license information.
# ------------------------------------------------------------------------------------------
import random
from typing import Tuple
import numpy as np
import torch
import torchvision
from scipy.ndimage import gaussian_filter, map_coordinates
[docs]class RandomGamma:
"""
Custom function to apply a random gamma transform within a specified range of possible gamma value.
See documentation of
[`adjust_gamma`](https://pytorch.org/vision/0.8/transforms.html#torchvision.transforms.functional.adjust_gamma) for
more details.
"""
def __init__(self, scale: Tuple[float, float]) -> None:
"""
:param scale: a tuple (min_gamma, max_gamma) that specifies the range of possible values to sample the gamma
value from when the transformation is called.
"""
self.scale = scale
def __call__(self, image: torch.Tensor) -> torch.Tensor:
gamma = random.uniform(*self.scale)
if len(image.shape) != 4:
raise ValueError(f"Expected input of shape [Z, C, H, W], but only got {len(image.shape)} dimensions")
for z in range(image.shape[0]):
for c in range(image.shape[1]):
image[z, c] = torchvision.transforms.functional.adjust_gamma(image[z, c], gamma=gamma)
return image
[docs]class ExpandChannels:
"""
Transforms an image with 1 channel to an image with 3 channels by copying pixel intensities of the image along
the 1st dimension.
"""
def __call__(self, data: torch.Tensor) -> torch.Tensor:
"""
:param: data of shape [Z, 1, H, W]
:return: data with channel copied 3 times, shape [Z, 3, H, W]
"""
shape = data.shape
if len(shape) != 4 or shape[1] != 1:
raise ValueError(f"Expected input of shape [Z, 1, H, W], found {shape}")
return torch.repeat_interleave(data, 3, dim=1)
[docs]class AddGaussianNoise:
def __init__(self, p_apply: float, std: float) -> None:
"""
Transformation to add Gaussian noise N(0, std) to an image.
:param: p_apply: probability of applying the transformation.
:param: std: standard deviation of the gaussian noise to add to the image.
"""
super().__init__()
self.p_apply = p_apply
self.std = std
def __call__(self, data: torch.Tensor) -> torch.Tensor:
if np.random.random(1) > self.p_apply:
return data
noise = torch.randn(size=data.shape[-2:]) * self.std
data = torch.clamp(data + noise, data.min(), data.max()) # type: ignore
return data