Remove deprecated skimage.filter.median_filter

This commit is contained in:
Johannes Schönberger
2014-04-11 10:05:51 -04:00
parent d90b30c4a0
commit ed558d672e
4 changed files with 0 additions and 239 deletions
-1
View File
@@ -14,4 +14,3 @@ Version 0.10
------------
* Remove backwards-compatability of `skimage.measure.regionprops`
* Remove deprecated logger function in `skimage/__init__.py`
* Remove deprecated function `filter.median_filter`
-2
View File
@@ -1,5 +1,4 @@
from .lpi_filter import inverse, wiener, LPIFilter2D
from .ctmf import median_filter
from ._gaussian import gaussian_filter
from ._canny import canny
from .edges import (sobel, hsobel, vsobel, scharr, hscharr, vscharr, prewitt,
@@ -25,7 +24,6 @@ denoise_tv_chambolle = deprecated('skimage.restoration.denoise_tv_chambolle')\
__all__ = ['inverse',
'wiener',
'LPIFilter2D',
'median_filter',
'gaussian_filter',
'canny',
'sobel',
-109
View File
@@ -1,109 +0,0 @@
"""ctmf.py - constant time per pixel median filtering with an octagonal shape
Reference: S. Perreault and P. Hebert, "Median Filtering in Constant Time",
IEEE Transactions on Image Processing, September 2007.
Originally part of CellProfiler, code licensed under both GPL and BSD licenses.
Website: http://www.cellprofiler.org
Copyright (c) 2003-2009 Massachusetts Institute of Technology
Copyright (c) 2009-2011 Broad Institute
All rights reserved.
Original author: Lee Kamentsky
"""
import warnings
import numpy as np
from . import _ctmf
from ._rank_order import rank_order
from .._shared.utils import deprecated
@deprecated('filter.rank.median')
def median_filter(image, radius=2, mask=None, percent=50):
"""Masked median filter with octagon shape.
Parameters
----------
image : (M, N) ndarray
Input image.
radius : int
Radius (in pixels) of a circle inscribed into the filtering
octagon. Must be at least 2. Default radius is 2.
mask : (M, N) ndarray
Mask with 1's for significant pixels, 0's for masked pixels.
By default, all pixels are considered significant.
percent : int
The unmasked pixels within the octagon are sorted, and the
value at `percent` percent of the index range is chosen.
Default value of 50 gives the median pixel.
Returns
-------
out : (M, N) ndarray
Filtered array. In areas where the median filter does
not overlap the mask, the filtered result is undefined, but
in practice, it will be the lowest value in the valid area.
Notes
-----
Because of the histogram implementation, the number of unique values
for the output is limited to 256.
Examples
--------
>>> a = np.ones((5, 5))
>>> a[2, 2] = 10 # introduce outlier
>>> b = median_filter(a)
>>> b[2, 2] # the median filter is good at removing outliers
1.0
"""
if image.ndim != 2:
raise TypeError("Input 'image' must be a two-dimensional array.")
if radius < 2:
raise ValueError("Input 'radius' must be >= 2.")
if mask is None:
mask = np.ones(image.shape, dtype=np.bool)
mask = np.ascontiguousarray(mask, dtype=np.bool)
if np.all(~ mask):
warnings.warn('Mask is all over image! Returning copy of input image.')
return image.copy()
if (not np.issubdtype(image.dtype, np.int) or
np.min(image) < 0 or np.max(image) > 255):
ranked_values, translation = rank_order(image[mask])
max_ranked_values = np.max(ranked_values)
if max_ranked_values == 0:
warnings.warn('Particular case? Returning copy of input image.')
return image.copy()
if max_ranked_values > 255:
ranked_values = ranked_values * 255 // max_ranked_values
was_ranked = True
else:
ranked_values = image[mask]
was_ranked = False
ranked_image = np.zeros(image.shape, np.uint8)
ranked_image[mask] = ranked_values
mask.dtype = np.uint8
output = np.zeros(image.shape, np.uint8)
_ctmf.median_filter(ranked_image, 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 image.
#
if max_ranked_values > 255:
result = translation[output.astype(np.uint32) *
max_ranked_values // 255]
else:
result = translation[output]
else:
result = output
return result
-127
View File
@@ -1,127 +0,0 @@
import numpy as np
from nose.tools import raises
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)), 3, np.ones((10, 10), bool))
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)), 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)), 3, mask)
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
result = median_filter(img, 3, mask)
assert (np.all(result[mask] == 0))
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, 20, np.ones((9, 9), bool))
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, 40, np.ones((20, 20), bool))
sorted = np.ravel(img)
sorted.sort()
min_acceptable = sorted[198]
max_acceptable = sorted[202]
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)
#
# 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[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
np.random.seed(0)
img = np.random.uniform(size=(21, 21))
result = median_filter(img, radius, np.ones((21, 21), bool))
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)
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[10:, :] = False
img[~ mask] = 2
img[1, 1] = 0 # to prevent short circuit for uniform data.
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))
# 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)
result1 = median_filter(img, radius=2, mask=mask, percent=50)
result2 = median_filter(img)
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)
@raises(TypeError)
def test_wrong_shape():
img = np.empty((10, 10, 3))
median_filter(img)
if __name__ == "__main__":
np.testing.run_module_suite()