From a63e3f454633bea824c0c15afc019ee3620c944f Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Wed, 26 Oct 2011 16:22:20 -0400 Subject: [PATCH 1/3] Require median filter radius >= 2 The octagon structuring element used by _ctmf.pyx does not scale correctly for smaller radii. --- skimage/filter/ctmf.py | 3 +++ skimage/filter/tests/test_ctmf.py | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/skimage/filter/ctmf.py b/skimage/filter/ctmf.py index 1f294ee4..38fe32eb 100644 --- a/skimage/filter/ctmf.py +++ b/skimage/filter/ctmf.py @@ -47,6 +47,9 @@ def median_filter(image, mask=None, radius=2, percent=50): if image.ndim != 2: raise TypeError("The input 'image' must be a two dimensional array.") + if radius < 2: + raise ValueError("The input 'radius' must be >= 2.") + if mask is None: mask = np.ones(image.shape, dtype=np.bool) mask = np.ascontiguousarray(mask, dtype=np.bool) diff --git a/skimage/filter/tests/test_ctmf.py b/skimage/filter/tests/test_ctmf.py index a3c23fe4..dfe35f46 100644 --- a/skimage/filter/tests/test_ctmf.py +++ b/skimage/filter/tests/test_ctmf.py @@ -1,4 +1,5 @@ import numpy as np +from nose.tools import raises from skimage.filter import median_filter @@ -110,5 +111,11 @@ def test_default_values(): np.testing.assert_array_equal(result1, result2) +@raises(ValueError) +def test_insufficient_size(): + img = (np.random.random((20, 20)) * 255).astype(np.uint8) + median_filter(img, radius=1) + + if __name__ == "__main__": np.testing.run_module_suite() From c6e854b7c7b17112a1a66f125f9856b8bf3fed96 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Wed, 26 Oct 2011 16:30:07 -0400 Subject: [PATCH 2/3] Switch radius and mask arguments for median_filter --- skimage/filter/ctmf.py | 8 ++++---- skimage/filter/tests/test_ctmf.py | 18 +++++++++--------- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/skimage/filter/ctmf.py b/skimage/filter/ctmf.py index 38fe32eb..2a0f2e1a 100644 --- a/skimage/filter/ctmf.py +++ b/skimage/filter/ctmf.py @@ -16,20 +16,20 @@ from . import _ctmf from rank_order import rank_order -def median_filter(image, mask=None, radius=2, percent=50): +def median_filter(image, radius=2, mask=None, percent=50): '''Masked median filter with octagon shape. Parameters ---------- image : (M,N) ndarray, dtype uint8 Input image. + radius : {int, 1}, optional + The radius of a circle inscribed into the filtering + octagon. Default radius is 1. mask : (M,N) ndarray, dtype uint8, optional A value of 1 indicates a significant pixel, 0 that a pixel is masked. By default, all pixels are considered. - radius : {int, 1}, optional - The radius of a circle inscribed into the filtering - octagon. Default radius is 1. percent : {int, 50}, optional The unmasked pixels within the octagon are sorted, and the value at the `percent`-th index chosen. For example, the diff --git a/skimage/filter/tests/test_ctmf.py b/skimage/filter/tests/test_ctmf.py index dfe35f46..fd820469 100644 --- a/skimage/filter/tests/test_ctmf.py +++ b/skimage/filter/tests/test_ctmf.py @@ -6,7 +6,7 @@ from skimage.filter import median_filter def test_00_00_zeros(): '''The median filter on an array of all zeros should be zero''' - result = median_filter(np.zeros((10, 10)), np.ones((10, 10), bool), 3) + result = median_filter(np.zeros((10, 10)), 3, np.ones((10, 10), bool)) assert np.all(result == 0) @@ -14,14 +14,14 @@ def test_00_01_all_masked(): '''Test a completely masked image Regression test of IMG-1029''' - result = median_filter(np.zeros((10, 10)), np.zeros((10, 10), bool), 3) + result = median_filter(np.zeros((10, 10)), 3, np.zeros((10, 10), bool)) assert (np.all(result == 0)) def test_00_02_all_but_one_masked(): mask = np.zeros((10, 10), bool) mask[5, 5] = True - median_filter(np.zeros((10, 10)), mask, 3) + median_filter(np.zeros((10, 10)), 3, mask) def test_01_01_mask(): @@ -30,7 +30,7 @@ def test_01_01_mask(): img[5, 5] = 1 mask = np.ones((10, 10), bool) mask[5, 5] = False - result = median_filter(img, mask, 3) + result = median_filter(img, 3, mask) assert (np.all(result[mask] == 0)) np.testing.assert_equal(result[5, 5], 1) @@ -39,7 +39,7 @@ def test_02_01_median(): '''A median filter larger than the image = median of image''' np.random.seed(0) img = np.random.uniform(size=(9, 9)) - result = median_filter(img, np.ones((9, 9), bool), 20) + result = median_filter(img, 20, np.ones((9, 9), bool)) np.testing.assert_equal(result[0, 0], np.median(img)) assert (np.all(result == np.median(img))) @@ -48,7 +48,7 @@ def test_02_02_median_bigger(): '''Use an image of more than 255 values to test approximation''' np.random.seed(0) img = np.random.uniform(size=(20, 20)) - result = median_filter(img, np.ones((20, 20), bool), 40) + result = median_filter(img, 40, np.ones((20, 20), bool)) sorted = np.ravel(img) sorted.sort() min_acceptable = sorted[198] @@ -78,7 +78,7 @@ def test_03_01_shape(): octagon[i - j > radius + a_2] = False np.random.seed(0) img = np.random.uniform(size=(21, 21)) - result = median_filter(img, np.ones((21, 21), bool), radius) + result = median_filter(img, radius, np.ones((21, 21), bool)) sorted = img[octagon] sorted.sort() min_acceptable = sorted[len(sorted) / 2 - 1] @@ -94,7 +94,7 @@ def test_04_01_half_masked(): mask[10:, :] = False img[~ mask] = 2 img[1, 1] = 0 # to prevent short circuit for uniform data. - result = median_filter(img, mask, 5) + result = median_filter(img, 5, mask) # in partial coverage areas, the result should be only # from the masked pixels assert (np.all(result[:14, :] == 1)) @@ -106,7 +106,7 @@ def test_04_01_half_masked(): def test_default_values(): img = (np.random.random((20, 20)) * 255).astype(np.uint8) mask = np.ones((20, 20), dtype=np.uint8) - result1 = median_filter(img, mask, radius=2, percent=50) + result1 = median_filter(img, radius=2, mask=mask, percent=50) result2 = median_filter(img) np.testing.assert_array_equal(result1, result2) From 2c61928aa6de1f7d2fee79262773535189da5afd Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Thu, 27 Oct 2011 09:22:53 -0400 Subject: [PATCH 3/3] DOC: Add note about changed arguments for median_filter --- doc/source/api_changes.txt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/source/api_changes.txt b/doc/source/api_changes.txt index 9e6cf28c..57486723 100644 --- a/doc/source/api_changes.txt +++ b/doc/source/api_changes.txt @@ -3,3 +3,7 @@ Version 0.3 - Remove ``as_grey``, ``dtype`` keyword from ImageCollection - Remove ``dtype`` from imread - Generalise ImageCollection to accept a load_func + +Version 0.4 +----------- +- Switch mask and radius arguments for median_filter