From e6f660d49df70834e2a3be8f36b787eb9f59442d Mon Sep 17 00:00:00 2001 From: Andreas Mueller Date: Mon, 26 Sep 2011 19:50:34 +0200 Subject: [PATCH 1/6] rank filter asserts input is 2d --- scikits/image/filter/ctmf.py | 3 +++ scikits/image/filter/tests/test_ctmf.py | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/scikits/image/filter/ctmf.py b/scikits/image/filter/ctmf.py index e88cdb54..310534b7 100644 --- a/scikits/image/filter/ctmf.py +++ b/scikits/image/filter/ctmf.py @@ -43,6 +43,9 @@ def median_filter(data, mask=None, radius=1, percent=50): ''' + if data.ndim!=2: + raise TypeError("The input 'data' must be a two dimensional array.") + if mask is None: mask = np.ones(data.shape, dtype=np.bool) mask = np.ascontiguousarray(mask, dtype=np.bool) diff --git a/scikits/image/filter/tests/test_ctmf.py b/scikits/image/filter/tests/test_ctmf.py index 02795b3c..1fc26968 100644 --- a/scikits/image/filter/tests/test_ctmf.py +++ b/scikits/image/filter/tests/test_ctmf.py @@ -101,5 +101,12 @@ def test_default_values(): result2 = median_filter(img) assert_array_equal(result1, result2) +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=1, percent=50) + result2 = median_filter(img) + assert_array_equal(result1, result2) + if __name__ == "__main__": run_module_suite() From dfad24e68260bbf47b57b6c9c0c1f25b29486ed3 Mon Sep 17 00:00:00 2001 From: Andreas Mueller Date: Mon, 26 Sep 2011 19:50:55 +0200 Subject: [PATCH 2/6] rank filter has radius 2 by default. radius 1 fails ?! --- scikits/image/filter/ctmf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scikits/image/filter/ctmf.py b/scikits/image/filter/ctmf.py index 310534b7..8fe5f6f6 100644 --- a/scikits/image/filter/ctmf.py +++ b/scikits/image/filter/ctmf.py @@ -15,7 +15,7 @@ import numpy as np from . import _ctmf from rank_order import rank_order -def median_filter(data, mask=None, radius=1, percent=50): +def median_filter(data, mask=None, radius=2, percent=50): '''Masked median filter with octagon shape. Parameters From 4fab810a5e67b5e2c363761c4594adf38e5fc812 Mon Sep 17 00:00:00 2001 From: Andreas Mueller Date: Mon, 26 Sep 2011 19:54:55 +0200 Subject: [PATCH 3/6] remove unused imports, avoid from x import * --- scikits/image/filter/tests/test_ctmf.py | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/scikits/image/filter/tests/test_ctmf.py b/scikits/image/filter/tests/test_ctmf.py index 1fc26968..1c6b8592 100644 --- a/scikits/image/filter/tests/test_ctmf.py +++ b/scikits/image/filter/tests/test_ctmf.py @@ -1,7 +1,4 @@ -import os.path - import numpy as np -from numpy.testing import * from scikits.image.filter import median_filter @@ -20,7 +17,7 @@ def test_00_01_all_masked(): def test_00_02_all_but_one_masked(): mask = np.zeros((10,10), bool) mask[5,5] = True - result = median_filter(np.zeros((10,10)), mask, 3) + median_filter(np.zeros((10,10)), mask, 3) def test_01_01_mask(): '''The median filter, masking a single value''' @@ -30,14 +27,14 @@ def test_01_01_mask(): mask[5,5] = False result = median_filter(img, mask, 3) assert (np.all(result[mask] == 0)) - assert_equal(result[5,5], 1) + np.testing.assert_equal(result[5,5], 1) 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) - assert_equal(result[0,0], np.median(img)) + np.testing.assert_equal(result[0,0], np.median(img)) assert (np.all(result == np.median(img))) def test_02_02_median_bigger(): @@ -99,14 +96,7 @@ def test_default_values(): mask = np.ones((20, 20), dtype=np.uint8) result1 = median_filter(img, mask, radius=1, percent=50) result2 = median_filter(img) - assert_array_equal(result1, result2) - -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=1, percent=50) - result2 = median_filter(img) - assert_array_equal(result1, result2) + np.testing.assert_array_equal(result1, result2) if __name__ == "__main__": - run_module_suite() + np.testing.run_module_suite() From 82212dd2f7a83460cb767fd09f1c01ba2be995f2 Mon Sep 17 00:00:00 2001 From: Andreas Mueller Date: Mon, 26 Sep 2011 20:11:51 +0200 Subject: [PATCH 4/6] pep8 --- scikits/image/filter/ctmf.py | 10 ++-- scikits/image/filter/tests/test_ctmf.py | 78 ++++++++++++++----------- 2 files changed, 51 insertions(+), 37 deletions(-) diff --git a/scikits/image/filter/ctmf.py b/scikits/image/filter/ctmf.py index 8fe5f6f6..875fc59b 100644 --- a/scikits/image/filter/ctmf.py +++ b/scikits/image/filter/ctmf.py @@ -15,6 +15,7 @@ import numpy as np from . import _ctmf from rank_order import rank_order + def median_filter(data, mask=None, radius=2, percent=50): '''Masked median filter with octagon shape. @@ -43,7 +44,7 @@ def median_filter(data, mask=None, radius=2, percent=50): ''' - if data.ndim!=2: + if data.ndim != 2: raise TypeError("The input 'data' must be a two dimensional array.") if mask is None: @@ -57,7 +58,7 @@ def median_filter(data, mask=None, radius=2, percent=50): # if (not np.issubdtype(data.dtype, np.int) or np.min(data) < 0 or np.max(data) > 255): - ranked_data,translation = rank_order(data[mask]) + ranked_data, translation = rank_order(data[mask]) max_ranked_data = np.max(ranked_data) if max_ranked_data == 0: return data @@ -67,7 +68,7 @@ def median_filter(data, mask=None, radius=2, percent=50): else: ranked_data = data[mask] was_ranked = False - input = np.zeros(data.shape, np.uint8 ) + input = np.zeros(data.shape, np.uint8) input[mask] = ranked_data mask.dtype = np.uint8 @@ -81,7 +82,8 @@ def median_filter(data, mask=None, radius=2, percent=50): # use the translation to look up the original value in the data. # if max_ranked_data > 255: - result = translation[output.astype(np.uint32) * max_ranked_data // 255] + result = translation[output.astype(np.uint32) * + max_ranked_data // 255] else: result = translation[output] else: diff --git a/scikits/image/filter/tests/test_ctmf.py b/scikits/image/filter/tests/test_ctmf.py index 1c6b8592..f338db62 100644 --- a/scikits/image/filter/tests/test_ctmf.py +++ b/scikits/image/filter/tests/test_ctmf.py @@ -2,46 +2,52 @@ import numpy as np from scikits.image.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)), np.ones((10, 10), bool), 3) assert np.all(result == 0) + 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)), np.zeros((10, 10), bool), 3) 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) + mask = np.zeros((10, 10), bool) + mask[5, 5] = True + median_filter(np.zeros((10, 10)), mask, 3) + def test_01_01_mask(): '''The median filter, masking a single value''' - img = np.zeros((10,10)) - img[5,5] = 1 - mask = np.ones((10,10),bool) - mask[5,5] = False + img = np.zeros((10, 10)) + img[5, 5] = 1 + mask = np.ones((10, 10), bool) + mask[5, 5] = False result = median_filter(img, mask, 3) assert (np.all(result[mask] == 0)) - np.testing.assert_equal(result[5,5], 1) + np.testing.assert_equal(result[5, 5], 1) + 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) - np.testing.assert_equal(result[0,0], np.median(img)) + img = np.random.uniform(size=(9, 9)) + result = median_filter(img, np.ones((9, 9), bool), 20) + np.testing.assert_equal(result[0, 0], np.median(img)) assert (np.all(result == np.median(img))) + 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) + img = np.random.uniform(size=(20, 20)) + result = median_filter(img, np.ones((20, 20), bool), 40) sorted = np.ravel(img) sorted.sort() min_acceptable = sorted[198] @@ -49,48 +55,53 @@ def test_02_02_median_bigger(): assert (np.all(result >= min_acceptable)) assert (np.all(result <= max_acceptable)) + def test_03_01_shape(): '''Make sure the median filter is the expected octagonal shape''' radius = 5 a_2 = int(radius / 2.414213) - i,j = np.mgrid[-10:11,-10:11] - octagon = np.ones((21,21), bool) + i, j = np.mgrid[-10:11, -10:11] + octagon = np.ones((21, 21), bool) # # constrain the octagon mask to be the points that are on # the correct side of the 8 edges # octagon[i < -radius] = False - octagon[i > radius] = False + octagon[i > radius] = False octagon[j < -radius] = False - octagon[j > radius] = False - octagon[i+j < -radius-a_2] = False - octagon[j-i > radius+a_2] = False - octagon[i+j > radius+a_2] = False - octagon[i-j > radius+a_2] = False + octagon[j > radius] = False + octagon[i + j < -radius - a_2] = False + octagon[j - i > radius + a_2] = False + octagon[i + j > radius + a_2] = False + 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) + img = np.random.uniform(size=(21, 21)) + result = median_filter(img, np.ones((21, 21), bool), radius) sorted = img[octagon] sorted.sort() - min_acceptable = sorted[len(sorted)/2-1] - max_acceptable = sorted[len(sorted)/2+1] - assert (result[10,10] >= min_acceptable) - assert (result[10,10] <= max_acceptable) + min_acceptable = sorted[len(sorted) / 2 - 1] + max_acceptable = sorted[len(sorted) / 2 + 1] + assert (result[10, 10] >= min_acceptable) + assert (result[10, 10] <= max_acceptable) + def test_04_01_half_masked(): '''Make sure that the median filter can handle large masked areas.''' img = np.ones((20, 20)) - mask = np.ones((20, 20),bool) + mask = np.ones((20, 20), bool) mask[10:, :] = False img[~ mask] = 2 - img[1, 1] = 0 # to prevent short circuit for uniform data. + img[1, 1] = 0 # to prevent short circuit for uniform data. result = median_filter(img, mask, 5) - # in partial coverage areas, the result should be only from the masked pixels + # in partial coverage areas, the result should be only + # from the masked pixels assert (np.all(result[:14, :] == 1)) - # in zero coverage areas, the result should be the lowest valud in the valid area + # in zero coverage areas, the result should be the lowest + # value in the valid area assert (np.all(result[15:, :] == np.min(img[mask]))) + def test_default_values(): img = (np.random.random((20, 20)) * 255).astype(np.uint8) mask = np.ones((20, 20), dtype=np.uint8) @@ -98,5 +109,6 @@ def test_default_values(): result2 = median_filter(img) np.testing.assert_array_equal(result1, result2) + if __name__ == "__main__": np.testing.run_module_suite() From e9efbbcf16347d6b6cf1880655b9e87553d6388f Mon Sep 17 00:00:00 2001 From: Andreas Mueller Date: Mon, 26 Sep 2011 20:15:49 +0200 Subject: [PATCH 5/6] adjusted default value test to new default values... what does that test do? --- scikits/image/filter/tests/test_ctmf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scikits/image/filter/tests/test_ctmf.py b/scikits/image/filter/tests/test_ctmf.py index f338db62..7b269868 100644 --- a/scikits/image/filter/tests/test_ctmf.py +++ b/scikits/image/filter/tests/test_ctmf.py @@ -105,7 +105,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=1, percent=50) + result1 = median_filter(img, mask, radius=2, percent=50) result2 = median_filter(img) np.testing.assert_array_equal(result1, result2) From 0cec5fcf09d32d7a6bb0aa96739deb5e07793482 Mon Sep 17 00:00:00 2001 From: Andreas Mueller Date: Mon, 26 Sep 2011 20:21:20 +0200 Subject: [PATCH 6/6] in median filter, rename input data to "image" --- scikits/image/filter/ctmf.py | 44 ++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/scikits/image/filter/ctmf.py b/scikits/image/filter/ctmf.py index 875fc59b..1f294ee4 100644 --- a/scikits/image/filter/ctmf.py +++ b/scikits/image/filter/ctmf.py @@ -16,12 +16,12 @@ from . import _ctmf from rank_order import rank_order -def median_filter(data, mask=None, radius=2, percent=50): +def median_filter(image, mask=None, radius=2, percent=50): '''Masked median filter with octagon shape. Parameters ---------- - data : (M,N) ndarray, dtype uint8 + image : (M,N) ndarray, dtype uint8 Input image. mask : (M,N) ndarray, dtype uint8, optional A value of 1 indicates a significant pixel, 0 @@ -44,46 +44,46 @@ def median_filter(data, mask=None, radius=2, percent=50): ''' - if data.ndim != 2: - raise TypeError("The input 'data' must be a two dimensional array.") + if image.ndim != 2: + raise TypeError("The input 'image' must be a two dimensional array.") if mask is None: - mask = np.ones(data.shape, dtype=np.bool) + mask = np.ones(image.shape, dtype=np.bool) mask = np.ascontiguousarray(mask, dtype=np.bool) if np.all(~ mask): - return data.copy() + return image.copy() # - # Normalize the ranked data to 0-255 + # Normalize the ranked image to 0-255 # - if (not np.issubdtype(data.dtype, np.int) or - np.min(data) < 0 or np.max(data) > 255): - ranked_data, translation = rank_order(data[mask]) - max_ranked_data = np.max(ranked_data) - if max_ranked_data == 0: - return data - if max_ranked_data > 255: - ranked_data = ranked_data * 255 // max_ranked_data + if (not np.issubdtype(image.dtype, np.int) or + np.min(image) < 0 or np.max(image) > 255): + ranked_image, translation = rank_order(image[mask]) + max_ranked_image = np.max(ranked_image) + if max_ranked_image == 0: + return image + if max_ranked_image > 255: + ranked_image = ranked_image * 255 // max_ranked_image was_ranked = True else: - ranked_data = data[mask] + ranked_image = image[mask] was_ranked = False - input = np.zeros(data.shape, np.uint8) - input[mask] = ranked_data + input = np.zeros(image.shape, np.uint8) + input[mask] = ranked_image mask.dtype = np.uint8 - output = np.zeros(data.shape, np.uint8) + output = np.zeros(image.shape, np.uint8) _ctmf.median_filter(input, mask, output, radius, percent) if was_ranked: # # The translation gives the original value at each ranking. # We rescale the output to the original ranking and then - # use the translation to look up the original value in the data. + # use the translation to look up the original value in the image. # - if max_ranked_data > 255: + if max_ranked_image > 255: result = translation[output.astype(np.uint32) * - max_ranked_data // 255] + max_ranked_image // 255] else: result = translation[output] else: