From 9aa395b3ae9ed7ae81d52bbf1d75b88502fd6763 Mon Sep 17 00:00:00 2001 From: Rich <33289025+rijobro@users.noreply.github.com> Date: Mon, 1 Feb 2021 09:54:32 +0000 Subject: [PATCH 1/6] rand_gaussian_noised with multiple keys Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> --- monai/transforms/intensity/dictionary.py | 11 +++++---- tests/test_rand_gaussian_noised.py | 30 ++++++++++-------------- 2 files changed, 19 insertions(+), 22 deletions(-) diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py index 18e2250084..cb1b6133aa 100644 --- a/monai/transforms/intensity/dictionary.py +++ b/monai/transforms/intensity/dictionary.py @@ -113,24 +113,25 @@ def __init__( self.mean = ensure_tuple_size(mean, len(self.keys)) self.std = std self._do_transform = False - self._noise: Optional[np.ndarray] = None + self._noise: Sequence[np.ndarray] = [] def randomize(self, im_shape: Sequence[int]) -> None: self._do_transform = self.R.random() < self.prob - self._noise = self.R.normal(self.mean, self.R.uniform(0, self.std), size=im_shape) + for m in self.mean: + self._noise.append(self.R.normal(m, self.R.uniform(0, self.std), size=im_shape)) def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.ndarray]: d = dict(data) image_shape = d[self.keys[0]].shape # image shape from the first data key self.randomize(image_shape) - if self._noise is None: + if not self._noise: raise AssertionError if not self._do_transform: return d - for key in self.keys: + for i, key in enumerate(self.keys): dtype = dtype_torch_to_numpy(d[key].dtype) if isinstance(d[key], torch.Tensor) else d[key].dtype - d[key] = d[key] + self._noise.astype(dtype) + d[key] = d[key] + self._noise[i].astype(dtype) return d diff --git a/tests/test_rand_gaussian_noised.py b/tests/test_rand_gaussian_noised.py index 63da23c8dc..3162706b6b 100644 --- a/tests/test_rand_gaussian_noised.py +++ b/tests/test_rand_gaussian_noised.py @@ -17,38 +17,34 @@ from monai.transforms import RandGaussianNoised from tests.utils import NumpyImageTestCase2D, TorchImageTestCase2D -TEST_CASE_0 = ["test_zero_mean", ["img"], 0, 0.1] +TEST_CASE_0 = ["test_zero_mean", ["img", "im2"], 0, 0.1] TEST_CASE_1 = ["test_non_zero_mean", ["img"], 1, 0.5] TEST_CASES = [TEST_CASE_0, TEST_CASE_1] seed = 0 -# Test with numpy - +def test_numpy_or_torch(keys, mean, std, imt): + gaussian_fn = RandGaussianNoised(keys=keys, prob=1.0, mean=mean, std=std) + gaussian_fn.set_random_state(seed) + noised = gaussian_fn({k: imt for k in keys}) + np.random.seed(seed) + np.random.random() + for k in keys: + expected = imt + np.random.normal(mean, np.random.uniform(0, std), size=imt.shape) + np.testing.assert_allclose(expected, noised[k], atol=1e-5, rtol=1e-5) +# Test with numpy class TestRandGaussianNoisedNumpy(NumpyImageTestCase2D): @parameterized.expand(TEST_CASES) def test_correct_results(self, _, keys, mean, std): - gaussian_fn = RandGaussianNoised(keys=keys, prob=1.0, mean=mean, std=std) - gaussian_fn.set_random_state(seed) - noised = gaussian_fn({"img": self.imt}) - np.random.seed(seed) - np.random.random() - expected = self.imt + np.random.normal(mean, np.random.uniform(0, std), size=self.imt.shape) - np.testing.assert_allclose(expected, noised["img"], atol=1e-5, rtol=1e-5) + test_numpy_or_torch(keys, mean, std, self.imt) # Test with torch class TestRandGaussianNoisedTorch(TorchImageTestCase2D): @parameterized.expand(TEST_CASES) def test_correct_results(self, _, keys, mean, std): - gaussian_fn = RandGaussianNoised(keys=keys, prob=1.0, mean=mean, std=std) - gaussian_fn.set_random_state(seed) - noised = gaussian_fn({"img": self.imt}) - np.random.seed(seed) - np.random.random() - expected = self.imt + np.random.normal(mean, np.random.uniform(0, std), size=self.imt.shape) - np.testing.assert_allclose(expected, noised["img"], atol=1e-5, rtol=1e-5) + test_numpy_or_torch(keys, mean, std, self.imt) if __name__ == "__main__": From 84f816078429509f71fdfb35fb3618c95c9d7586 Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Mon, 1 Feb 2021 09:56:35 +0000 Subject: [PATCH 2/6] update key names Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> --- tests/test_rand_gaussian_noised.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_rand_gaussian_noised.py b/tests/test_rand_gaussian_noised.py index 3162706b6b..c9b310e5d9 100644 --- a/tests/test_rand_gaussian_noised.py +++ b/tests/test_rand_gaussian_noised.py @@ -17,8 +17,8 @@ from monai.transforms import RandGaussianNoised from tests.utils import NumpyImageTestCase2D, TorchImageTestCase2D -TEST_CASE_0 = ["test_zero_mean", ["img", "im2"], 0, 0.1] -TEST_CASE_1 = ["test_non_zero_mean", ["img"], 1, 0.5] +TEST_CASE_0 = ["test_zero_mean", ["img1", "img2"], 0, 0.1] +TEST_CASE_1 = ["test_non_zero_mean", ["img1", "img2"], 1, 0.5] TEST_CASES = [TEST_CASE_0, TEST_CASE_1] seed = 0 From e620feeb29acc64b0b9d38493991f0c8e53e165c Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Mon, 1 Feb 2021 10:02:38 +0000 Subject: [PATCH 3/6] clear list of noise before randomising Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> --- monai/transforms/intensity/dictionary.py | 3 ++- tests/test_rand_gaussian_noised.py | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py index cb1b6133aa..b5d8b14c56 100644 --- a/monai/transforms/intensity/dictionary.py +++ b/monai/transforms/intensity/dictionary.py @@ -117,6 +117,7 @@ def __init__( def randomize(self, im_shape: Sequence[int]) -> None: self._do_transform = self.R.random() < self.prob + self._noise.clear() for m in self.mean: self._noise.append(self.R.normal(m, self.R.uniform(0, self.std), size=im_shape)) @@ -125,7 +126,7 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.nda image_shape = d[self.keys[0]].shape # image shape from the first data key self.randomize(image_shape) - if not self._noise: + if len(self._noise) != len(self.keys): raise AssertionError if not self._do_transform: return d diff --git a/tests/test_rand_gaussian_noised.py b/tests/test_rand_gaussian_noised.py index c9b310e5d9..442a85ca77 100644 --- a/tests/test_rand_gaussian_noised.py +++ b/tests/test_rand_gaussian_noised.py @@ -23,6 +23,7 @@ seed = 0 + def test_numpy_or_torch(keys, mean, std, imt): gaussian_fn = RandGaussianNoised(keys=keys, prob=1.0, mean=mean, std=std) gaussian_fn.set_random_state(seed) @@ -33,6 +34,7 @@ def test_numpy_or_torch(keys, mean, std, imt): expected = imt + np.random.normal(mean, np.random.uniform(0, std), size=imt.shape) np.testing.assert_allclose(expected, noised[k], atol=1e-5, rtol=1e-5) + # Test with numpy class TestRandGaussianNoisedNumpy(NumpyImageTestCase2D): @parameterized.expand(TEST_CASES) From 0e9836444ae910d61f0a9903eec4dd69c01fe65e Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Mon, 1 Feb 2021 10:13:48 +0000 Subject: [PATCH 4/6] add type Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> --- monai/transforms/intensity/dictionary.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py index b5d8b14c56..9a92e9e3de 100644 --- a/monai/transforms/intensity/dictionary.py +++ b/monai/transforms/intensity/dictionary.py @@ -16,7 +16,7 @@ """ from collections.abc import Iterable -from typing import Any, Dict, Hashable, Mapping, Optional, Sequence, Tuple, Union +from typing import Any, Dict, Hashable, List, Mapping, Optional, Sequence, Tuple, Union import numpy as np import torch @@ -113,7 +113,7 @@ def __init__( self.mean = ensure_tuple_size(mean, len(self.keys)) self.std = std self._do_transform = False - self._noise: Sequence[np.ndarray] = [] + self._noise: List[np.ndarray] = [] def randomize(self, im_shape: Sequence[int]) -> None: self._do_transform = self.R.random() < self.prob From 9af19287a4a6504c24ae9ac906d694c1ea9f93c0 Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Mon, 1 Feb 2021 10:59:07 +0000 Subject: [PATCH 5/6] bug fix Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> --- monai/transforms/intensity/dictionary.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py index 9a92e9e3de..a978a39383 100644 --- a/monai/transforms/intensity/dictionary.py +++ b/monai/transforms/intensity/dictionary.py @@ -110,7 +110,7 @@ def __init__( ) -> None: super().__init__(keys) self.prob = prob - self.mean = ensure_tuple_size(mean, len(self.keys)) + self.mean = ensure_tuple_size(mean, len(self.keys), mean) self.std = std self._do_transform = False self._noise: List[np.ndarray] = [] @@ -130,9 +130,9 @@ def __call__(self, data: Mapping[Hashable, np.ndarray]) -> Dict[Hashable, np.nda raise AssertionError if not self._do_transform: return d - for i, key in enumerate(self.keys): + for noise, key in zip(self._noise, self.keys): dtype = dtype_torch_to_numpy(d[key].dtype) if isinstance(d[key], torch.Tensor) else d[key].dtype - d[key] = d[key] + self._noise[i].astype(dtype) + d[key] = d[key] + noise.astype(dtype) return d From 7b0b7f32ac7fdd9365ac0680678a9eff41a02f01 Mon Sep 17 00:00:00 2001 From: Richard Brown <33289025+rijobro@users.noreply.github.com> Date: Tue, 2 Feb 2021 09:41:24 +0000 Subject: [PATCH 6/6] use ensure_tuple_rep Signed-off-by: Richard Brown <33289025+rijobro@users.noreply.github.com> --- monai/transforms/intensity/dictionary.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/monai/transforms/intensity/dictionary.py b/monai/transforms/intensity/dictionary.py index 76a91a8b62..1c9b31c120 100644 --- a/monai/transforms/intensity/dictionary.py +++ b/monai/transforms/intensity/dictionary.py @@ -35,7 +35,7 @@ ShiftIntensity, ThresholdIntensity, ) -from monai.utils import dtype_torch_to_numpy, ensure_tuple_size +from monai.utils import dtype_torch_to_numpy, ensure_tuple_rep, ensure_tuple_size __all__ = [ "RandGaussianNoised", @@ -110,7 +110,7 @@ def __init__( ) -> None: super().__init__(keys) self.prob = prob - self.mean = ensure_tuple_size(mean, len(self.keys), mean) + self.mean = ensure_tuple_rep(mean, len(self.keys)) self.std = std self._do_transform = False self._noise: List[np.ndarray] = []