From db7e9c2b4ab6f7f9314a112107e1a5669392670d Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Tue, 26 Jul 2016 19:25:20 +1000 Subject: [PATCH 1/6] Bug fix: correct pixel selection for s&p noise --- skimage/util/noise.py | 20 ++++++++------------ 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/skimage/util/noise.py b/skimage/util/noise.py index ff20084a..9ee77061 100644 --- a/skimage/util/noise.py +++ b/skimage/util/noise.py @@ -166,23 +166,19 @@ def random_noise(image, mode='gaussian', seed=None, clip=True, **kwargs): amount=kwargs['amount'], salt_vs_pepper=0.) elif mode == 's&p': - # This mode makes no effort to avoid repeat sampling. Thus, the - # exact number of replaced pixels is only approximate. out = image.copy() # Salt mode - num_salt = np.ceil( - kwargs['amount'] * image.size * kwargs['salt_vs_pepper']) - coords = [np.random.randint(0, i - 1, int(num_salt)) - for i in image.shape] - out[coords] = 1 + p_salt = kwargs['amount'] * kwargs['salt_vs_pepper'] + mask = np.random.choice([True, False], size=image.shape, + p=[p_salt, 1 - p_salt]) + out[mask] = 1 # Pepper mode - num_pepper = np.ceil( - kwargs['amount'] * image.size * (1. - kwargs['salt_vs_pepper'])) - coords = [np.random.randint(0, i - 1, int(num_pepper)) - for i in image.shape] - out[coords] = low_clip + p_pepper = kwargs['amount'] * (1 - kwargs['salt_vs_pepper']) + mask = np.random.choice([True, False], size=image.shape, + p=[p_pepper, 1 - p_pepper]) + out[mask] = low_clip elif mode == 'speckle': noise = np.random.normal(kwargs['mean'], kwargs['var'] ** 0.5, From cc843d6f14cd36561f8e3fb54d0577e2008c26a9 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Tue, 26 Jul 2016 19:36:18 +1000 Subject: [PATCH 2/6] Add regression tests for S&P noise --- skimage/util/tests/test_random_noise.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/skimage/util/tests/test_random_noise.py b/skimage/util/tests/test_random_noise.py index 39477cb0..112ebf77 100644 --- a/skimage/util/tests/test_random_noise.py +++ b/skimage/util/tests/test_random_noise.py @@ -26,6 +26,19 @@ def test_salt(): assert 0.11 < proportion <= 0.15 +def test_salt_p1(): + image = np.random.rand(2, 3) + noisy = random_noise(image, mode='salt', amount=1) + assert_array_equal(noisy, [[1, 1, 1], [1, 1, 1]]) + + +def test_singleton_dim(): + """Ensure images where size of a given dimension is 1 work correctly.""" + image = np.random.rand(1, 20) + noisy = random_noise(image, mode='salt', amount=0.1, seed=42) + assert np.sum(noisy == 1) == 2 + + def test_pepper(): seed = 42 cam = img_as_float(camera()) From 2bac24fdf45b26cf69447ea094fb7e3a0b653702 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Wed, 27 Jul 2016 00:34:54 +1000 Subject: [PATCH 3/6] Ensure probability of flipping pixels is correct --- skimage/util/noise.py | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/skimage/util/noise.py b/skimage/util/noise.py index 9ee77061..5678e33a 100644 --- a/skimage/util/noise.py +++ b/skimage/util/noise.py @@ -169,16 +169,15 @@ def random_noise(image, mode='gaussian', seed=None, clip=True, **kwargs): out = image.copy() # Salt mode - p_salt = kwargs['amount'] * kwargs['salt_vs_pepper'] - mask = np.random.choice([True, False], size=image.shape, - p=[p_salt, 1 - p_salt]) - out[mask] = 1 - - # Pepper mode - p_pepper = kwargs['amount'] * (1 - kwargs['salt_vs_pepper']) - mask = np.random.choice([True, False], size=image.shape, - p=[p_pepper, 1 - p_pepper]) - out[mask] = low_clip + p = kwargs['amount'] + q = kwargs['salt_vs_pepper'] + flipped = np.random.choice([True, False], size=image.shape, + p=[p, 1 - p]) + salted = np.random.choice([True, False], size=image.shape, + p=[q, 1 - q]) + peppered = ~salted + out[flipped & salted] = 1 + out[flipped & peppered] = low_clip elif mode == 'speckle': noise = np.random.normal(kwargs['mean'], kwargs['var'] ** 0.5, From 18f661902c6cbd8b6cfe7e40b52c37ba0b3898b2 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Wed, 27 Jul 2016 01:01:24 +1000 Subject: [PATCH 4/6] Update test tolerance to reflect changed probabilities --- skimage/util/tests/test_random_noise.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/util/tests/test_random_noise.py b/skimage/util/tests/test_random_noise.py index 112ebf77..ed77f4df 100644 --- a/skimage/util/tests/test_random_noise.py +++ b/skimage/util/tests/test_random_noise.py @@ -82,7 +82,7 @@ def test_salt_and_pepper(): assert 0.11 < proportion <= 0.18 # Verify the relative amount of salt vs. pepper is close to expected - assert 0.18 < saltmask.sum() / float(peppermask.sum()) < 0.32 + assert 0.18 < saltmask.sum() / float(peppermask.sum()) < 0.33 def test_gaussian(): From 2bb0def97599f388c581e66e98d6e9a4712e8207 Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Wed, 27 Jul 2016 09:14:53 +1000 Subject: [PATCH 5/6] Remove obsolete comment --- skimage/util/noise.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/skimage/util/noise.py b/skimage/util/noise.py index 5678e33a..b6156a1c 100644 --- a/skimage/util/noise.py +++ b/skimage/util/noise.py @@ -167,8 +167,6 @@ def random_noise(image, mode='gaussian', seed=None, clip=True, **kwargs): elif mode == 's&p': out = image.copy() - - # Salt mode p = kwargs['amount'] q = kwargs['salt_vs_pepper'] flipped = np.random.choice([True, False], size=image.shape, From b02b2b16cd0f9c72a8955671c3bcbb5afbe703ab Mon Sep 17 00:00:00 2001 From: Juan Nunez-Iglesias Date: Thu, 28 Jul 2016 09:29:24 +1000 Subject: [PATCH 6/6] Clarify that pepper noise can be signed --- skimage/util/noise.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/skimage/util/noise.py b/skimage/util/noise.py index b6156a1c..6db8183e 100644 --- a/skimage/util/noise.py +++ b/skimage/util/noise.py @@ -21,8 +21,11 @@ def random_noise(image, mode='gaussian', seed=None, clip=True, **kwargs): local variance at each point of `image` - 'poisson' Poisson-distributed noise generated from the data. - 'salt' Replaces random pixels with 1. - - 'pepper' Replaces random pixels with 0. - - 's&p' Replaces random pixels with 0 or 1. + - 'pepper' Replaces random pixels with 0 (for unsigned images) or + -1 (for signed images). + - 's&p' Replaces random pixels with either 1 or `low_val`, where + `low_val` is 0 for unsigned images or -1 for signed + images. - 'speckle' Multiplicative noise using out = image + n*image, where n is uniform noise with specified mean & variance. seed : int