Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion batchgeneratorsv2/transforms/intensity/brightness.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ def __init__(self, multiplier_range: RandomScalar, synchronize_channels: bool, p

def get_parameters(self, **data_dict) -> dict:
shape = data_dict['image'].shape
apply_to_channel = torch.where(torch.rand(shape[0]) < self.p_per_channel)[0]
apply_to_channel_np = np.where(np.random.rand(shape[0]) < self.p_per_channel)[0]
apply_to_channel = torch.from_numpy(apply_to_channel_np)
if self.synchronize_channels:
multipliers = torch.Tensor([sample_scalar(self.multiplier_range, image=data_dict['image'], channel=None)] * len(apply_to_channel))
else:
Expand Down
3 changes: 2 additions & 1 deletion batchgeneratorsv2/transforms/intensity/contrast.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ def __init__(self, contrast_range: RandomScalar, preserve_range: bool, synchroni

def get_parameters(self, **data_dict) -> dict:
shape = data_dict['image'].shape
apply_to_channel = torch.where(torch.rand(shape[0]) < self.p_per_channel)[0]
apply_to_channel_np = np.where(np.random.rand(shape[0]) < self.p_per_channel)[0]
apply_to_channel = torch.from_numpy(apply_to_channel_np)
if self.synchronize_channels:
multipliers = torch.Tensor([sample_scalar(self.contrast_range, image=data_dict['image'], channel=None)] * len(apply_to_channel))
else:
Expand Down
9 changes: 6 additions & 3 deletions batchgeneratorsv2/transforms/intensity/gamma.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from batchgeneratorsv2.helpers.scalar_type import RandomScalar, sample_scalar
from batchgeneratorsv2.transforms.base.basic_transform import ImageOnlyTransform

import numpy as np

class GammaTransform(ImageOnlyTransform):
def __init__(self, gamma: RandomScalar, p_invert_image: float, synchronize_channels: bool, p_per_channel: float,
Expand All @@ -18,9 +19,11 @@ def __init__(self, gamma: RandomScalar, p_invert_image: float, synchronize_chann

def get_parameters(self, **data_dict) -> dict:
shape = data_dict['image'].shape
apply_to_channel = torch.where(torch.rand(shape[0]) < self.p_per_channel)[0]
retain_stats = torch.rand(len(apply_to_channel)) < self.p_retain_stats
invert_image = torch.rand(len(apply_to_channel)) < self.p_invert_image
apply_to_channel_np = np.where(np.random.rand(shape[0]) < self.p_per_channel)[0]
apply_to_channel = torch.from_numpy(apply_to_channel_np)

retain_stats = torch.from_numpy(np.random.rand(len(apply_to_channel)) < self.p_retain_stats)
invert_image = torch.from_numpy(np.random.rand(len(apply_to_channel)) < self.p_invert_image)

if self.synchronize_channels:
gamma = torch.Tensor([sample_scalar(self.gamma, image=data_dict['image'], channel=None)] * len(apply_to_channel))
Expand Down
17 changes: 8 additions & 9 deletions batchgeneratorsv2/transforms/intensity/gaussian_noise.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from batchgeneratorsv2.transforms.base.basic_transform import ImageOnlyTransform
import torch

import numpy as np


class GaussianNoiseTransform(ImageOnlyTransform):
def __init__(self,
Expand All @@ -19,7 +21,7 @@ def __init__(self,
def get_parameters(self, **data_dict) -> dict:
shape = data_dict['image'].shape
dct = {}
dct['apply_to_channel'] = torch.rand(shape[0]) < self.p_per_channel
dct['apply_to_channel'] = np.random.rand(shape[0]) < self.p_per_channel
dct['sigmas'] = \
[sample_scalar(self.noise_variance, data_dict['image'])
for i in range(sum(dct['apply_to_channel']))] if not self.synchronize_channels \
Expand All @@ -36,15 +38,12 @@ def _apply_to_image(self, img: torch.Tensor, **params) -> torch.Tensor:
def _sample_gaussian_noise(self, img_shape: Tuple[int, ...], **params):
if not isinstance(params['sigmas'], list):
num_channels = sum(params['apply_to_channel'])
# gaussian = torch.tile(torch.normal(0, params['sigmas'], size=(1, *img_shape[1:])),
# (num_channels, *[1]*(len(img_shape) - 1)))
gaussian = torch.normal(0, params['sigmas'], size=(1, *img_shape[1:]))
gaussian.expand((num_channels, *[-1]*(len(img_shape) - 1)))
noise_np = np.random.normal(0, params['sigmas'], size=(1, *img_shape[1:]))
gaussian = torch.from_numpy(noise_np.astype(np.float32))
gaussian = gaussian.expand((num_channels, *[-1]*(len(img_shape) - 1)))
else:
gaussian = [
torch.normal(0, i, size=(1, *img_shape[1:])) for i in params['sigmas']
]
gaussian = torch.cat(gaussian, dim=0)
noise_np_list = [np.random.normal(0, i, size=(1, *img_shape[1:])) for i in params['sigmas']]
gaussian = torch.cat([torch.from_numpy(n.astype(np.float32)) for n in noise_np_list], dim=0)
return gaussian


Expand Down
3 changes: 2 additions & 1 deletion batchgeneratorsv2/transforms/intensity/inversion.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ def get_parameters(self, **data_dict) -> dict:
if np.random.uniform() < self.p_synchronize_channels:
apply_to_channel = torch.arange(0, shape[0])
else:
apply_to_channel = torch.where(torch.rand(shape[0]) < self.p_per_channel)[0]
apply_to_channel_np = np.where(np.random.rand(shape[0]) < self.p_per_channel)[0]
apply_to_channel = torch.from_numpy(apply_to_channel_np)
else:
apply_to_channel = []
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def __init__(self,
def get_parameters(self, **data_dict) -> dict:
# this needs to be applied in random order to the channels
np.random.shuffle(self.channel_idx)
apply_to_channels = [self.channel_idx[i] for i, j in enumerate(torch.rand(len(self.channel_idx)) < self.p_per_label) if j]
apply_to_channels = [self.channel_idx[i] for i, j in enumerate(np.random.rand(len(self.channel_idx)) < self.p_per_label) if j]
operators = [np.random.choice(self.any_of_these) for _ in apply_to_channels]
strel_size = [sample_scalar(self.strel_size, image=data_dict['image'], channel=a) for a in apply_to_channels]
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def __init__(self,
def get_parameters(self, **data_dict) -> dict:
# this needs to be applied in random order to the channels
np.random.shuffle(self.channel_idx)
apply_to_channels = [self.channel_idx[i] for i, j in enumerate(torch.rand(len(self.channel_idx)) < self.p_per_label) if j]
apply_to_channels = [self.channel_idx[i] for i, j in enumerate(np.random.rand(len(self.channel_idx)) < self.p_per_label) if j]

# self.fill_with_other_class_p cannot be resolved here because we don't know how many components there are
return {
Expand Down
4 changes: 2 additions & 2 deletions batchgeneratorsv2/transforms/noise/gaussian_blur.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def __init__(self,
benchmark: bool = False
):
"""
uses separable gaussian filters for all the speed
Uses separable gaussian filters for all the speed. Note : Benchmark = True will likely make the transform non deterministic.

blur_sigma, if callable, will be called as blur_sigma(image, shape, dim) where shape is (c, x(, y, z) and dim i
s 1, 2 or 3 for x, y and z, respectively)
Expand All @@ -99,7 +99,7 @@ def get_parameters(self, **data_dict) -> dict:
shape = data_dict['image'].shape
dims = len(shape) - 1
dct = {}
dct['apply_to_channel'] = torch.rand(shape[0]) < self.p_per_channel
dct['apply_to_channel'] = np.random.rand(shape[0]) < self.p_per_channel
if self.synchronize_axes:
dct['sigmas'] = \
[[sample_scalar(self.blur_sigma, shape, dim=None)] * dims
Expand Down
8 changes: 5 additions & 3 deletions batchgeneratorsv2/transforms/noise/rician.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import torch
from typing import Tuple
from batchgeneratorsv2.transforms.base.basic_transform import ImageOnlyTransform

import numpy as np

class RicianNoiseTransform(ImageOnlyTransform):
"""
Expand All @@ -21,8 +21,10 @@ def get_parameters(self, image: torch.Tensor, **kwargs) -> dict:

def _apply_to_image(self, img: torch.Tensor, **params) -> torch.Tensor:
var = params['variance']
noise_real = torch.empty_like(img).normal_(mean=0.0, std=var)
noise_imag = torch.empty_like(img).normal_(mean=0.0, std=var)
noise_real_np = np.random.normal(0.0, var, size=img.shape).astype(np.float32)
noise_imag_np = np.random.normal(0.0, var, size=img.shape).astype(np.float32)
noise_real = torch.from_numpy(noise_real_np).to(img.device)
noise_imag = torch.from_numpy(noise_imag_np).to(img.device)

min_val = img.min()
shifted = img - min_val
Expand Down
6 changes: 4 additions & 2 deletions batchgeneratorsv2/transforms/spatial/low_resolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from batchgeneratorsv2.transforms.base.basic_transform import ImageOnlyTransform
from torch.nn.functional import interpolate

import numpy as np

class SimulateLowResolutionTransform(ImageOnlyTransform):
def __init__(self,
Expand All @@ -32,9 +33,10 @@ def __init__(self,
def get_parameters(self, **data_dict) -> dict:
shape = data_dict['image'].shape
if self.allowed_channels is None:
apply_to_channel = torch.where(torch.rand(shape[0]) < self.p_per_channel)[0]
apply_to_channel_np = np.where(np.random.rand(shape[0]) < self.p_per_channel)[0]
apply_to_channel = torch.from_numpy(apply_to_channel_np)
else:
apply_to_channel = [i for i in self.allowed_channels if torch.rand(1) < self.p_per_channel]
apply_to_channel = [i for i in self.allowed_channels if np.random.rand() < self.p_per_channel]
if self.synchronize_channels:
if self.synchronize_axes:
scales = torch.Tensor([[sample_scalar(self.scale, image=data_dict['image'], channel=None, dim=None)] * (len(shape) - 1)] * len(apply_to_channel))
Expand Down
3 changes: 2 additions & 1 deletion batchgeneratorsv2/transforms/spatial/mirroring.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,15 @@

from batchgeneratorsv2.transforms.base.basic_transform import BasicTransform

import numpy as np

class MirrorTransform(BasicTransform):
def __init__(self, allowed_axes: Tuple[int, ...]):
super().__init__()
self.allowed_axes = allowed_axes

def get_parameters(self, **data_dict) -> dict:
axes = [i for i in self.allowed_axes if torch.rand(1) < 0.5]
axes = [i for i in self.allowed_axes if np.random.rand() < 0.5]
return {
'axes': axes
}
Expand Down
23 changes: 7 additions & 16 deletions batchgeneratorsv2/transforms/spatial/spatial.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,27 +115,18 @@ def get_parameters(self, **data_dict) -> dict:
dim=i, deformation_scale=deformation_scales[i])
for i in range(dim)]
# doing it like this for better memory layout for blurring
offsets = torch.normal(mean=0, std=1, size=(dim, *self.patch_size))
offsets_np = np.random.randn(dim, *self.patch_size).astype(np.float32)

# all the additional time elastic deform takes is spent here
for d in range(dim):
# fft torch, slower
# for i in range(offsets.ndim - 1):
# offsets[d] = blur_dimension(offsets[d][None], sigmas[d], i, force_use_fft=True, truncate=6)[0]

# fft numpy, this is faster o.O
tmp = np.fft.fftn(offsets[d].numpy())
tmp = np.fft.fftn(offsets_np[d])
tmp = fourier_gaussian(tmp, sigmas[d])
offsets[d] = torch.from_numpy(np.fft.ifftn(tmp).real)

# tmp = offsets[d].numpy().astype(np.float64)
# gaussian_filter(tmp, sigmas[d], 0, output=tmp)
# offsets[d] = torch.from_numpy(tmp).to(offsets.dtype)
# print(offsets.dtype)
offsets_np[d] = np.fft.ifftn(tmp).real

mx = torch.max(torch.abs(offsets[d]))
offsets[d] /= (mx / np.clip(magnitude[d], a_min=1e-8, a_max=np.inf))
mx = np.max(np.abs(offsets_np[d]))
offsets_np[d] /= (mx / np.clip(magnitude[d], a_min=1e-8, a_max=np.inf))

spatial_dims = tuple(list(range(1, dim + 1)))
offsets = torch.from_numpy(offsets_np)
offsets = torch.permute(offsets, (*spatial_dims, 0))
else:
offsets = None
Expand Down
2 changes: 1 addition & 1 deletion batchgeneratorsv2/transforms/utils/random.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def __init__(self, transform: BasicTransform, apply_probability: float = 1):
self.apply_probability = apply_probability

def get_parameters(self, **data_dict) -> dict:
return {"apply_transform": torch.rand(1).item() < self.apply_probability}
return {"apply_transform": np.random.rand() < self.apply_probability}

def apply(self, data_dict: dict, **params) -> dict:
if params['apply_transform']:
Expand Down
Loading