diff --git a/skimage/rank/generic.py b/skimage/rank/generic.py new file mode 100644 index 00000000..e8808e5e --- /dev/null +++ b/skimage/rank/generic.py @@ -0,0 +1,10 @@ +import numpy as np + +def find_bitdepth(image): + """returns the max bith depth of a uint16 image + """ + umax = np.max(image) + if umax>2: + return int(np.log2(umax)) + else: + return 1 diff --git a/skimage/rank/percentile_rank.py b/skimage/rank/percentile_rank.py index 49f87dd4..840a302f 100644 --- a/skimage/rank/percentile_rank.py +++ b/skimage/rank/percentile_rank.py @@ -7,11 +7,14 @@ __docformat__ = 'restructuredtext en' import warnings from skimage import img_as_ubyte +import numpy as np + +from .generic import find_bitdepth +import _crank16_percentiles,_crank8_percentiles __all__ = ['percentile_mean'] - -def percentile_mean(image, selem, out=None, shift_x=False, shift_y=False, p0=.0, p1=1.): +def percentile_mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False, p0=.0, p1=1.): """Return greyscale local mean of an image. Mean is computed on the given structuring element. Only pixel values contained inside the @@ -20,16 +23,22 @@ def percentile_mean(image, selem, out=None, shift_x=False, shift_y=False, p0=.0, Parameters ---------- image : ndarray - Image array (uint8 array or uint16). + Image array (uint8 array or uint16). If image is uint16, as the algorithm uses max. 12bit histogram, + an exception will be raised if image has a value > 4095 selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray The array to store the result of the morphology. If None is passed, a new array will be allocated. + mask : ndarray (uint8) + Mask array that defines (>0) area of the image included in the local neighborhood. + If None, the complete image is used (default). shift_x, shift_y : bool shift structuring element about center point. This only affects eccentric structuring elements (i.e. selem with even numbered sides). Shift is bounded to the structuring element sizes. + p0, p1 : float in [0.,...,1.] + define the [p0,p1] percentile interval to be considered for computing the value. Returns ------- @@ -54,5 +63,18 @@ def percentile_mean(image, selem, out=None, shift_x=False, shift_y=False, p0=.0, [0, 0, 0, 0, 0]], dtype=uint8) """ - pass + selem = img_as_ubyte(selem) + if mask is not None: + mask = img_as_ubyte(mask) + if image.dtype == np.uint8: + return _crank8_percentiles.mean(image,selem,shift_x=shift_x,shift_y=shift_y,mask=mask,out=out,p0=p0,p1=p1) + elif image.dtype == np.uint16: + bitdepth = find_bitdepth(image) + if bitdepth>11: + raise ValueError("only uint16 <4096 image (12bit) supported!") + return _crank16_percentiles.mean(image,selem,shift_x=shift_x,shift_y=shift_y,mask=mask,bitdepth=bitdepth+1, + out=out,p0=p0,p1=p1) + else: + raise TypeError("only uint8 and uint16 image supported!") + diff --git a/skimage/rank/rank.py b/skimage/rank/rank.py index 7e4d16a2..c26fd033 100644 --- a/skimage/rank/rank.py +++ b/skimage/rank/rank.py @@ -9,21 +9,13 @@ import warnings from skimage import img_as_ubyte import numpy as np +from .generic import find_bitdepth import _crank16,_crank8 __all__ = ['mean'] -def find_bitdepth(image): - """returns the max bith depth of a uint16 image - """ - umax = np.max(image) - if umax>2: - return int(np.log2(umax)) - else: - return 1 - -def mean(image, selem, mask=None, out=None, shift_x=False, shift_y=False): +def mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """Return greyscale local mean of an image. Mean is computed on the given structuring element. @@ -33,14 +25,14 @@ def mean(image, selem, mask=None, out=None, shift_x=False, shift_y=False): image : ndarray Image array (uint8 array or uint16). If image is uint16, as the algorithm uses max. 12bit histogram, an exception will be raised if image has a value > 4095 - mask : ndarray (uint8) - Mask array that defines (>0) area of the image included in the local neighborhood. - If None, the complete image is used (default). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray The array to store the result of the morphology. If None is passed, a new array will be allocated. + mask : ndarray (uint8) + Mask array that defines (>0) area of the image included in the local neighborhood. + If None, the complete image is used (default). shift_x, shift_y : bool shift structuring element about center point. This only affects eccentric structuring elements (i.e. selem with even numbered sides). @@ -54,33 +46,43 @@ def mean(image, selem, mask=None, out=None, shift_x=False, shift_y=False): Examples -------- to be updated - >>> # Erosion shrinks bright regions + >>> # Local mean >>> from skimage.morphology import square - >>> bright_square = np.array([[0, 0, 0, 0, 0], + >>> ima8 = 255*np.array([[0, 0, 0, 0, 0], ... [0, 1, 1, 1, 0], ... [0, 1, 1, 1, 0], ... [0, 1, 1, 1, 0], ... [0, 0, 0, 0, 0]], dtype=np.uint8) - >>> erosion(bright_square, square(3)) - array([[0, 0, 0, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 1, 0, 0], - [0, 0, 0, 0, 0], - [0, 0, 0, 0, 0]], dtype=uint8) + >>> mean(ima8, square(3)) + array([[ 63, 85, 127, 85, 63], + [ 85, 113, 170, 113, 85], + [127, 170, 255, 170, 127], + [ 85, 113, 170, 113, 85], + [ 63, 85, 127, 85, 63]], dtype=uint8) + + >>> ima16 = 4095*np.array([[0, 0, 0, 0, 0], + ... [0, 1, 1, 1, 0], + ... [0, 1, 1, 1, 0], + ... [0, 1, 1, 1, 0], + ... [0, 0, 0, 0, 0]], dtype=np.uint16) + >>> mean(ima16, square(3)) + array([[1023, 1365, 2047, 1365, 1023], + [1365, 1820, 2730, 1820, 1365], + [2047, 2730, 4095, 2730, 2047], + [1365, 1820, 2730, 1820, 1365], + [1023, 1365, 2047, 1365, 1023]], dtype=uint16) """ - if image is out: - raise NotImplementedError("In-place erosion not supported!") selem = img_as_ubyte(selem) if mask is not None: mask = img_as_ubyte(mask) if image.dtype == np.uint8: - return _crank8.mean(image,selem,shift_x=shift_x,shift_y=shift_y,mask=mask) + return _crank8.mean(image,selem,shift_x=shift_x,shift_y=shift_y,mask=mask,out=out) elif image.dtype == np.uint16: bitdepth = find_bitdepth(image) if bitdepth>11: - raise ValueError("only uint16 <4096 image are supported!") - return _crank16.mean(image,selem,shift_x=shift_x,shift_y=shift_y,mask=mask,bitdepth=bitdepth+1) + raise ValueError("only uint16 <4096 image (12bit) supported!") + return _crank16.mean(image,selem,shift_x=shift_x,shift_y=shift_y,mask=mask,bitdepth=bitdepth+1,out=out) else: raise TypeError("only uint8 and uint16 image supported!") diff --git a/skimage/rank/tests/test_rank.py b/skimage/rank/tests/test_rank.py index 77dae32b..75dd7f65 100644 --- a/skimage/rank/tests/test_rank.py +++ b/skimage/rank/tests/test_rank.py @@ -24,6 +24,17 @@ plt.colorbar() plt.figure() plt.imshow(np.hstack((a16,f16))) plt.colorbar() + +f8 = rank.percentile_mean(a8,selem,p0=.1,p1=.9) +f16 = rank.percentile_mean(a16,selem,p0=.1,p1=.9) + +plt.figure() +plt.imshow(np.hstack((a8,f8))) +plt.colorbar() +plt.figure() +plt.imshow(np.hstack((a16,f16))) +plt.colorbar() + plt.show()