From b1e0597ee15dc35ad9a75cabd8ef4b1ee699945d Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Fri, 22 Jan 2016 13:43:47 +0530 Subject: [PATCH 1/4] Raise warning for 3D images in denoise_bilateral --- skimage/restoration/_denoise.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/skimage/restoration/_denoise.py b/skimage/restoration/_denoise.py index 62985cc7..754fcf97 100644 --- a/skimage/restoration/_denoise.py +++ b/skimage/restoration/_denoise.py @@ -3,10 +3,11 @@ import numpy as np from .. import img_as_float from ..restoration._denoise_cy import _denoise_bilateral, _denoise_tv_bregman from .._shared.utils import _mode_deprecations +import warnings def denoise_bilateral(image, win_size=5, sigma_range=None, sigma_spatial=1, - bins=10000, mode='constant', cval=0): + bins=10000, mode='constant', cval=0, multichannel=False): """Denoise image using bilateral filter. This is an edge-preserving and noise reducing denoising filter. It averages @@ -45,6 +46,9 @@ def denoise_bilateral(image, win_size=5, sigma_range=None, sigma_spatial=1, cval : string Used in conjunction with mode 'constant', the value outside the image boundaries. + multichannel : bool, default False + Whether the last axis of the image is to be interpreted as multiple + channels or another spatial dimension. Returns ------- @@ -64,6 +68,18 @@ def denoise_bilateral(image, win_size=5, sigma_range=None, sigma_spatial=1, >>> noisy = np.clip(noisy, 0, 1) >>> denoised = denoise_bilateral(noisy, sigma_range=0.05, sigma_spatial=15) """ + if multichannel: + if image.shape[2] not in (3, 4): + msg = "Input image must be grayscale, RGB, or RGBA; but has " \ + "a shape {0}." + warnings.warn(msg.format(image.shape)) + else: + if image.ndim > 2: + msg = "Input image must be grayscale, RGB, or RGBA; but has " \ + "a shape {0}." + raise TypeError(msg.format(image.shape)) + + mode = _mode_deprecations(mode) return _denoise_bilateral(image, win_size, sigma_range, sigma_spatial, bins, mode, cval) From 63b893d4c683c7efc29b7af0029055c992eeadee Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Sun, 24 Jan 2016 23:10:51 +0530 Subject: [PATCH 2/4] Fix test and doctest for multichannel kwarg in denoise_bilateral --- doc/examples/filters/plot_denoise.py | 4 ++-- skimage/restoration/_denoise.py | 26 ++++++++++++++++------- skimage/restoration/tests/test_denoise.py | 8 +++++-- 3 files changed, 26 insertions(+), 12 deletions(-) diff --git a/doc/examples/filters/plot_denoise.py b/doc/examples/filters/plot_denoise.py index e66d2478..be9314ee 100644 --- a/doc/examples/filters/plot_denoise.py +++ b/doc/examples/filters/plot_denoise.py @@ -49,14 +49,14 @@ ax[0, 0].set_title('noisy') ax[0, 1].imshow(denoise_tv_chambolle(noisy, weight=0.1, multichannel=True)) ax[0, 1].axis('off') ax[0, 1].set_title('TV') -ax[0, 2].imshow(denoise_bilateral(noisy, sigma_range=0.05, sigma_spatial=15)) +ax[0, 2].imshow(denoise_bilateral(noisy, sigma_range=0.05, sigma_spatial=15, multichannel=True)) ax[0, 2].axis('off') ax[0, 2].set_title('Bilateral') ax[1, 0].imshow(denoise_tv_chambolle(noisy, weight=0.2, multichannel=True)) ax[1, 0].axis('off') ax[1, 0].set_title('(more) TV') -ax[1, 1].imshow(denoise_bilateral(noisy, sigma_range=0.1, sigma_spatial=15)) +ax[1, 1].imshow(denoise_bilateral(noisy, sigma_range=0.1, sigma_spatial=15, multichannel=True)) ax[1, 1].axis('off') ax[1, 1].set_title('(more) Bilateral') ax[1, 2].imshow(astro) diff --git a/skimage/restoration/_denoise.py b/skimage/restoration/_denoise.py index 754fcf97..7c172744 100644 --- a/skimage/restoration/_denoise.py +++ b/skimage/restoration/_denoise.py @@ -46,7 +46,7 @@ def denoise_bilateral(image, win_size=5, sigma_range=None, sigma_spatial=1, cval : string Used in conjunction with mode 'constant', the value outside the image boundaries. - multichannel : bool, default False + multichannel : bool Whether the last axis of the image is to be interpreted as multiple channels or another spatial dimension. @@ -66,17 +66,27 @@ def denoise_bilateral(image, win_size=5, sigma_range=None, sigma_spatial=1, >>> astro = astro[220:300, 220:320] >>> noisy = astro + 0.6 * astro.std() * np.random.random(astro.shape) >>> noisy = np.clip(noisy, 0, 1) - >>> denoised = denoise_bilateral(noisy, sigma_range=0.05, sigma_spatial=15) + >>> denoised = denoise_bilateral(noisy, sigma_range=0.05, + ... sigma_spatial=15, multichannel=True) """ if multichannel: - if image.shape[2] not in (3, 4): - msg = "Input image must be grayscale, RGB, or RGBA; but has " \ - "a shape {0}." - warnings.warn(msg.format(image.shape)) + if image.ndim != 3: + raise ValueError("Use ``multichannel=False`` for 2D grayscale images. " + "The last axis of the input image must be multiple " + "color channels not another spatial dimension.") + elif image.shape[2] not in (3, 4): + if image.shape[2] > 4: + warnings.warn("The last axis of the input image is interpreted " + "as channels. Input image with shape {0} has {1} " + "channels in last axis. ``denoise_bilateral`` is " + "implemented for 2D grayscale and color images " + "only.".format(image.shape, image.shape[2])) + else: + msg = "Input image must be grayscale, RGB, or RGBA; but has shape {0}." + warnings.warn(msg.format(image.shape)) else: if image.ndim > 2: - msg = "Input image must be grayscale, RGB, or RGBA; but has " \ - "a shape {0}." + msg = "Input image must be grayscale, RGB, or RGBA; but has shape {0}." raise TypeError(msg.format(image.shape)) diff --git a/skimage/restoration/tests/test_denoise.py b/skimage/restoration/tests/test_denoise.py index 58f0a261..8f9b8649 100644 --- a/skimage/restoration/tests/test_denoise.py +++ b/skimage/restoration/tests/test_denoise.py @@ -175,15 +175,19 @@ def test_denoise_bilateral_3d(): img = np.clip(img, 0, 1) out1 = restoration.denoise_bilateral(img, sigma_range=0.1, - sigma_spatial=20) + sigma_spatial=20, multichannel=True) out2 = restoration.denoise_bilateral(img, sigma_range=0.2, - sigma_spatial=30) + sigma_spatial=30, multichannel=True) # make sure noise is reduced in the checkerboard cells assert img[30:45, 5:15].std() > out1[30:45, 5:15].std() assert out1[30:45, 5:15].std() > out2[30:45, 5:15].std() +def test_denoise_bilateral_3d_grayscale(): + img = np.ones((500, 500, 3)) + assert_raises(TypeError, restoration.denoise_bilateral, img) + def test_denoise_bilateral_nan(): img = np.NaN + np.empty((50, 50)) out = restoration.denoise_bilateral(img) From b40d0285504a08a022b698266d071883bff4a880 Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Fri, 29 Jan 2016 14:14:41 +0530 Subject: [PATCH 3/4] Add tests for warnings in denoise_bilateral --- doc/examples/filters/plot_denoise.py | 6 +++-- skimage/restoration/_denoise.py | 9 ++++--- skimage/restoration/tests/test_denoise.py | 32 ++++++++++++++++++----- 3 files changed, 36 insertions(+), 11 deletions(-) diff --git a/doc/examples/filters/plot_denoise.py b/doc/examples/filters/plot_denoise.py index be9314ee..9d3d0485 100644 --- a/doc/examples/filters/plot_denoise.py +++ b/doc/examples/filters/plot_denoise.py @@ -49,14 +49,16 @@ ax[0, 0].set_title('noisy') ax[0, 1].imshow(denoise_tv_chambolle(noisy, weight=0.1, multichannel=True)) ax[0, 1].axis('off') ax[0, 1].set_title('TV') -ax[0, 2].imshow(denoise_bilateral(noisy, sigma_range=0.05, sigma_spatial=15, multichannel=True)) +ax[0, 2].imshow(denoise_bilateral(noisy, sigma_range=0.05, sigma_spatial=15, + multichannel=True)) ax[0, 2].axis('off') ax[0, 2].set_title('Bilateral') ax[1, 0].imshow(denoise_tv_chambolle(noisy, weight=0.2, multichannel=True)) ax[1, 0].axis('off') ax[1, 0].set_title('(more) TV') -ax[1, 1].imshow(denoise_bilateral(noisy, sigma_range=0.1, sigma_spatial=15, multichannel=True)) +ax[1, 1].imshow(denoise_bilateral(noisy, sigma_range=0.1, sigma_spatial=15, + multichannel=True)) ax[1, 1].axis('off') ax[1, 1].set_title('(more) Bilateral') ax[1, 2].imshow(astro) diff --git a/skimage/restoration/_denoise.py b/skimage/restoration/_denoise.py index 7c172744..b21501c1 100644 --- a/skimage/restoration/_denoise.py +++ b/skimage/restoration/_denoise.py @@ -7,7 +7,7 @@ import warnings def denoise_bilateral(image, win_size=5, sigma_range=None, sigma_spatial=1, - bins=10000, mode='constant', cval=0, multichannel=False): + bins=10000, mode='constant', cval=0, multichannel=True): """Denoise image using bilateral filter. This is an edge-preserving and noise reducing denoising filter. It averages @@ -86,8 +86,11 @@ def denoise_bilateral(image, win_size=5, sigma_range=None, sigma_spatial=1, warnings.warn(msg.format(image.shape)) else: if image.ndim > 2: - msg = "Input image must be grayscale, RGB, or RGBA; but has shape {0}." - raise TypeError(msg.format(image.shape)) + raise TypeError("Bilateral filter is not implemented for " + "grayscale images of 3 or more dimensions, " + "but input image has {0} dimension. Use " + "``multichannel=True`` for 2-D RGB " + "images.".format(image.shape)) mode = _mode_deprecations(mode) diff --git a/skimage/restoration/tests/test_denoise.py b/skimage/restoration/tests/test_denoise.py index 8f9b8649..7c6f0c57 100644 --- a/skimage/restoration/tests/test_denoise.py +++ b/skimage/restoration/tests/test_denoise.py @@ -2,6 +2,7 @@ import numpy as np from numpy.testing import run_module_suite, assert_raises, assert_equal from skimage import restoration, data, color, img_as_float, measure +from skimage._shared._warnings import expected_warnings np.random.seed(1234) @@ -159,16 +160,16 @@ def test_denoise_bilateral_2d(): img = np.clip(img, 0, 1) out1 = restoration.denoise_bilateral(img, sigma_range=0.1, - sigma_spatial=20) + sigma_spatial=20, multichannel=False) out2 = restoration.denoise_bilateral(img, sigma_range=0.2, - sigma_spatial=30) + sigma_spatial=30, multichannel=False) # make sure noise is reduced in the checkerboard cells assert img[30:45, 5:15].std() > out1[30:45, 5:15].std() assert out1[30:45, 5:15].std() > out2[30:45, 5:15].std() -def test_denoise_bilateral_3d(): +def test_denoise_bilateral_color(): img = checkerboard.copy() # add some random noise img += 0.5 * img.std() * np.random.rand(*img.shape) @@ -185,12 +186,31 @@ def test_denoise_bilateral_3d(): def test_denoise_bilateral_3d_grayscale(): - img = np.ones((500, 500, 3)) - assert_raises(TypeError, restoration.denoise_bilateral, img) + img = np.ones((50, 50, 3)) + assert_raises(TypeError, restoration.denoise_bilateral, img, \ + multichannel=False) + + +def test_denoise_bilateral_3d_multichannel(): + img = np.ones((50, 50, 50)) + with expected_warnings(["grayscale"]): + result = restoration.denoise_bilateral(img, multichannel=True) + + expected = np.empty_like(img) + expected.fill(np.nan) + + assert_equal(result, expected) + + +def test_denoise_bilateral_multidimensional(): + img = np.ones((10, 10, 10, 10)) + assert_raises(ValueError, restoration.denoise_bilateral, img, + multichannel=True) + def test_denoise_bilateral_nan(): img = np.NaN + np.empty((50, 50)) - out = restoration.denoise_bilateral(img) + out = restoration.denoise_bilateral(img, multichannel=False) assert_equal(img, out) From 7014d04327ec62be6d74f7d2581b1d091040ac45 Mon Sep 17 00:00:00 2001 From: Himanshu Mishra Date: Fri, 5 Feb 2016 08:11:45 +0530 Subject: [PATCH 4/4] Remove useless multichannel=True kwarg from tests --- doc/examples/filters/plot_denoise.py | 6 ++--- skimage/restoration/_denoise.py | 27 ++++++++++++++--------- skimage/restoration/tests/test_denoise.py | 11 +++++---- 3 files changed, 24 insertions(+), 20 deletions(-) diff --git a/doc/examples/filters/plot_denoise.py b/doc/examples/filters/plot_denoise.py index 9d3d0485..e66d2478 100644 --- a/doc/examples/filters/plot_denoise.py +++ b/doc/examples/filters/plot_denoise.py @@ -49,16 +49,14 @@ ax[0, 0].set_title('noisy') ax[0, 1].imshow(denoise_tv_chambolle(noisy, weight=0.1, multichannel=True)) ax[0, 1].axis('off') ax[0, 1].set_title('TV') -ax[0, 2].imshow(denoise_bilateral(noisy, sigma_range=0.05, sigma_spatial=15, - multichannel=True)) +ax[0, 2].imshow(denoise_bilateral(noisy, sigma_range=0.05, sigma_spatial=15)) ax[0, 2].axis('off') ax[0, 2].set_title('Bilateral') ax[1, 0].imshow(denoise_tv_chambolle(noisy, weight=0.2, multichannel=True)) ax[1, 0].axis('off') ax[1, 0].set_title('(more) TV') -ax[1, 1].imshow(denoise_bilateral(noisy, sigma_range=0.1, sigma_spatial=15, - multichannel=True)) +ax[1, 1].imshow(denoise_bilateral(noisy, sigma_range=0.1, sigma_spatial=15)) ax[1, 1].axis('off') ax[1, 1].set_title('(more) Bilateral') ax[1, 2].imshow(astro) diff --git a/skimage/restoration/_denoise.py b/skimage/restoration/_denoise.py index b21501c1..ed0fea81 100644 --- a/skimage/restoration/_denoise.py +++ b/skimage/restoration/_denoise.py @@ -66,14 +66,21 @@ def denoise_bilateral(image, win_size=5, sigma_range=None, sigma_spatial=1, >>> astro = astro[220:300, 220:320] >>> noisy = astro + 0.6 * astro.std() * np.random.random(astro.shape) >>> noisy = np.clip(noisy, 0, 1) - >>> denoised = denoise_bilateral(noisy, sigma_range=0.05, - ... sigma_spatial=15, multichannel=True) + >>> denoised = denoise_bilateral(noisy, sigma_range=0.05, sigma_spatial=15) """ if multichannel: if image.ndim != 3: - raise ValueError("Use ``multichannel=False`` for 2D grayscale images. " - "The last axis of the input image must be multiple " - "color channels not another spatial dimension.") + if image.ndim == 2: + raise ValueError("Use ``multichannel=False`` for 2D grayscale " + "images. The last axis of the input image " + "must be multiple color channels not another " + "spatial dimension.") + else: + raise ValueError("Bilateral filter is only implemented for " + "2D grayscale images (image.ndim == 2) and " + "2D multichannel (image.ndim == 3) images, " + "but the input image has {0} dimensions. " + "".format(image.ndim)) elif image.shape[2] not in (3, 4): if image.shape[2] > 4: warnings.warn("The last axis of the input image is interpreted " @@ -86,11 +93,11 @@ def denoise_bilateral(image, win_size=5, sigma_range=None, sigma_spatial=1, warnings.warn(msg.format(image.shape)) else: if image.ndim > 2: - raise TypeError("Bilateral filter is not implemented for " - "grayscale images of 3 or more dimensions, " - "but input image has {0} dimension. Use " - "``multichannel=True`` for 2-D RGB " - "images.".format(image.shape)) + raise ValueError("Bilateral filter is not implemented for " + "grayscale images of 3 or more dimensions, " + "but input image has {0} dimension. Use " + "``multichannel=True`` for 2-D RGB " + "images.".format(image.shape)) mode = _mode_deprecations(mode) diff --git a/skimage/restoration/tests/test_denoise.py b/skimage/restoration/tests/test_denoise.py index 7c6f0c57..f0537f10 100644 --- a/skimage/restoration/tests/test_denoise.py +++ b/skimage/restoration/tests/test_denoise.py @@ -175,10 +175,8 @@ def test_denoise_bilateral_color(): img += 0.5 * img.std() * np.random.rand(*img.shape) img = np.clip(img, 0, 1) - out1 = restoration.denoise_bilateral(img, sigma_range=0.1, - sigma_spatial=20, multichannel=True) - out2 = restoration.denoise_bilateral(img, sigma_range=0.2, - sigma_spatial=30, multichannel=True) + out1 = restoration.denoise_bilateral(img, sigma_range=0.1, sigma_spatial=20) + out2 = restoration.denoise_bilateral(img, sigma_range=0.2, sigma_spatial=30) # make sure noise is reduced in the checkerboard cells assert img[30:45, 5:15].std() > out1[30:45, 5:15].std() @@ -187,14 +185,14 @@ def test_denoise_bilateral_color(): def test_denoise_bilateral_3d_grayscale(): img = np.ones((50, 50, 3)) - assert_raises(TypeError, restoration.denoise_bilateral, img, \ + assert_raises(ValueError, restoration.denoise_bilateral, img, multichannel=False) def test_denoise_bilateral_3d_multichannel(): img = np.ones((50, 50, 50)) with expected_warnings(["grayscale"]): - result = restoration.denoise_bilateral(img, multichannel=True) + result = restoration.denoise_bilateral(img) expected = np.empty_like(img) expected.fill(np.nan) @@ -204,6 +202,7 @@ def test_denoise_bilateral_3d_multichannel(): def test_denoise_bilateral_multidimensional(): img = np.ones((10, 10, 10, 10)) + assert_raises(ValueError, restoration.denoise_bilateral, img) assert_raises(ValueError, restoration.denoise_bilateral, img, multichannel=True)