From 32f39eecbbc82380a0a0342fd56f28daf7e6ee29 Mon Sep 17 00:00:00 2001 From: "Josh Warner (Mac)" Date: Wed, 3 Jul 2013 23:54:26 -0500 Subject: [PATCH] ENH: Improve random_noise with better param names & docfixes --- skimage/util/noise.py | 56 +++++++++++++++---------- skimage/util/tests/test_random_noise.py | 22 ++++++---- 2 files changed, 47 insertions(+), 31 deletions(-) diff --git a/skimage/util/noise.py b/skimage/util/noise.py index bf1d412d..71b69aad 100644 --- a/skimage/util/noise.py +++ b/skimage/util/noise.py @@ -24,18 +24,20 @@ def random_noise(image, mode='gaussian', seed=None, **kwargs): 'speckle' Multiplicative noise using out = image + n*image, where n is uniform noise with specified mean & variance. seed : int - If provided, this will set the random seed before generating noise. - m : float + If provided, this will set the random seed before generating noise, + for valid pseudo-random comparisons. + mean : float Mean of random distribution. Used in 'gaussian' and 'speckle'. - v : float + Default : 0. + var : float Variance of random distribution. Used in 'gaussian' and 'speckle'. - Note: variance = (standard deviation) ** 2 - d : float + Note: variance = (standard deviation) ** 2. Default : 0.01 + prop_replace : float Proportion of image pixels to replace with noise on range [0, 1]. - Used in 'salt', 'pepper', and 'salt & pepper'. - p : float + Used in 'salt', 'pepper', and 'salt & pepper'. Default : 0.05 + prop_salt : float Proportion of salt vs. pepper noise for 's&p' on range [0, 1]. - Higher values represent more salt. + Higher values represent more salt. Default : 0.5 (equal amounts) Returns ------- @@ -57,15 +59,15 @@ def random_noise(image, mode='gaussian', seed=None, **kwargs): 'speckle': 'gaussian_values'} kwdefaults = { - 'm': 0., - 'v': 0.01, - 'd': 0.05, - 'p': 0.5} + 'mean': 0., + 'var': 0.01, + 'prop_replace': 0.05, + 'prop_salt': 0.5} allowedkwargs = { - 'gaussian_values': ['m', 'v'], - 'sp_values': ['d'], - 's&p_values': ['d', 'p']} + 'gaussian_values': ['mean', 'var'], + 'sp_values': ['prop_replace'], + 's&p_values': ['prop_replace', 'prop_salt']} for key in kwargs: if key not in allowedkwargs[allowedtypes[mode]]: @@ -77,7 +79,8 @@ def random_noise(image, mode='gaussian', seed=None, **kwargs): kwargs.setdefault(kw, kwdefaults[kw]) if mode == 'gaussian': - noise = np.random.normal(kwargs['m'], kwargs['v'] ** 0.5, image.shape) + noise = np.random.normal(kwargs['mean'], kwargs['var'] ** 0.5, + image.shape) out = np.clip(image + noise, 0., 1.) elif mode == 'poisson': @@ -91,29 +94,36 @@ def random_noise(image, mode='gaussian', seed=None, **kwargs): elif mode == 'salt': # Re-call function with mode='s&p' and p=1 (all salt noise) - out = random_noise(image, mode='s&p', seed=seed, d=kwargs['d'], p=1) + out = random_noise(image, mode='s&p', seed=seed, + prop_replace=kwargs['prop_replace'], prop_salt=1.) elif mode == 'pepper': # Re-call function with mode='s&p' and p=1 (all pepper noise) - out = random_noise(image, mode='s&p', seed=seed, d=kwargs['d'], p=0) + out = random_noise(image, mode='s&p', seed=seed, + prop_replace=kwargs['prop_replace'], prop_salt=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['d'] * image.size * kwargs['p']) - coords = [np.random.randint(0, i - 1, num_salt) + num_salt = np.ceil( + kwargs['prop_replace'] * image.size * kwargs['prop_salt']) + coords = [np.random.randint(0, i - 1, int(num_salt)) for i in image.shape] out[coords] = 1 # Pepper mode - num_pepper = np.ceil(kwargs['d'] * image.size * (1. - kwargs['p'])) - coords = [np.random.randint(0, i - 1, num_pepper) + num_pepper = np.ceil( + kwargs['prop_replace'] * image.size * (1. - kwargs['prop_salt'])) + coords = [np.random.randint(0, i - 1, int(num_pepper)) for i in image.shape] out[coords] = 0 elif mode == 'speckle': - noise = np.random.normal(kwargs['m'], kwargs['v'] ** 0.5, image.shape) + noise = np.random.normal(kwargs['mean'], kwargs['var'] ** 0.5, + image.shape) out = np.clip(image + image * noise, 0., 1.) return out diff --git a/skimage/util/tests/test_random_noise.py b/skimage/util/tests/test_random_noise.py index 98b78117..6b6ba5c4 100644 --- a/skimage/util/tests/test_random_noise.py +++ b/skimage/util/tests/test_random_noise.py @@ -1,4 +1,4 @@ -from numpy.testing import assert_array_equal, assert_allclose +from numpy.testing import assert_array_equal, assert_allclose, assert_raises import numpy as np from skimage.data import camera @@ -15,7 +15,7 @@ def test_set_seed(): def test_salt(): seed = 42 cam = img_as_float(camera()) - cam_noisy = random_noise(cam, seed=seed, mode='salt', d=0.15) + cam_noisy = random_noise(cam, seed=seed, mode='salt', prop_replace=0.15) saltmask = cam != cam_noisy # Ensure all changes are to 1.0 @@ -29,7 +29,7 @@ def test_salt(): def test_pepper(): seed = 42 cam = img_as_float(camera()) - cam_noisy = random_noise(cam, seed=seed, mode='pepper', d=0.15) + cam_noisy = random_noise(cam, seed=seed, mode='pepper', prop_replace=0.15) peppermask = cam != cam_noisy # Ensure all changes are to 1.0 @@ -43,7 +43,8 @@ def test_pepper(): def test_salt_and_pepper(): seed = 42 cam = img_as_float(camera()) - cam_noisy = random_noise(cam, seed=seed, mode='s&p', d=0.15, p=0.25) + cam_noisy = random_noise(cam, seed=seed, mode='s&p', prop_replace=0.15, + prop_salt=0.25) saltmask = np.logical_and(cam != cam_noisy, cam_noisy == 1.) peppermask = np.logical_and(cam != cam_noisy, cam_noisy == 0.) @@ -63,10 +64,10 @@ def test_salt_and_pepper(): def test_gaussian(): seed = 42 data = np.zeros((128, 128)) + 0.5 - data_gaussian = random_noise(data, seed=seed, v=0.01) + data_gaussian = random_noise(data, seed=seed, var=0.01) assert 0.008 < data_gaussian.var() < 0.012 - data_gaussian = random_noise(data, seed=seed, m=0.3, v=0.015) + data_gaussian = random_noise(data, seed=seed, mean=0.3, var=0.015) assert 0.28 < data_gaussian.mean() - 0.5 < 0.32 assert 0.012 < data_gaussian.var() < 0.018 @@ -78,10 +79,15 @@ def test_speckle(): noise = np.random.normal(0.1, 0.02 ** 0.5, (128, 128)) expected = np.clip(data + data * noise, 0, 1) - data_speckle = random_noise(data, mode='speckle', seed=seed, m=0.1, - v=0.02) + data_speckle = random_noise(data, mode='speckle', seed=seed, mean=0.1, + var=0.02) assert_allclose(expected, data_speckle) +def test_bad_mode(): + data = np.zeros((64, 64)) + assert_raises(KeyError, random_noise, data, 'perlin') + + if __name__ == '__main__': np.testing.run_module_suite()