From 58a4a43f104d40d6e12019e4c37a602f09b860d6 Mon Sep 17 00:00:00 2001 From: Tony S Yu Date: Fri, 28 Jun 2013 18:06:10 -0500 Subject: [PATCH] Change rank.pyx to _rank.py - Cython was unnecessary in the main rank module - Don't shadow package name in the module - Add support for int8 images. --- skimage/filter/rank/__init__.py | 6 +++--- skimage/filter/rank/{rank.pyx => _rank.py} | 20 +++++++++++------- skimage/filter/rank/tests/test_rank.py | 24 ++++++++++++++++++++++ 3 files changed, 40 insertions(+), 10 deletions(-) rename skimage/filter/rank/{rank.pyx => _rank.py} (98%) diff --git a/skimage/filter/rank/__init__.py b/skimage/filter/rank/__init__.py index 906566b7..deceaade 100644 --- a/skimage/filter/rank/__init__.py +++ b/skimage/filter/rank/__init__.py @@ -1,6 +1,6 @@ -from .rank import (autolevel, bottomhat, equalize, gradient, maximum, mean, - meansubtraction, median, minimum, modal, morph_contr_enh, - pop, threshold, tophat, noise_filter, entropy, otsu) +from ._rank import (autolevel, bottomhat, equalize, gradient, maximum, mean, + meansubtraction, median, minimum, modal, morph_contr_enh, + pop, threshold, tophat, noise_filter, entropy, otsu) from .percentile_rank import (percentile_autolevel, percentile_gradient, percentile_mean, percentile_mean_subtraction, percentile_morph_contr_enh, percentile, diff --git a/skimage/filter/rank/rank.pyx b/skimage/filter/rank/_rank.py similarity index 98% rename from skimage/filter/rank/rank.pyx rename to skimage/filter/rank/_rank.py index 559f1c76..652732dd 100644 --- a/skimage/filter/rank/rank.pyx +++ b/skimage/filter/rank/_rank.py @@ -40,13 +40,10 @@ def _apply(func8, func16, image, selem, out, mask, shift_x, shift_y): if image is out: raise NotImplementedError("Cannot perform rank operation in place.") - if image.dtype == np.uint8: - if func8 is None: - raise TypeError("Not implemented for uint8 image.") - if out is None: - out = np.zeros(image.shape, dtype=np.uint8) - func8(image, selem, shift_x=shift_x, shift_y=shift_y, - mask=mask, out=out) + is_8bit = image.dtype in (np.uint8, np.int8) + + if func8 is not None and (is_8bit or func16 is None): + out = _apply8(func8, image, selem, out, mask, shift_x, shift_y) elif image.dtype == np.uint16: if func16 is None: raise TypeError("Not implemented for uint16 image.") @@ -63,6 +60,15 @@ def _apply(func8, func16, image, selem, out, mask, shift_x, shift_y): return out +def _apply8(func8, image, selem, out, mask, shift_x, shift_y): + if out is None: + out = np.zeros(image.shape, dtype=np.uint8) + image = img_as_ubyte(image) + func8(image, selem, shift_x=shift_x, shift_y=shift_y, + mask=mask, out=out) + return out + + def autolevel(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """Autolevel image using local histogram. diff --git a/skimage/filter/rank/tests/test_rank.py b/skimage/filter/rank/tests/test_rank.py index d7748d0f..7a515a89 100644 --- a/skimage/filter/rank/tests/test_rank.py +++ b/skimage/filter/rank/tests/test_rank.py @@ -1,6 +1,7 @@ import numpy as np from numpy.testing import run_module_suite, assert_array_equal, assert_raises +from skimage import img_as_ubyte from skimage import data, util from skimage.morphology import cmorph, disk from skimage.filter import rank @@ -186,6 +187,29 @@ def test_compare_autolevels_16bit(): assert_array_equal(loc_autolevel, loc_perc_autolevel) +def test_compare_8bit_unsigned_vs_signed(): + # filters applied on 8-bit image ore 16-bit image (having only real 8-bit of + # dynamic) should be identical + + # Create signed int8 image that and convert it to uint8 + image = img_as_ubyte(data.camera()) + image[image > 127] = 0 + image_s = image.astype(np.int8) + image_u = img_as_ubyte(image_s) + + assert_array_equal(image_u, img_as_ubyte(image_s)) + + methods = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'maximum', + 'mean', 'meansubtraction', 'median', 'minimum', 'modal', + 'morph_contr_enh', 'pop', 'threshold', 'tophat'] + + for method in methods: + func = getattr(rank, method) + out_u = func(image_u, disk(3)) + out_s = func(image_s, disk(3)) + assert_array_equal(out_u, out_s) + + def test_compare_8bit_vs_16bit(): # filters applied on 8-bit image ore 16-bit image (having only real 8-bit of # dynamic) should be identical