From 9a17db19da341e4250d1168660db13b8fdb2075e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 09:31:37 +0200 Subject: [PATCH 01/43] Refactor rank filter package for consistent naming --- skimage/filter/rank/__init__.py | 16 +- skimage/filter/rank/_rank.py | 773 ----------------- .../rank/{bilateral_rank.pyx => bilateral.py} | 8 +- ...ank16_bilateral.pyx => bilateral16_cy.pyx} | 2 +- .../rank/{_core16.pxd => core16_cy.pxd} | 0 .../rank/{_core16.pyx => core16_cy.pyx} | 2 +- .../filter/rank/{_core8.pxd => core8_cy.pxd} | 0 .../filter/rank/{_core8.pyx => core8_cy.pyx} | 0 skimage/filter/rank/generic.py | 776 ++++++++++++++++++ .../rank/{_crank16.pyx => generic16_cy.pyx} | 2 +- .../rank/{_crank8.pyx => generic8_cy.pyx} | 2 +- .../{percentile_rank.pyx => percentile.py} | 26 +- ...16_percentiles.pyx => percentile16_cy.pyx} | 2 +- ...nk8_percentiles.pyx => percentile8_cy.pyx} | 2 +- skimage/filter/setup.py | 37 +- 15 files changed, 822 insertions(+), 826 deletions(-) delete mode 100644 skimage/filter/rank/_rank.py rename skimage/filter/rank/{bilateral_rank.pyx => bilateral.py} (96%) rename skimage/filter/rank/{_crank16_bilateral.pyx => bilateral16_cy.pyx} (98%) rename skimage/filter/rank/{_core16.pxd => core16_cy.pxd} (100%) rename skimage/filter/rank/{_core16.pyx => core16_cy.pyx} (99%) rename skimage/filter/rank/{_core8.pxd => core8_cy.pxd} (100%) rename skimage/filter/rank/{_core8.pyx => core8_cy.pyx} (100%) rename skimage/filter/rank/{_crank16.pyx => generic16_cy.pyx} (99%) rename skimage/filter/rank/{_crank8.pyx => generic8_cy.pyx} (99%) rename skimage/filter/rank/{percentile_rank.pyx => percentile.py} (94%) rename skimage/filter/rank/{_crank16_percentiles.pyx => percentile16_cy.pyx} (99%) rename skimage/filter/rank/{_crank8_percentiles.pyx => percentile8_cy.pyx} (99%) diff --git a/skimage/filter/rank/__init__.py b/skimage/filter/rank/__init__.py index deceaade..9ad816ce 100644 --- a/skimage/filter/rank/__init__.py +++ b/skimage/filter/rank/__init__.py @@ -1,11 +1,11 @@ -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, - percentile_pop, percentile_threshold) -from .bilateral_rank import bilateral_mean, bilateral_pop +from .generic import (autolevel, bottomhat, equalize, gradient, maximum, mean, + meansubtraction, median, minimum, modal, morph_contr_enh, + pop, threshold, tophat, noise_filter, entropy, otsu) +from .percentile import (percentile_autolevel, percentile_gradient, + percentile_mean, percentile_mean_subtraction, + percentile_morph_contr_enh, percentile, + percentile_pop, percentile_threshold) +from .bilateral import bilateral_mean, bilateral_pop __all__ = ['autolevel', diff --git a/skimage/filter/rank/_rank.py b/skimage/filter/rank/_rank.py deleted file mode 100644 index ea58ad86..00000000 --- a/skimage/filter/rank/_rank.py +++ /dev/null @@ -1,773 +0,0 @@ -"""The local histogram is computed using a sliding window similar to the method -described in [1]_. - -Input image can be 8-bit or 16-bit with a value < 4096 (i.e. 12 bit), for 16-bit -input images, the number of histogram bins is determined from the maximum value -present in the image. - -Result image is 8 or 16-bit with respect to the input image. - -References ----------- - -.. [1] Huang, T. ,Yang, G. ; Tang, G.. "A fast two-dimensional - median filtering algorithm", IEEE Transactions on Acoustics, Speech and - Signal Processing, Feb 1979. Volume: 27 , Issue: 1, Page(s): 13 - 18. - -""" - -import numpy as np -from skimage import img_as_ubyte, img_as_uint -from skimage.filter.rank import _crank8, _crank16 -from skimage.filter.rank.generic import find_bitdepth - - -__all__ = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'maximum', 'mean', - 'meansubtraction', 'median', 'minimum', 'modal', 'morph_contr_enh', - 'pop', 'threshold', 'tophat', 'noise_filter', 'entropy', 'otsu'] - - -def _apply(func8, func16, image, selem, out, mask, shift_x, shift_y): - selem = img_as_ubyte(selem > 0) - image = np.ascontiguousarray(image) - - if mask is None: - mask = np.ones(image.shape, dtype=np.uint8) - else: - mask = np.ascontiguousarray(mask) - mask = img_as_ubyte(mask) - - if image is out: - raise NotImplementedError("Cannot perform rank operation in place.") - - 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) - else: - image = img_as_uint(image) - if out is None: - out = np.zeros(image.shape, dtype=np.uint16) - bitdepth = find_bitdepth(image) - if bitdepth > 11: - image = image >> 4 - bitdepth = find_bitdepth(image) - func16(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, - bitdepth=bitdepth + 1, out=out) - - 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. - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - out : uint8 array or uint16 array (same as input image) - The result of the local autolevel. - - Examples - -------- - >>> from skimage import data - >>> from skimage.morphology import disk - >>> from skimage.filter.rank import autolevel - >>> # Load test image - >>> ima = data.camera() - >>> # Stretch image contrast locally - >>> auto = autolevel(ima, disk(20)) - - """ - - return _apply(_crank8.autolevel, _crank16.autolevel, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def bottomhat(image, selem, out=None, mask=None, shift_x=False, shift_y=False): - """Returns greyscale local bottomhat of an image. - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - local bottomhat : uint8 array or uint16 array depending on input image - The result of the local bottomhat. - - """ - - return _apply(_crank8.bottomhat, _crank16.bottomhat, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def equalize(image, selem, out=None, mask=None, shift_x=False, shift_y=False): - """Equalize image using local histogram. - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - out : uint8 array or uint16 array (same as input image) - The result of the local equalize. - - Examples - -------- - >>> from skimage import data - >>> from skimage.morphology import disk - >>> from skimage.filter.rank import equalize - >>> # Load test image - >>> ima = data.camera() - >>> # Local equalization - >>> equ = equalize(ima, disk(20)) - - """ - - return _apply(_crank8.equalize, _crank16.equalize, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def gradient(image, selem, out=None, mask=None, shift_x=False, shift_y=False): - """Return greyscale local gradient of an image (i.e. local maximum - local - minimum). - - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - out : uint8 array or uint16 array (same as input image) - The local gradient. - - """ - - return _apply(_crank8.gradient, _crank16.gradient, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def maximum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): - """Return greyscale local maximum of an image. - - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - out : uint8 array or uint16 array (same as input image) - The local maximum. - - See also - -------- - skimage.morphology.dilation - - Note - ---- - * input image can be 8-bit or 16-bit with a value < 4096 (i.e. 12 bit) - * the lower algorithm complexity makes the rank.maximum() more efficient for - larger images and structuring elements - - """ - - return _apply(_crank8.maximum, _crank16.maximum, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False): - """Return greyscale local mean of an image. - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - out : uint8 array or uint16 array (same as input image) - The local mean. - - Examples - -------- - >>> from skimage import data - >>> from skimage.morphology import disk - >>> from skimage.filter.rank import mean - >>> # Load test image - >>> ima = data.camera() - >>> # Local mean - >>> avg = mean(ima, disk(20)) - - """ - - return _apply(_crank8.mean, _crank16.mean, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def meansubtraction(image, selem, out=None, mask=None, shift_x=False, - shift_y=False): - """Return image subtracted from its local mean. - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - out : uint8 array or uint16 array (same as input image) - The result of the local meansubtraction. - - """ - - return _apply(_crank8.meansubtraction, _crank16.meansubtraction, image, - selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def median(image, selem, out=None, mask=None, shift_x=False, shift_y=False): - """Return greyscale local median of an image. - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - out : uint8 array or uint16 array (same as input image) - The local median. - - Examples - -------- - >>> from skimage import data - >>> from skimage.morphology import disk - >>> from skimage.filter.rank import median - >>> # Load test image - >>> ima = data.camera() - >>> # Local mean - >>> avg = median(ima, disk(20)) - - """ - - return _apply(_crank8.median, _crank16.median, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def minimum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): - """Return greyscale local minimum of an image. - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - out : uint8 array or uint16 array (same as input image) - The local minimum. - - See also - -------- - skimage.morphology.erosion - - Note - ---- - * input image can be 8-bit or 16-bit with a value < 4096 (i.e. 12 bit) - * the lower algorithm complexity makes the rank.minimum() more efficient - for larger images and structuring elements - - """ - - return _apply(_crank8.minimum, _crank16.minimum, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def modal(image, selem, out=None, mask=None, shift_x=False, shift_y=False): - """Return greyscale local mode of an image. - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - out : uint8 array or uint16 array (same as input image) - The local modal. - - """ - - return _apply(_crank8.modal, _crank16.modal, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def morph_contr_enh(image, selem, out=None, mask=None, shift_x=False, - shift_y=False): - """Enhance an image replacing each pixel by the local maximum if pixel - greylevel is closest to maximimum than local minimum OR local minimum - otherwise. - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - out : uint8 array or uint16 array (same as input image) - The result of the local morph_contr_enh. - - Examples - -------- - >>> from skimage import data - >>> from skimage.morphology import disk - >>> from skimage.filter.rank import morph_contr_enh - >>> # Load test image - >>> ima = data.camera() - >>> # Local mean - >>> avg = morph_contr_enh(ima, disk(20)) - - """ - - return _apply(_crank8.morph_contr_enh, _crank16.morph_contr_enh, image, - selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def pop(image, selem, out=None, mask=None, shift_x=False, shift_y=False): - """Return the number (population) of pixels actually inside the - neighborhood. - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - out : uint8 array or uint16 array (same as input image) - The number of pixels belonging to the neighborhood. - - Examples - -------- - >>> # Local mean - >>> from skimage.morphology import square - >>> import skimage.filter.rank as rank - >>> ima = 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) - >>> rank.pop(ima, square(3)) - array([[4, 6, 6, 6, 4], - [6, 9, 9, 9, 6], - [6, 9, 9, 9, 6], - [6, 9, 9, 9, 6], - [4, 6, 6, 6, 4]], dtype=uint8) - - """ - - return _apply(_crank8.pop, _crank16.pop, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def threshold(image, selem, out=None, mask=None, shift_x=False, shift_y=False): - """Return greyscale local threshold of an image. - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - out : uint8 array or uint16 array (same as input image) - The result of the local threshold. - - Examples - -------- - >>> # Local threshold - >>> from skimage.morphology import square - >>> from skimage.filter.rank import threshold - >>> ima = 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) - >>> threshold(ima, square(3)) - array([[0, 0, 0, 0, 0], - [0, 1, 1, 1, 0], - [0, 1, 0, 1, 0], - [0, 1, 1, 1, 0], - [0, 0, 0, 0, 0]], dtype=uint8) - - """ - - return _apply(_crank8.threshold, _crank16.threshold, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def tophat(image, selem, out=None, mask=None, shift_x=False, shift_y=False): - """Return greyscale local tophat of an image. - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - out : uint8 array or uint16 array (same as input image) - The image tophat. - - """ - - return _apply(_crank8.tophat, _crank16.tophat, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def noise_filter(image, selem, out=None, mask=None, shift_x=False, - shift_y=False): - """Returns the noise feature as described in [Hashimoto12]_ - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - References - ---------- - .. [Hashimoto12] N. Hashimoto et al. Referenceless image quality evaluation - for whole slide imaging. J Pathol Inform 2012;3:9. - - Returns - ------- - out : uint8 array or uint16 array (same as input image) - The image noise. - - """ - - # ensure that the central pixel in the structuring element is empty - centre_r = int(selem.shape[0] / 2) + shift_y - centre_c = int(selem.shape[1] / 2) + shift_x - # make a local copy - selem_cpy = selem.copy() - selem_cpy[centre_r, centre_c] = 0 - - return _apply(_crank8.noise_filter, None, image, selem_cpy, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def entropy(image, selem, out=None, mask=None, shift_x=False, shift_y=False): - """Returns the entropy [1]_ computed locally. Entropy is computed - using base 2 logarithm i.e. the filter returns the minimum number of - bits needed to encode local greylevel distribution. - - Parameters - ---------- - image : ndarray - Image array (uint8 array or uint16). If image is uint16, 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 - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - out : uint8 array or uint16 array (same as input image) - entropy x10 (uint8 images) and entropy x1000 (uint16 images) - - References - ---------- - .. [1] http://en.wikipedia.org/wiki/Entropy_(information_theory) - - Examples - -------- - >>> # Local entropy - >>> from skimage import data - >>> from skimage.filter.rank import entropy - >>> from skimage.morphology import disk - >>> # defining a 8- and a 16-bit test images - >>> a8 = data.camera() - >>> a16 = data.camera().astype(np.uint16) * 4 - >>> # pixel values contain 10x the local entropy - >>> ent8 = entropy(a8, disk(5)) - >>> # pixel values contain 1000x the local entropy - >>> ent16 = entropy(a16, disk(5)) - - """ - - return _apply(_crank8.entropy, _crank16.entropy, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) - - -def otsu(image, selem, out=None, mask=None, shift_x=False, shift_y=False): - """Returns the Otsu's threshold value for each pixel. - - Parameters - ---------- - image : ndarray - Image array (uint8 array). - selem : ndarray - The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray - If None, 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 : int - Offset added to the structuring element center point. Shift is bounded - to the structuring element sizes (center must be inside the given - structuring element). - - Returns - ------- - out : uint8 array - Otsu's threshold values - - References - ---------- - .. [otsu] http://en.wikipedia.org/wiki/Otsu's_method - - Notes - ----- - * input image are 8-bit only - - Examples - -------- - >>> # Local entropy - >>> from skimage import data - >>> from skimage.filter.rank import otsu - >>> from skimage.morphology import disk - >>> # defining a 8-bit test images - >>> a8 = data.camera() - >>> loc_otsu = otsu(a8, disk(5)) - >>> thresh_image = a8 >= loc_otsu - - """ - - return _apply(_crank8.otsu, None, image, selem, out=out, - mask=mask, shift_x=shift_x, shift_y=shift_y) diff --git a/skimage/filter/rank/bilateral_rank.pyx b/skimage/filter/rank/bilateral.py similarity index 96% rename from skimage/filter/rank/bilateral_rank.pyx rename to skimage/filter/rank/bilateral.py index e2a1fcf3..a111dd7c 100644 --- a/skimage/filter/rank/bilateral_rank.pyx +++ b/skimage/filter/rank/bilateral.py @@ -28,8 +28,8 @@ References import numpy as np from skimage import img_as_ubyte -from skimage.filter.rank import _crank16_bilateral -from skimage.filter.rank.generic import find_bitdepth +from . import bilateral16_cy +from .generic import find_bitdepth __all__ = ['bilateral_mean', 'bilateral_pop'] @@ -130,7 +130,7 @@ def bilateral_mean(image, selem, out=None, mask=None, shift_x=False, >>> bilat_ima = bilateral_mean(ima, disk(20), s0=10,s1=10) """ - return _apply(None, _crank16_bilateral.mean, image, selem, out=out, + return _apply(None, _bilateral16_cy.mean, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, s0=s0, s1=s1) @@ -188,5 +188,5 @@ def bilateral_pop(image, selem, out=None, mask=None, shift_x=False, """ - return _apply(None, _crank16_bilateral.pop, image, selem, out=out, + return _apply(None, _bilateral16_cy.pop, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, s0=s0, s1=s1) diff --git a/skimage/filter/rank/_crank16_bilateral.pyx b/skimage/filter/rank/bilateral16_cy.pyx similarity index 98% rename from skimage/filter/rank/_crank16_bilateral.pyx rename to skimage/filter/rank/bilateral16_cy.pyx index e431e42b..d9f68f73 100644 --- a/skimage/filter/rank/_crank16_bilateral.pyx +++ b/skimage/filter/rank/bilateral16_cy.pyx @@ -4,7 +4,7 @@ #cython: wraparound=False cimport numpy as cnp -from skimage.filter.rank._core16 cimport _core16 +from .core16_cy cimport _core16 # ----------------------------------------------------------------- diff --git a/skimage/filter/rank/_core16.pxd b/skimage/filter/rank/core16_cy.pxd similarity index 100% rename from skimage/filter/rank/_core16.pxd rename to skimage/filter/rank/core16_cy.pxd diff --git a/skimage/filter/rank/_core16.pyx b/skimage/filter/rank/core16_cy.pyx similarity index 99% rename from skimage/filter/rank/_core16.pyx rename to skimage/filter/rank/core16_cy.pyx index 0c7a7a82..63bcdff1 100644 --- a/skimage/filter/rank/_core16.pyx +++ b/skimage/filter/rank/core16_cy.pyx @@ -7,7 +7,7 @@ import numpy as np cimport numpy as cnp from libc.stdlib cimport malloc, free -from _core8 cimport is_in_mask +from .core8_cy cimport is_in_mask cdef inline int int_max(int a, int b): diff --git a/skimage/filter/rank/_core8.pxd b/skimage/filter/rank/core8_cy.pxd similarity index 100% rename from skimage/filter/rank/_core8.pxd rename to skimage/filter/rank/core8_cy.pxd diff --git a/skimage/filter/rank/_core8.pyx b/skimage/filter/rank/core8_cy.pyx similarity index 100% rename from skimage/filter/rank/_core8.pyx rename to skimage/filter/rank/core8_cy.pyx diff --git a/skimage/filter/rank/generic.py b/skimage/filter/rank/generic.py index 94fc3130..124d4f25 100644 --- a/skimage/filter/rank/generic.py +++ b/skimage/filter/rank/generic.py @@ -1,3 +1,31 @@ +"""The local histogram is computed using a sliding window similar to the method +described in [1]_. + +Input image can be 8-bit or 16-bit with a value < 4096 (i.e. 12 bit), for 16-bit +input images, the number of histogram bins is determined from the maximum value +present in the image. + +Result image is 8 or 16-bit with respect to the input image. + +References +---------- + +.. [1] Huang, T. ,Yang, G. ; Tang, G.. "A fast two-dimensional + median filtering algorithm", IEEE Transactions on Acoustics, Speech and + Signal Processing, Feb 1979. Volume: 27 , Issue: 1, Page(s): 13 - 18. + +""" + +import numpy as np +from skimage import img_as_ubyte, img_as_uint +from . import generic8_cy, generic16_cy + + +__all__ = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'maximum', 'mean', + 'meansubtraction', 'median', 'minimum', 'modal', 'morph_contr_enh', + 'pop', 'threshold', 'tophat', 'noise_filter', 'entropy', 'otsu'] + + import numpy as np @@ -9,3 +37,751 @@ def find_bitdepth(image): return int(np.log2(umax)) else: return 1 + + +def _apply(func8, func16, image, selem, out, mask, shift_x, shift_y): + selem = img_as_ubyte(selem > 0) + image = np.ascontiguousarray(image) + + if mask is None: + mask = np.ones(image.shape, dtype=np.uint8) + else: + mask = np.ascontiguousarray(mask) + mask = img_as_ubyte(mask) + + if image is out: + raise NotImplementedError("Cannot perform rank operation in place.") + + 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) + else: + image = img_as_uint(image) + if out is None: + out = np.zeros(image.shape, dtype=np.uint16) + bitdepth = find_bitdepth(image) + if bitdepth > 11: + image = image >> 4 + bitdepth = find_bitdepth(image) + func16(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, + bitdepth=bitdepth + 1, out=out) + + 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. + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + out : uint8 array or uint16 array (same as input image) + The result of the local autolevel. + + Examples + -------- + >>> from skimage import data + >>> from skimage.morphology import disk + >>> from skimage.filter.rank import autolevel + >>> # Load test image + >>> ima = data.camera() + >>> # Stretch image contrast locally + >>> auto = autolevel(ima, disk(20)) + + """ + + return _apply(generic8_cy.autolevel, generic16_cy.autolevel, image, selem, + out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + + +def bottomhat(image, selem, out=None, mask=None, shift_x=False, shift_y=False): + """Returns greyscale local bottomhat of an image. + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + local bottomhat : uint8 array or uint16 array depending on input image + The result of the local bottomhat. + + """ + + return _apply(generic8_cy.bottomhat, generic16_cy.bottomhat, image, selem, + out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + + +def equalize(image, selem, out=None, mask=None, shift_x=False, shift_y=False): + """Equalize image using local histogram. + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + out : uint8 array or uint16 array (same as input image) + The result of the local equalize. + + Examples + -------- + >>> from skimage import data + >>> from skimage.morphology import disk + >>> from skimage.filter.rank import equalize + >>> # Load test image + >>> ima = data.camera() + >>> # Local equalization + >>> equ = equalize(ima, disk(20)) + + """ + + return _apply(generic8_cy.equalize, generic16_cy.equalize, image, selem, + out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + + +def gradient(image, selem, out=None, mask=None, shift_x=False, shift_y=False): + """Return greyscale local gradient of an image (i.e. local maximum - local + minimum). + + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + out : uint8 array or uint16 array (same as input image) + The local gradient. + + """ + + return _apply(generic8_cy.gradient, generic16_cy.gradient, image, selem, + out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + + +def maximum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): + """Return greyscale local maximum of an image. + + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + out : uint8 array or uint16 array (same as input image) + The local maximum. + + See also + -------- + skimage.morphology.dilation + + Note + ---- + * input image can be 8-bit or 16-bit with a value < 4096 (i.e. 12 bit) + * the lower algorithm complexity makes the rank.maximum() more efficient for + larger images and structuring elements + + """ + + return _apply(generic8_cy.maximum, generic16_cy.maximum, image, selem, + out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + + +def mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False): + """Return greyscale local mean of an image. + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + out : uint8 array or uint16 array (same as input image) + The local mean. + + Examples + -------- + >>> from skimage import data + >>> from skimage.morphology import disk + >>> from skimage.filter.rank import mean + >>> # Load test image + >>> ima = data.camera() + >>> # Local mean + >>> avg = mean(ima, disk(20)) + + """ + + return _apply(generic8_cy.mean, generic16_cy.mean, image, selem, out=out, + mask=mask, shift_x=shift_x, shift_y=shift_y) + + +def meansubtraction(image, selem, out=None, mask=None, shift_x=False, + shift_y=False): + """Return image subtracted from its local mean. + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + out : uint8 array or uint16 array (same as input image) + The result of the local meansubtraction. + + """ + + return _apply(generic8_cy.meansubtraction, generic16_cy.meansubtraction, + image, selem, out=out, mask=mask, shift_x=shift_x, + shift_y=shift_y) + + +def median(image, selem, out=None, mask=None, shift_x=False, shift_y=False): + """Return greyscale local median of an image. + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + out : uint8 array or uint16 array (same as input image) + The local median. + + Examples + -------- + >>> from skimage import data + >>> from skimage.morphology import disk + >>> from skimage.filter.rank import median + >>> # Load test image + >>> ima = data.camera() + >>> # Local mean + >>> avg = median(ima, disk(20)) + + """ + + return _apply(generic8_cy.median, generic16_cy.median, image, selem, + out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + + +def minimum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): + """Return greyscale local minimum of an image. + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + out : uint8 array or uint16 array (same as input image) + The local minimum. + + See also + -------- + skimage.morphology.erosion + + Note + ---- + * input image can be 8-bit or 16-bit with a value < 4096 (i.e. 12 bit) + * the lower algorithm complexity makes the rank.minimum() more efficient + for larger images and structuring elements + + """ + + return _apply(generic8_cy.minimum, generic16_cy.minimum, image, selem, + out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + + +def modal(image, selem, out=None, mask=None, shift_x=False, shift_y=False): + """Return greyscale local mode of an image. + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + out : uint8 array or uint16 array (same as input image) + The local modal. + + """ + + return _apply(generic8_cy.modal, generic16_cy.modal, image, selem, + out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + + +def morph_contr_enh(image, selem, out=None, mask=None, shift_x=False, + shift_y=False): + """Enhance an image replacing each pixel by the local maximum if pixel + greylevel is closest to maximimum than local minimum OR local minimum + otherwise. + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + out : uint8 array or uint16 array (same as input image) + The result of the local morph_contr_enh. + + Examples + -------- + >>> from skimage import data + >>> from skimage.morphology import disk + >>> from skimage.filter.rank import morph_contr_enh + >>> # Load test image + >>> ima = data.camera() + >>> # Local mean + >>> avg = morph_contr_enh(ima, disk(20)) + + """ + + return _apply(generic8_cy.morph_contr_enh, generic16_cy.morph_contr_enh, + image, selem, out=out, mask=mask, shift_x=shift_x, + shift_y=shift_y) + + +def pop(image, selem, out=None, mask=None, shift_x=False, shift_y=False): + """Return the number (population) of pixels actually inside the + neighborhood. + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + out : uint8 array or uint16 array (same as input image) + The number of pixels belonging to the neighborhood. + + Examples + -------- + >>> # Local mean + >>> from skimage.morphology import square + >>> import skimage.filter.rank as rank + >>> ima = 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) + >>> rank.pop(ima, square(3)) + array([[4, 6, 6, 6, 4], + [6, 9, 9, 9, 6], + [6, 9, 9, 9, 6], + [6, 9, 9, 9, 6], + [4, 6, 6, 6, 4]], dtype=uint8) + + """ + + return _apply(generic8_cy.pop, generic16_cy.pop, image, selem, out=out, + mask=mask, shift_x=shift_x, shift_y=shift_y) + + +def threshold(image, selem, out=None, mask=None, shift_x=False, shift_y=False): + """Return greyscale local threshold of an image. + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + out : uint8 array or uint16 array (same as input image) + The result of the local threshold. + + Examples + -------- + >>> # Local threshold + >>> from skimage.morphology import square + >>> from skimage.filter.rank import threshold + >>> ima = 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) + >>> threshold(ima, square(3)) + array([[0, 0, 0, 0, 0], + [0, 1, 1, 1, 0], + [0, 1, 0, 1, 0], + [0, 1, 1, 1, 0], + [0, 0, 0, 0, 0]], dtype=uint8) + + """ + + return _apply(generic8_cy.threshold, generic16_cy.threshold, image, selem, + out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + + +def tophat(image, selem, out=None, mask=None, shift_x=False, shift_y=False): + """Return greyscale local tophat of an image. + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + out : uint8 array or uint16 array (same as input image) + The image tophat. + + """ + + return _apply(generic8_cy.tophat, generic16_cy.tophat, image, selem, + out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + + +def noise_filter(image, selem, out=None, mask=None, shift_x=False, + shift_y=False): + """Returns the noise feature as described in [Hashimoto12]_ + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + References + ---------- + .. [Hashimoto12] N. Hashimoto et al. Referenceless image quality evaluation + for whole slide imaging. J Pathol Inform 2012;3:9. + + Returns + ------- + out : uint8 array or uint16 array (same as input image) + The image noise. + + """ + + # ensure that the central pixel in the structuring element is empty + centre_r = int(selem.shape[0] / 2) + shift_y + centre_c = int(selem.shape[1] / 2) + shift_x + # make a local copy + selem_cpy = selem.copy() + selem_cpy[centre_r, centre_c] = 0 + + return _apply(generic8_cy.noise_filter, None, image, selem_cpy, out=out, + mask=mask, shift_x=shift_x, shift_y=shift_y) + + +def entropy(image, selem, out=None, mask=None, shift_x=False, shift_y=False): + """Returns the entropy [1]_ computed locally. Entropy is computed + using base 2 logarithm i.e. the filter returns the minimum number of + bits needed to encode local greylevel distribution. + + Parameters + ---------- + image : ndarray + Image array (uint8 array or uint16). If image is uint16, 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 + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + out : uint8 array or uint16 array (same as input image) + entropy x10 (uint8 images) and entropy x1000 (uint16 images) + + References + ---------- + .. [1] http://en.wikipedia.org/wiki/Entropy_(information_theory) + + Examples + -------- + >>> # Local entropy + >>> from skimage import data + >>> from skimage.filter.rank import entropy + >>> from skimage.morphology import disk + >>> # defining a 8- and a 16-bit test images + >>> a8 = data.camera() + >>> a16 = data.camera().astype(np.uint16) * 4 + >>> # pixel values contain 10x the local entropy + >>> ent8 = entropy(a8, disk(5)) + >>> # pixel values contain 1000x the local entropy + >>> ent16 = entropy(a16, disk(5)) + + """ + + return _apply(generic8_cy.entropy, generic16_cy.entropy, image, selem, + out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + + +def otsu(image, selem, out=None, mask=None, shift_x=False, shift_y=False): + """Returns the Otsu's threshold value for each pixel. + + Parameters + ---------- + image : ndarray + Image array (uint8 array). + selem : ndarray + The neighborhood expressed as a 2-D array of 1's and 0's. + out : ndarray + If None, 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 : int + Offset added to the structuring element center point. Shift is bounded + to the structuring element sizes (center must be inside the given + structuring element). + + Returns + ------- + out : uint8 array + Otsu's threshold values + + References + ---------- + .. [otsu] http://en.wikipedia.org/wiki/Otsu's_method + + Notes + ----- + * input image are 8-bit only + + Examples + -------- + >>> # Local entropy + >>> from skimage import data + >>> from skimage.filter.rank import otsu + >>> from skimage.morphology import disk + >>> # defining a 8-bit test images + >>> a8 = data.camera() + >>> loc_otsu = otsu(a8, disk(5)) + >>> thresh_image = a8 >= loc_otsu + + """ + + return _apply(generic8_cy.otsu, None, image, selem, out=out, + mask=mask, shift_x=shift_x, shift_y=shift_y) diff --git a/skimage/filter/rank/_crank16.pyx b/skimage/filter/rank/generic16_cy.pyx similarity index 99% rename from skimage/filter/rank/_crank16.pyx rename to skimage/filter/rank/generic16_cy.pyx index e704afe0..eace0afa 100644 --- a/skimage/filter/rank/_crank16.pyx +++ b/skimage/filter/rank/generic16_cy.pyx @@ -5,7 +5,7 @@ cimport numpy as cnp from libc.math cimport log -from skimage.filter.rank._core16 cimport _core16 +from .core16_cy cimport _core16 # ----------------------------------------------------------------- diff --git a/skimage/filter/rank/_crank8.pyx b/skimage/filter/rank/generic8_cy.pyx similarity index 99% rename from skimage/filter/rank/_crank8.pyx rename to skimage/filter/rank/generic8_cy.pyx index da511790..1cccc21f 100644 --- a/skimage/filter/rank/_crank8.pyx +++ b/skimage/filter/rank/generic8_cy.pyx @@ -5,7 +5,7 @@ cimport numpy as cnp from libc.math cimport log -from skimage.filter.rank._core8 cimport _core8 +from .core8_cy cimport _core8 # ----------------------------------------------------------------- diff --git a/skimage/filter/rank/percentile_rank.pyx b/skimage/filter/rank/percentile.py similarity index 94% rename from skimage/filter/rank/percentile_rank.pyx rename to skimage/filter/rank/percentile.py index 704f53c2..25758115 100644 --- a/skimage/filter/rank/percentile_rank.pyx +++ b/skimage/filter/rank/percentile.py @@ -24,8 +24,8 @@ References import numpy as np from skimage import img_as_ubyte -from skimage.filter.rank.generic import find_bitdepth -from skimage.filter.rank import _crank16_percentiles, _crank8_percentiles +from . import percentile8_cy, percentile16_cy +from .generic import find_bitdepth __all__ = ['percentile_autolevel', 'percentile_gradient', @@ -106,7 +106,7 @@ def percentile_autolevel(image, selem, out=None, mask=None, shift_x=False, """ return _apply( - _crank8_percentiles.autolevel, _crank16_percentiles.autolevel, + percentile8_cy.autolevel, percentile16_cy.autolevel, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1) @@ -146,7 +146,7 @@ def percentile_gradient(image, selem, out=None, mask=None, shift_x=False, """ - return _apply(_crank8_percentiles.gradient, _crank16_percentiles.gradient, + return _apply(percentile8_cy.gradient, percentile16_cy.gradient, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1) @@ -186,7 +186,7 @@ def percentile_mean(image, selem, out=None, mask=None, shift_x=False, """ - return _apply(_crank8_percentiles.mean, _crank16_percentiles.mean, + return _apply(percentile8_cy.mean, percentile16_cy.mean, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1) @@ -226,8 +226,8 @@ def percentile_mean_subtraction(image, selem, out=None, mask=None, """ - return _apply(_crank8_percentiles.mean_subtraction, - _crank16_percentiles.mean_subtraction, + return _apply(percentile8_cy.mean_subtraction, + percentile16_cy.mean_subtraction, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1) @@ -268,8 +268,8 @@ def percentile_morph_contr_enh( """ - return _apply(_crank8_percentiles.morph_contr_enh, - _crank16_percentiles.morph_contr_enh, + return _apply(percentile8_cy.morph_contr_enh, + percentile16_cy.morph_contr_enh, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1) @@ -308,8 +308,8 @@ def percentile(image, selem, out=None, mask=None, shift_x=False, shift_y=False, """ - return _apply(_crank8_percentiles.percentile, - _crank16_percentiles.percentile, + return _apply(percentile8_cy.percentile, + percentile16_cy.percentile, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=0.) @@ -349,7 +349,7 @@ def percentile_pop(image, selem, out=None, mask=None, shift_x=False, """ - return _apply(_crank8_percentiles.pop, _crank16_percentiles.pop, + return _apply(percentile8_cy.pop, percentile16_cy.pop, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1) @@ -391,6 +391,6 @@ def percentile_threshold(image, selem, out=None, mask=None, shift_x=False, """ return _apply( - _crank8_percentiles.threshold, _crank16_percentiles.threshold, + percentile8_cy.threshold, percentile16_cy.threshold, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=0.) diff --git a/skimage/filter/rank/_crank16_percentiles.pyx b/skimage/filter/rank/percentile16_cy.pyx similarity index 99% rename from skimage/filter/rank/_crank16_percentiles.pyx rename to skimage/filter/rank/percentile16_cy.pyx index f4a4c9b2..368bec0e 100644 --- a/skimage/filter/rank/_crank16_percentiles.pyx +++ b/skimage/filter/rank/percentile16_cy.pyx @@ -4,7 +4,7 @@ #cython: wraparound=False cimport numpy as cnp -from skimage.filter.rank._core16 cimport _core16, int_min, int_max +from .core16_cy cimport _core16, int_min, int_max # ----------------------------------------------------------------- diff --git a/skimage/filter/rank/_crank8_percentiles.pyx b/skimage/filter/rank/percentile8_cy.pyx similarity index 99% rename from skimage/filter/rank/_crank8_percentiles.pyx rename to skimage/filter/rank/percentile8_cy.pyx index 8e5cee9c..7f514f89 100644 --- a/skimage/filter/rank/_crank8_percentiles.pyx +++ b/skimage/filter/rank/percentile8_cy.pyx @@ -4,7 +4,7 @@ #cython: wraparound=False cimport numpy as cnp -from skimage.filter.rank._core8 cimport _core8, uint8_max, uint8_min +from .core8_cy cimport _core8, uint8_max, uint8_min # ----------------------------------------------------------------- diff --git a/skimage/filter/setup.py b/skimage/filter/setup.py index c70730f0..35626114 100644 --- a/skimage/filter/setup.py +++ b/skimage/filter/setup.py @@ -14,46 +14,39 @@ def configuration(parent_package='', top_path=None): cython(['_ctmf.pyx'], working_path=base_path) cython(['_denoise_cy.pyx'], working_path=base_path) - cython(['rank/_core8.pyx'], working_path=base_path) - cython(['rank/_core16.pyx'], working_path=base_path) - cython(['rank/_crank8.pyx'], working_path=base_path) - cython(['rank/_crank8_percentiles.pyx'], working_path=base_path) - cython(['rank/_crank16.pyx'], working_path=base_path) - cython(['rank/_crank16_percentiles.pyx'], working_path=base_path) - cython(['rank/_crank16_bilateral.pyx'], working_path=base_path) - cython(['rank/percentile_rank.pyx'], working_path=base_path) - cython(['rank/bilateral_rank.pyx'], working_path=base_path) + cython(['rank/core8_cy.pyx'], working_path=base_path) + cython(['rank/core16_cy.pyx'], working_path=base_path) + cython(['rank/generic8_cy.pyx'], working_path=base_path) + cython(['rank/percentile8_cy.pyx'], working_path=base_path) + cython(['rank/generic16_cy.pyx'], working_path=base_path) + cython(['rank/percentile16_cy.pyx'], working_path=base_path) + cython(['rank/bilateral16_cy.pyx'], working_path=base_path) config.add_extension('_ctmf', sources=['_ctmf.c'], include_dirs=[get_numpy_include_dirs()]) config.add_extension('_denoise_cy', sources=['_denoise_cy.c'], include_dirs=[get_numpy_include_dirs(), '../_shared']) - config.add_extension('rank._core8', sources=['rank/_core8.c'], + config.add_extension('rank.core8_cy', sources=['rank/core8_cy.c'], include_dirs=[get_numpy_include_dirs()]) - config.add_extension('rank._core16', sources=['rank/_core16.c'], + config.add_extension('rank.core16_cy', sources=['rank/core16_cy.c'], include_dirs=[get_numpy_include_dirs()]) - config.add_extension('rank._crank8', sources=['rank/_crank8.c'], + config.add_extension('rank.generic8_cy', sources=['rank/generic8_cy.c'], include_dirs=[get_numpy_include_dirs()]) config.add_extension( - 'rank._crank8_percentiles', sources=['rank/_crank8_percentiles.c'], + 'rank.percentile8_cy', sources=['rank/percentile8_cy.c'], include_dirs=[get_numpy_include_dirs()]) - config.add_extension('rank._crank16', sources=['rank/_crank16.c'], + config.add_extension('rank.generic16_cy', sources=['rank/generic16_cy.c'], include_dirs=[get_numpy_include_dirs()]) config.add_extension( - 'rank._crank16_percentiles', sources=['rank/_crank16_percentiles.c'], + 'rank.percentile16_cy', sources=['rank/percentile16_cy.c'], include_dirs=[get_numpy_include_dirs()]) config.add_extension( - 'rank._crank16_bilateral', sources=['rank/_crank16_bilateral.c'], - include_dirs=[get_numpy_include_dirs()]) - config.add_extension( - 'rank.percentile_rank', sources=['rank/percentile_rank.c'], - include_dirs=[get_numpy_include_dirs()]) - config.add_extension( - 'rank.bilateral_rank', sources=['rank/bilateral_rank.c'], + 'rank.bilateral16_cy', sources=['rank/bilateral16_cy.c'], include_dirs=[get_numpy_include_dirs()]) return config + if __name__ == '__main__': from numpy.distutils.core import setup setup(maintainer='scikit-image Developers', From 2641df3497bc65d5d98c3365e8f3862b24499648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 10:41:04 +0200 Subject: [PATCH 02/43] Use typed memoryviews in rank filter package --- skimage/filter/rank/core16_cy.pxd | 12 +- skimage/filter/rank/core16_cy.pyx | 74 ++++++------ skimage/filter/rank/core8_cy.pxd | 10 +- skimage/filter/rank/core8_cy.pyx | 67 +++++------ skimage/filter/rank/generic16_cy.pyx | 126 ++++++++++----------- skimage/filter/rank/generic8_cy.pyx | 143 ++++++++++++------------ skimage/filter/rank/percentile16_cy.pyx | 72 ++++++------ skimage/filter/rank/percentile8_cy.pyx | 69 ++++++------ 8 files changed, 275 insertions(+), 298 deletions(-) diff --git a/skimage/filter/rank/core16_cy.pxd b/skimage/filter/rank/core16_cy.pxd index 5586aea1..f13f0fd1 100644 --- a/skimage/filter/rank/core16_cy.pxd +++ b/skimage/filter/rank/core16_cy.pxd @@ -4,17 +4,17 @@ cimport numpy as cnp ctypedef cnp.uint16_t dtype_t -cdef int int_max(int a, int b) -cdef int int_min(int a, int b) +cdef dtype_t uint16_max(dtype_t a, dtype_t b) +cdef dtype_t uint16_min(dtype_t a, dtype_t b) # 16-bit core kernel receives extra information about data bitdepth cdef void _core16(dtype_t kernel(Py_ssize_t *, float, dtype_t, Py_ssize_t, Py_ssize_t, Py_ssize_t, float, float, Py_ssize_t, Py_ssize_t), - cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask, - cnp.ndarray[dtype_t, ndim=2] out, + dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, char shift_x, char shift_y, Py_ssize_t bitdepth, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1) except * diff --git a/skimage/filter/rank/core16_cy.pyx b/skimage/filter/rank/core16_cy.pyx index 63bcdff1..25592d39 100644 --- a/skimage/filter/rank/core16_cy.pyx +++ b/skimage/filter/rank/core16_cy.pyx @@ -10,33 +10,33 @@ from libc.stdlib cimport malloc, free from .core8_cy cimport is_in_mask -cdef inline int int_max(int a, int b): +cdef inline dtype_t uint16_max(dtype_t a, dtype_t b): return a if a >= b else b -cdef inline int int_min(int a, int b): +cdef inline dtype_t uint16_min(dtype_t a, dtype_t b): return a if a <= b else b -cdef inline void histogram_increment(Py_ssize_t * histo, float * pop, +cdef inline void histogram_increment(Py_ssize_t* histo, float* pop, dtype_t value): histo[value] += 1 pop[0] += 1 -cdef inline void histogram_decrement(Py_ssize_t * histo, float * pop, +cdef inline void histogram_decrement(Py_ssize_t* histo, float* pop, dtype_t value): histo[value] -= 1 pop[0] -= 1 -cdef void _core16(dtype_t kernel(Py_ssize_t *, float, dtype_t, +cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, Py_ssize_t, Py_ssize_t, Py_ssize_t, float, float, Py_ssize_t, Py_ssize_t), - cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask, - cnp.ndarray[dtype_t, ndim=2] out, + dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, char shift_x, char shift_y, Py_ssize_t bitdepth, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1) except *: """Compute histogram for each pixel neighborhood, apply kernel function and @@ -65,12 +65,8 @@ cdef void _core16(dtype_t kernel(Py_ssize_t *, float, dtype_t, cdef Py_ssize_t maxbin = maxbin_list[bitdepth] cdef Py_ssize_t midbin = midbin_list[bitdepth] - assert (image < maxbin).all() - # define pointers to the data - cdef dtype_t * out_data = out.data - cdef dtype_t * image_data = image.data - cdef cnp.uint8_t * mask_data = mask.data + cdef char* mask_data = &mask[0, 0] # define local variable types cdef Py_ssize_t r, c, rr, cc, s, value, local_max, i, even_row @@ -84,19 +80,19 @@ cdef void _core16(dtype_t kernel(Py_ssize_t *, float, dtype_t, cdef Py_ssize_t num_se_n, num_se_s, num_se_e, num_se_w # the current local histogram distribution - cdef Py_ssize_t * histo = malloc(maxbin * sizeof(Py_ssize_t)) + cdef Py_ssize_t* histo = malloc(maxbin * sizeof(Py_ssize_t)) # these lists contain the relative pixel row and column for each of the 4 # attack borders east, west, north and south e.g. se_e_r lists the rows of # the east structuring element border - cdef Py_ssize_t * se_e_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_e_c = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_w_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_w_c = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_n_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_n_c = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_s_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_s_c = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_e_r = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_e_c = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_w_r = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_w_c = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_n_r = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_n_c = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_s_r = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_s_c = malloc(max_se * sizeof(Py_ssize_t)) # build attack and release borders # by using difference along axis @@ -145,12 +141,12 @@ cdef void _core16(dtype_t kernel(Py_ssize_t *, float, dtype_t, cc = c - centre_c if selem[r, c]: if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_increment(histo, &pop, image_data[rr * cols + cc]) + histogram_increment(histo, &pop, image[rr, cc]) r = 0 c = 0 # kernel ------------------------------------------- - out_data[r * cols + c] = kernel(histo, pop, image_data[r * cols + c], + out[r, c] = kernel(histo, pop, image[r, c], bitdepth, maxbin, midbin, p0, p1, s0, s1) # kernel ------------------------------------------- @@ -163,17 +159,17 @@ cdef void _core16(dtype_t kernel(Py_ssize_t *, float, dtype_t, rr = r + se_e_r[s] cc = c + se_e_c[s] if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_increment(histo, &pop, image_data[rr * cols + cc]) + histogram_increment(histo, &pop, image[rr, cc]) for s in range(num_se_w): rr = r + se_w_r[s] cc = c + se_w_c[s] - 1 if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_decrement(histo, &pop, image_data[rr * cols + cc]) + histogram_decrement(histo, &pop, image[rr, cc]) # kernel ------------------------------------------- - out_data[r * cols + c] = kernel( - histo, pop, image_data[r * cols + c], + out[r, c] = kernel( + histo, pop, image[r, c], bitdepth, maxbin, midbin, p0, p1, s0, s1) # kernel ------------------------------------------- @@ -186,16 +182,16 @@ cdef void _core16(dtype_t kernel(Py_ssize_t *, float, dtype_t, rr = r + se_s_r[s] cc = c + se_s_c[s] if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_increment(histo, &pop, image_data[rr * cols + cc]) + histogram_increment(histo, &pop, image[rr, cc]) for s in range(num_se_n): rr = r + se_n_r[s] - 1 cc = c + se_n_c[s] if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_decrement(histo, &pop, image_data[rr * cols + cc]) + histogram_decrement(histo, &pop, image[rr, cc]) # kernel ------------------------------------------- - out_data[r * cols + c] = kernel(histo, pop, image_data[r * cols + c], + out[r, c] = kernel(histo, pop, image[r, c], bitdepth, maxbin, midbin, p0, p1, s0, s1) # kernel ------------------------------------------- @@ -205,17 +201,17 @@ cdef void _core16(dtype_t kernel(Py_ssize_t *, float, dtype_t, rr = r + se_w_r[s] cc = c + se_w_c[s] if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_increment(histo, &pop, image_data[rr * cols + cc]) + histogram_increment(histo, &pop, image[rr, cc]) for s in range(num_se_e): rr = r + se_e_r[s] cc = c + se_e_c[s] + 1 if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_decrement(histo, &pop, image_data[rr * cols + cc]) + histogram_decrement(histo, &pop, image[rr, cc]) # kernel ------------------------------------------- - out_data[r * cols + c] = kernel( - histo, pop, image_data[r * cols + c], + out[r, c] = kernel( + histo, pop, image[r, c], bitdepth, maxbin, midbin, p0, p1, s0, s1) # kernel ------------------------------------------- @@ -228,16 +224,16 @@ cdef void _core16(dtype_t kernel(Py_ssize_t *, float, dtype_t, rr = r + se_s_r[s] cc = c + se_s_c[s] if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_increment(histo, &pop, image_data[rr * cols + cc]) + histogram_increment(histo, &pop, image[rr, cc]) for s in range(num_se_n): rr = r + se_n_r[s] - 1 cc = c + se_n_c[s] if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_decrement(histo, &pop, image_data[rr * cols + cc]) + histogram_decrement(histo, &pop, image[rr, cc]) # kernel ------------------------------------------- - out_data[r * cols + c] = kernel(histo, pop, image_data[r * cols + c], + out[r, c] = kernel(histo, pop, image[r, c], bitdepth, maxbin, midbin, p0, p1, s0, s1) # kernel ------------------------------------------- diff --git a/skimage/filter/rank/core8_cy.pxd b/skimage/filter/rank/core8_cy.pxd index d3b6d8c2..8d7f9744 100644 --- a/skimage/filter/rank/core8_cy.pxd +++ b/skimage/filter/rank/core8_cy.pxd @@ -10,16 +10,16 @@ cdef dtype_t uint8_min(dtype_t a, dtype_t b) cdef dtype_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols, Py_ssize_t r, Py_ssize_t c, - dtype_t * mask) + char* mask) # 8-bit core kernel receives extra information about data inferior and superior # percentiles cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, float, Py_ssize_t, Py_ssize_t), - cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask, - cnp.ndarray[dtype_t, ndim=2] out, + dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, char shift_x, char shift_y, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1) except * diff --git a/skimage/filter/rank/core8_cy.pyx b/skimage/filter/rank/core8_cy.pyx index 79ae9bbf..b8d49a0f 100644 --- a/skimage/filter/rank/core8_cy.pyx +++ b/skimage/filter/rank/core8_cy.pyx @@ -31,7 +31,7 @@ cdef inline void histogram_decrement(Py_ssize_t * histo, float * pop, cdef inline dtype_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols, Py_ssize_t r, Py_ssize_t c, - dtype_t * mask): + char* mask): """Check whether given coordinate is within image and mask is true.""" if r < 0 or r > rows - 1 or c < 0 or c > cols - 1: return 0 @@ -44,10 +44,10 @@ cdef inline dtype_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols, cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, float, Py_ssize_t, Py_ssize_t), - cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask, - cnp.ndarray[dtype_t, ndim=2] out, + dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, char shift_x, char shift_y, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1) except *: """Compute histogram for each pixel neighborhood, apply kernel function and @@ -68,11 +68,7 @@ cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, assert centre_r < srows assert centre_c < scols - # define pointers to the data - - cdef dtype_t * out_data = out.data - cdef dtype_t * image_data = image.data - cdef dtype_t * mask_data = mask.data + cdef char* mask_data = &mask[0, 0] # define local variable types cdef Py_ssize_t r, c, rr, cc, s, value, local_max, i, even_row @@ -87,19 +83,19 @@ cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, cdef Py_ssize_t num_se_n, num_se_s, num_se_e, num_se_w # the current local histogram distribution - cdef Py_ssize_t * histo = malloc(256 * sizeof(Py_ssize_t)) + cdef Py_ssize_t * histo = malloc(256 * sizeof(Py_ssize_t)) # these lists contain the relative pixel row and column for each of the 4 # attack borders east, west, north and south e.g. se_e_r lists the rows of # the east structuring element border - cdef Py_ssize_t * se_e_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_e_c = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_w_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_w_c = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_n_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_n_c = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_s_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_s_c = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t * se_e_r = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t * se_e_c = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t * se_w_r = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t * se_w_c = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t * se_n_r = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t * se_n_c = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t * se_s_r = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t * se_s_c = malloc(max_se * sizeof(Py_ssize_t)) # build attack and release borders # by using difference along axis @@ -149,12 +145,12 @@ cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, cc = c - centre_c if selem[r, c]: if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_increment(histo, &pop, image_data[rr * cols + cc]) + histogram_increment(histo, &pop, image[rr, cc]) r = 0 c = 0 # kernel ------------------------------------------------------------------- - out_data[r * cols + c] = kernel(histo, pop, image_data[r * cols + c], + out[r, c] = kernel(histo, pop, image[r, c], p0, p1, s0, s1) # kernel ------------------------------------------------------------------- @@ -167,17 +163,17 @@ cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, rr = r + se_e_r[s] cc = c + se_e_c[s] if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_increment(histo, &pop, image_data[rr * cols + cc]) + histogram_increment(histo, &pop, image[rr, cc]) for s in range(num_se_w): rr = r + se_w_r[s] cc = c + se_w_c[s] - 1 if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_decrement(histo, &pop, image_data[rr * cols + cc]) + histogram_decrement(histo, &pop, image[rr, cc]) # kernel ----------------------------------------------------------- - out_data[r * cols + c] = \ - kernel(histo, pop, image_data[r * cols + c], p0, p1, s0, s1) + out[r, c] = \ + kernel(histo, pop, image[r, c], p0, p1, s0, s1) # kernel ----------------------------------------------------------- r += 1 # pass to the next row @@ -189,16 +185,16 @@ cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, rr = r + se_s_r[s] cc = c + se_s_c[s] if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_increment(histo, &pop, image_data[rr * cols + cc]) + histogram_increment(histo, &pop, image[rr, cc]) for s in range(num_se_n): rr = r + se_n_r[s] - 1 cc = c + se_n_c[s] if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_decrement(histo, &pop, image_data[rr * cols + cc]) + histogram_decrement(histo, &pop, image[rr, cc]) # kernel --------------------------------------------------------------- - out_data[r * cols + c] = kernel(histo, pop, image_data[r * cols + c], + out[r, c] = kernel(histo, pop, image[r, c], p0, p1, s0, s1) # kernel --------------------------------------------------------------- @@ -208,17 +204,17 @@ cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, rr = r + se_w_r[s] cc = c + se_w_c[s] if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_increment(histo, &pop, image_data[rr * cols + cc]) + histogram_increment(histo, &pop, image[rr, cc]) for s in range(num_se_e): rr = r + se_e_r[s] cc = c + se_e_c[s] + 1 if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_decrement(histo, &pop, image_data[rr * cols + cc]) + histogram_decrement(histo, &pop, image[rr, cc]) # kernel ----------------------------------------------------------- - out_data[r * cols + c] = kernel( - histo, pop, image_data[r * cols + c], p0, p1, s0, s1) + out[r, c] = kernel( + histo, pop, image[r, c], p0, p1, s0, s1) # kernel ----------------------------------------------------------- r += 1 # pass to the next row @@ -230,21 +226,20 @@ cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, rr = r + se_s_r[s] cc = c + se_s_c[s] if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_increment(histo, &pop, image_data[rr * cols + cc]) + histogram_increment(histo, &pop, image[rr, cc]) for s in range(num_se_n): rr = r + se_n_r[s] - 1 cc = c + se_n_c[s] if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_decrement(histo, &pop, image_data[rr * cols + cc]) + histogram_decrement(histo, &pop, image[rr, cc]) # kernel --------------------------------------------------------------- - out_data[r * cols + c] = kernel(histo, pop, image_data[r * cols + c], + out[r, c] = kernel(histo, pop, image[r, c], p0, p1, s0, s1) # kernel --------------------------------------------------------------- # release memory allocated by malloc - free(se_e_r) free(se_e_c) free(se_w_r) diff --git a/skimage/filter/rank/generic16_cy.pyx b/skimage/filter/rank/generic16_cy.pyx index eace0afa..7b2a8088 100644 --- a/skimage/filter/rank/generic16_cy.pyx +++ b/skimage/filter/rank/generic16_cy.pyx @@ -5,17 +5,13 @@ cimport numpy as cnp from libc.math cimport log -from .core16_cy cimport _core16 +from .core16_cy cimport dtype_t, _core16 # ----------------------------------------------------------------- # kernels uint16 take extra parameter for defining the bitdepth # ----------------------------------------------------------------- - -ctypedef cnp.uint16_t dtype_t - - cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, @@ -287,136 +283,136 @@ cdef inline dtype_t kernel_entropy(Py_ssize_t * histo, float pop, # ----------------------------------------------------------------- -def autolevel(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def autolevel(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): _core16(kernel_autolevel, image, selem, mask, out, shift_x, shift_y, bitdepth, 0, 0, 0, 0) -def bottomhat(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def bottomhat(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): _core16(kernel_bottomhat, image, selem, mask, out, shift_x, shift_y, bitdepth, 0, 0, 0, 0) -def equalize(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def equalize(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): _core16(kernel_equalize, image, selem, mask, out, shift_x, shift_y, bitdepth, 0, 0, 0, 0) -def gradient(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def gradient(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): _core16(kernel_gradient, image, selem, mask, out, shift_x, shift_y, bitdepth, 0, 0, 0, 0) -def maximum(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def maximum(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): _core16(kernel_maximum, image, selem, mask, out, shift_x, shift_y, bitdepth, 0, 0, 0, 0) -def mean(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def mean(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): _core16(kernel_mean, image, selem, mask, out, shift_x, shift_y, bitdepth, 0, 0, 0, 0) -def meansubtraction(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def meansubtraction(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): _core16(kernel_meansubtraction, image, selem, mask, out, shift_x, shift_y, bitdepth, 0, 0, 0, 0) -def median(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def median(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): _core16(kernel_median, image, selem, mask, out, shift_x, shift_y, bitdepth, 0, 0, 0, 0) -def minimum(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def minimum(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): _core16(kernel_minimum, image, selem, mask, out, shift_x, shift_y, bitdepth, 0, 0, 0, 0) -def morph_contr_enh(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def morph_contr_enh(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): _core16(kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y, bitdepth, 0, 0, 0, 0) -def modal(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def modal(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): _core16(kernel_modal, image, selem, mask, out, shift_x, shift_y, bitdepth, 0, 0, 0, 0) -def pop(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def pop(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): _core16(kernel_pop, image, selem, mask, out, shift_x, shift_y, bitdepth, 0, 0, 0, 0) -def threshold(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def threshold(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): _core16(kernel_threshold, image, selem, mask, out, shift_x, shift_y, bitdepth, 0, 0, 0, 0) -def tophat(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def tophat(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): _core16(kernel_tophat, image, selem, mask, out, shift_x, shift_y, bitdepth, 0, 0, 0, 0) -def entropy(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def entropy(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): _core16(kernel_entropy, image, selem, mask, out, shift_x, shift_y, bitdepth, 0, 0, 0, 0) diff --git a/skimage/filter/rank/generic8_cy.pyx b/skimage/filter/rank/generic8_cy.pyx index 1cccc21f..62749041 100644 --- a/skimage/filter/rank/generic8_cy.pyx +++ b/skimage/filter/rank/generic8_cy.pyx @@ -5,7 +5,7 @@ cimport numpy as cnp from libc.math cimport log -from .core8_cy cimport _core8 +from .core8_cy cimport dtype_t, _core8 # ----------------------------------------------------------------- @@ -13,9 +13,6 @@ from .core8_cy cimport _core8 # ----------------------------------------------------------------- -ctypedef cnp.uint8_t dtype_t - - cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -330,154 +327,154 @@ cdef inline dtype_t kernel_otsu(Py_ssize_t * histo, float pop, dtype_t g, # ----------------------------------------------------------------- -def autolevel(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def autolevel(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_autolevel, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def bottomhat(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def bottomhat(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_bottomhat, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def equalize(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def equalize(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_equalize, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def gradient(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def gradient(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_gradient, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def maximum(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def maximum(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_maximum, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def mean(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def mean(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_mean, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def meansubtraction(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, - char shift_x=0, char shift_y=0): +def meansubtraction(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, + char shift_x=0, char shift_y=0): _core8(kernel_meansubtraction, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def median(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def median(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_median, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def minimum(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def minimum(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_minimum, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def morph_contr_enh(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def morph_contr_enh(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def modal(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def modal(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_modal, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def pop(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def pop(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_pop, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def threshold(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def threshold(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_threshold, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def tophat(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def tophat(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_tophat, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def noise_filter(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def noise_filter(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_noise_filter, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def entropy(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def entropy(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_entropy, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) -def otsu(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def otsu(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0): _core8(kernel_otsu, image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0) diff --git a/skimage/filter/rank/percentile16_cy.pyx b/skimage/filter/rank/percentile16_cy.pyx index 368bec0e..8680aae4 100644 --- a/skimage/filter/rank/percentile16_cy.pyx +++ b/skimage/filter/rank/percentile16_cy.pyx @@ -4,17 +4,13 @@ #cython: wraparound=False cimport numpy as cnp -from .core16_cy cimport _core16, int_min, int_max +from .core16_cy cimport dtype_t, _core16, uint16_min, uint16_max # ----------------------------------------------------------------- # kernels uint16 (SOFT version using percentiles) # ----------------------------------------------------------------- - -ctypedef cnp.uint16_t dtype_t - - cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, @@ -41,7 +37,7 @@ cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop, delta = imax - imin if delta > 0: return (1.0 * (maxbin - 1) - * (int_min(int_max(imin, g), imax) + * (uint16_min(uint16_max(imin, g), imax) - imin) / delta) else: return (imax - imin) @@ -233,10 +229,10 @@ cdef inline dtype_t kernel_threshold(Py_ssize_t * histo, float pop, # ----------------------------------------------------------------- -def autolevel(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def autolevel(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0., float p1=0.): """bottom hat @@ -245,10 +241,10 @@ def autolevel(cnp.ndarray[dtype_t, ndim=2] image, bitdepth, p0, p1, 0, 0) -def gradient(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def gradient(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0., float p1=0.): """return p0,p1 percentile gradient @@ -257,10 +253,10 @@ def gradient(cnp.ndarray[dtype_t, ndim=2] image, bitdepth, p0, p1, 0, 0) -def mean(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def mean(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0., float p1=0.): """return mean between [p0 and p1] percentiles @@ -269,10 +265,10 @@ def mean(cnp.ndarray[dtype_t, ndim=2] image, bitdepth, p0, p1, 0, 0) -def mean_subtraction(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def mean_subtraction(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0., float p1=0.): """return original - mean between [p0 and p1] percentiles *.5 +127 @@ -282,10 +278,10 @@ def mean_subtraction(cnp.ndarray[dtype_t, ndim=2] image, bitdepth, p0, p1, 0, 0) -def morph_contr_enh(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def morph_contr_enh(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0., float p1=0.): """reforce contrast using percentiles @@ -294,10 +290,10 @@ def morph_contr_enh(cnp.ndarray[dtype_t, ndim=2] image, bitdepth, p0, p1, 0, 0) -def percentile(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def percentile(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0.): """return p0 percentile @@ -306,10 +302,10 @@ def percentile(cnp.ndarray[dtype_t, ndim=2] image, bitdepth, p0, .0, 0, 0) -def pop(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def pop(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0., float p1=0.): """return nb of pixels between [p0 and p1] @@ -318,10 +314,10 @@ def pop(cnp.ndarray[dtype_t, ndim=2] image, bitdepth, p0, p1, 0, 0) -def threshold(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def threshold(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0.): """return (maxbin-1) if g > percentile p0 diff --git a/skimage/filter/rank/percentile8_cy.pyx b/skimage/filter/rank/percentile8_cy.pyx index 7f514f89..6c37cf66 100644 --- a/skimage/filter/rank/percentile8_cy.pyx +++ b/skimage/filter/rank/percentile8_cy.pyx @@ -4,7 +4,7 @@ #cython: wraparound=False cimport numpy as cnp -from .core8_cy cimport _core8, uint8_max, uint8_min +from .core8_cy cimport dtype_t, _core8, uint8_max, uint8_min # ----------------------------------------------------------------- @@ -12,9 +12,6 @@ from .core8_cy cimport _core8, uint8_max, uint8_min # ----------------------------------------------------------------- -ctypedef cnp.uint8_t dtype_t - - cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -206,10 +203,10 @@ cdef inline dtype_t kernel_threshold(Py_ssize_t * histo, float pop, # ----------------------------------------------------------------- -def autolevel(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def autolevel(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, float p0=0., float p1=0.): """autolevel """ @@ -217,10 +214,10 @@ def autolevel(cnp.ndarray[dtype_t, ndim=2] image, 0, 0) -def gradient(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def gradient(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, float p0=0., float p1=0.): """return p0,p1 percentile gradient """ @@ -228,10 +225,10 @@ def gradient(cnp.ndarray[dtype_t, ndim=2] image, 0, 0) -def mean(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def mean(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, float p0=0., float p1=0.): """return mean between [p0 and p1] percentiles """ @@ -239,10 +236,10 @@ def mean(cnp.ndarray[dtype_t, ndim=2] image, 0, 0) -def mean_subtraction(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def mean_subtraction(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, float p0=0., float p1=0.): """return original - mean between [p0 and p1] percentiles *.5 +127 """ @@ -250,10 +247,10 @@ def mean_subtraction(cnp.ndarray[dtype_t, ndim=2] image, p0, p1, 0, 0) -def morph_contr_enh(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def morph_contr_enh(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, float p0=0., float p1=0.): """reforce contrast using percentiles """ @@ -261,10 +258,10 @@ def morph_contr_enh(cnp.ndarray[dtype_t, ndim=2] image, p0, p1, 0, 0) -def percentile(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def percentile(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, float p0=0.): """return p0 percentile """ @@ -272,10 +269,10 @@ def percentile(cnp.ndarray[dtype_t, ndim=2] image, p0, 0., 0, 0) -def pop(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def pop(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, float p0=0., float p1=0.): """return nb of pixels between [p0 and p1] """ @@ -283,10 +280,10 @@ def pop(cnp.ndarray[dtype_t, ndim=2] image, 0, 0) -def threshold(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[dtype_t, ndim=2] selem, - cnp.ndarray[dtype_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def threshold(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, float p0=0.): """return 255 if g > percentile p0 """ From d251fd88919013d3a0665ba93445c0c54eef21af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 10:47:13 +0200 Subject: [PATCH 03/43] Improve code layout and styling --- skimage/filter/rank/bilateral16_cy.pyx | 4 +- skimage/filter/rank/core16_cy.pxd | 2 +- skimage/filter/rank/core16_cy.pyx | 21 ++++------ skimage/filter/rank/core8_cy.pxd | 2 +- skimage/filter/rank/core8_cy.pyx | 56 ++++++++++++------------- skimage/filter/rank/generic16_cy.pyx | 30 ++++++------- skimage/filter/rank/generic8_cy.pyx | 34 +++++++-------- skimage/filter/rank/percentile16_cy.pyx | 16 +++---- skimage/filter/rank/percentile8_cy.pyx | 16 +++---- 9 files changed, 87 insertions(+), 94 deletions(-) diff --git a/skimage/filter/rank/bilateral16_cy.pyx b/skimage/filter/rank/bilateral16_cy.pyx index d9f68f73..63a89453 100644 --- a/skimage/filter/rank/bilateral16_cy.pyx +++ b/skimage/filter/rank/bilateral16_cy.pyx @@ -15,7 +15,7 @@ from .core16_cy cimport _core16 ctypedef cnp.uint16_t dtype_t -cdef inline dtype_t kernel_mean(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -37,7 +37,7 @@ cdef inline dtype_t kernel_mean(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_pop(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, diff --git a/skimage/filter/rank/core16_cy.pxd b/skimage/filter/rank/core16_cy.pxd index f13f0fd1..cebf0aab 100644 --- a/skimage/filter/rank/core16_cy.pxd +++ b/skimage/filter/rank/core16_cy.pxd @@ -9,7 +9,7 @@ cdef dtype_t uint16_min(dtype_t a, dtype_t b) # 16-bit core kernel receives extra information about data bitdepth -cdef void _core16(dtype_t kernel(Py_ssize_t *, float, dtype_t, +cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, Py_ssize_t, Py_ssize_t, Py_ssize_t, float, float, Py_ssize_t, Py_ssize_t), dtype_t[:, ::1] image, diff --git a/skimage/filter/rank/core16_cy.pyx b/skimage/filter/rank/core16_cy.pyx index 25592d39..02acc93d 100644 --- a/skimage/filter/rank/core16_cy.pyx +++ b/skimage/filter/rank/core16_cy.pyx @@ -146,8 +146,8 @@ cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, r = 0 c = 0 # kernel ------------------------------------------- - out[r, c] = kernel(histo, pop, image[r, c], - bitdepth, maxbin, midbin, p0, p1, s0, s1) + out[r, c] = kernel(histo, pop, image[r, c], bitdepth, maxbin, midbin, + p0, p1, s0, s1) # kernel ------------------------------------------- # main loop @@ -168,9 +168,8 @@ cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, histogram_decrement(histo, &pop, image[rr, cc]) # kernel ------------------------------------------- - out[r, c] = kernel( - histo, pop, image[r, c], - bitdepth, maxbin, midbin, p0, p1, s0, s1) + out[r, c] = kernel(histo, pop, image[r, c], bitdepth, maxbin, + midbin, p0, p1, s0, s1) # kernel ------------------------------------------- r += 1 # pass to the next row @@ -192,7 +191,7 @@ cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, # kernel ------------------------------------------- out[r, c] = kernel(histo, pop, image[r, c], - bitdepth, maxbin, midbin, p0, p1, s0, s1) + bitdepth, maxbin, midbin, p0, p1, s0, s1) # kernel ------------------------------------------- # ---> east to west @@ -210,9 +209,8 @@ cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, histogram_decrement(histo, &pop, image[rr, cc]) # kernel ------------------------------------------- - out[r, c] = kernel( - histo, pop, image[r, c], - bitdepth, maxbin, midbin, p0, p1, s0, s1) + out[r, c] = kernel(histo, pop, image[r, c], bitdepth, maxbin, + midbin, p0, p1, s0, s1) # kernel ------------------------------------------- r += 1 # pass to the next row @@ -233,12 +231,11 @@ cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, histogram_decrement(histo, &pop, image[rr, cc]) # kernel ------------------------------------------- - out[r, c] = kernel(histo, pop, image[r, c], - bitdepth, maxbin, midbin, p0, p1, s0, s1) + out[r, c] = kernel(histo, pop, image[r, c], bitdepth, maxbin, midbin, + p0, p1, s0, s1) # kernel ------------------------------------------- # release memory allocated by malloc - free(se_e_r) free(se_e_c) free(se_w_r) diff --git a/skimage/filter/rank/core8_cy.pxd b/skimage/filter/rank/core8_cy.pxd index 8d7f9744..c2b709d4 100644 --- a/skimage/filter/rank/core8_cy.pxd +++ b/skimage/filter/rank/core8_cy.pxd @@ -15,7 +15,7 @@ cdef dtype_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols, # 8-bit core kernel receives extra information about data inferior and superior # percentiles -cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, +cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, float, Py_ssize_t, Py_ssize_t), dtype_t[:, ::1] image, char[:, ::1] selem, diff --git a/skimage/filter/rank/core8_cy.pyx b/skimage/filter/rank/core8_cy.pyx index b8d49a0f..357a1051 100644 --- a/skimage/filter/rank/core8_cy.pyx +++ b/skimage/filter/rank/core8_cy.pyx @@ -17,13 +17,13 @@ cdef inline dtype_t uint8_min(dtype_t a, dtype_t b): return a if a <= b else b -cdef inline void histogram_increment(Py_ssize_t * histo, float * pop, +cdef inline void histogram_increment(Py_ssize_t* histo, float* pop, dtype_t value): histo[value] += 1 pop[0] += 1 -cdef inline void histogram_decrement(Py_ssize_t * histo, float * pop, +cdef inline void histogram_decrement(Py_ssize_t* histo, float* pop, dtype_t value): histo[value] -= 1 pop[0] -= 1 @@ -42,7 +42,7 @@ cdef inline dtype_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols, return 0 -cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, +cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, float, Py_ssize_t, Py_ssize_t), dtype_t[:, ::1] image, char[:, ::1] selem, @@ -83,19 +83,19 @@ cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, cdef Py_ssize_t num_se_n, num_se_s, num_se_e, num_se_w # the current local histogram distribution - cdef Py_ssize_t * histo = malloc(256 * sizeof(Py_ssize_t)) + cdef Py_ssize_t* histo = malloc(256 * sizeof(Py_ssize_t)) # these lists contain the relative pixel row and column for each of the 4 # attack borders east, west, north and south e.g. se_e_r lists the rows of # the east structuring element border - cdef Py_ssize_t * se_e_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_e_c = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_w_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_w_c = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_n_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_n_c = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_s_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t * se_s_c = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_e_r = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_e_c = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_w_r = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_w_c = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_n_r = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_n_c = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_s_r = malloc(max_se * sizeof(Py_ssize_t)) + cdef Py_ssize_t* se_s_c = malloc(max_se * sizeof(Py_ssize_t)) # build attack and release borders # by using difference along axis @@ -149,10 +149,9 @@ cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, r = 0 c = 0 - # kernel ------------------------------------------------------------------- - out[r, c] = kernel(histo, pop, image[r, c], - p0, p1, s0, s1) - # kernel ------------------------------------------------------------------- + # kernel ------------------------------------------------------------------ + out[r, c] = kernel(histo, pop, image[r, c], p0, p1, s0, s1) + # kernel ------------------------------------------------------------------ # main loop r = 0 @@ -171,10 +170,9 @@ cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, if is_in_mask(rows, cols, rr, cc, mask_data): histogram_decrement(histo, &pop, image[rr, cc]) - # kernel ----------------------------------------------------------- - out[r, c] = \ - kernel(histo, pop, image[r, c], p0, p1, s0, s1) - # kernel ----------------------------------------------------------- + # kernel ---------------------------------------------------------- + out[r, c] = kernel(histo, pop, image[r, c], p0, p1, s0, s1) + # kernel ---------------------------------------------------------- r += 1 # pass to the next row if r >= rows: @@ -193,10 +191,9 @@ cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, if is_in_mask(rows, cols, rr, cc, mask_data): histogram_decrement(histo, &pop, image[rr, cc]) - # kernel --------------------------------------------------------------- - out[r, c] = kernel(histo, pop, image[r, c], - p0, p1, s0, s1) - # kernel --------------------------------------------------------------- + # kernel -------------------------------------------------------------- + out[r, c] = kernel(histo, pop, image[r, c], p0, p1, s0, s1) + # kernel -------------------------------------------------------------- # ---> east to west for c in range(cols - 2, -1, -1): @@ -212,10 +209,10 @@ cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, if is_in_mask(rows, cols, rr, cc, mask_data): histogram_decrement(histo, &pop, image[rr, cc]) - # kernel ----------------------------------------------------------- + # kernel ---------------------------------------------------------- out[r, c] = kernel( histo, pop, image[r, c], p0, p1, s0, s1) - # kernel ----------------------------------------------------------- + # kernel ---------------------------------------------------------- r += 1 # pass to the next row if r >= rows: @@ -234,10 +231,9 @@ cdef void _core8(dtype_t kernel(Py_ssize_t *, float, dtype_t, float, if is_in_mask(rows, cols, rr, cc, mask_data): histogram_decrement(histo, &pop, image[rr, cc]) - # kernel --------------------------------------------------------------- - out[r, c] = kernel(histo, pop, image[r, c], - p0, p1, s0, s1) - # kernel --------------------------------------------------------------- + # kernel -------------------------------------------------------------- + out[r, c] = kernel(histo, pop, image[r, c], p0, p1, s0, s1) + # kernel -------------------------------------------------------------- # release memory allocated by malloc free(se_e_r) diff --git a/skimage/filter/rank/generic16_cy.pyx b/skimage/filter/rank/generic16_cy.pyx index 7b2a8088..32021e78 100644 --- a/skimage/filter/rank/generic16_cy.pyx +++ b/skimage/filter/rank/generic16_cy.pyx @@ -12,7 +12,7 @@ from .core16_cy cimport dtype_t, _core16 # kernels uint16 take extra parameter for defining the bitdepth # ----------------------------------------------------------------- -cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -35,7 +35,7 @@ cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop, return (imax - imin) -cdef inline dtype_t kernel_bottomhat(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_bottomhat(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -51,7 +51,7 @@ cdef inline dtype_t kernel_bottomhat(Py_ssize_t * histo, float pop, else: return (0) -cdef inline dtype_t kernel_equalize(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_equalize(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -70,7 +70,7 @@ cdef inline dtype_t kernel_equalize(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_gradient(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -91,7 +91,7 @@ cdef inline dtype_t kernel_gradient(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_maximum(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_maximum(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -106,7 +106,7 @@ cdef inline dtype_t kernel_maximum(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_mean(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -122,7 +122,7 @@ cdef inline dtype_t kernel_mean(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_meansubtraction(Py_ssize_t * histo, +cdef inline dtype_t kernel_meansubtraction(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, @@ -141,7 +141,7 @@ cdef inline dtype_t kernel_meansubtraction(Py_ssize_t * histo, return (0) -cdef inline dtype_t kernel_median(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_median(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -159,7 +159,7 @@ cdef inline dtype_t kernel_median(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_minimum(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_minimum(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -174,7 +174,7 @@ cdef inline dtype_t kernel_minimum(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_modal(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_modal(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -191,7 +191,7 @@ cdef inline dtype_t kernel_modal(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t * histo, +cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, @@ -218,7 +218,7 @@ cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t * histo, return (0) -cdef inline dtype_t kernel_pop(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -226,7 +226,7 @@ cdef inline dtype_t kernel_pop(Py_ssize_t * histo, float pop, return (pop) -cdef inline dtype_t kernel_threshold(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_threshold(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -242,7 +242,7 @@ cdef inline dtype_t kernel_threshold(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_tophat(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_tophat(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -258,7 +258,7 @@ cdef inline dtype_t kernel_tophat(Py_ssize_t * histo, float pop, else: return (0) -cdef inline dtype_t kernel_entropy(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_entropy(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, diff --git a/skimage/filter/rank/generic8_cy.pyx b/skimage/filter/rank/generic8_cy.pyx index 62749041..93473a85 100644 --- a/skimage/filter/rank/generic8_cy.pyx +++ b/skimage/filter/rank/generic8_cy.pyx @@ -13,7 +13,7 @@ from .core8_cy cimport dtype_t, _core8 # ----------------------------------------------------------------- -cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -37,7 +37,7 @@ cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_bottomhat(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_bottomhat(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -53,7 +53,7 @@ cdef inline dtype_t kernel_bottomhat(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_equalize(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_equalize(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -71,7 +71,7 @@ cdef inline dtype_t kernel_equalize(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_gradient(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -91,7 +91,7 @@ cdef inline dtype_t kernel_gradient(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_maximum(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_maximum(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -105,7 +105,7 @@ cdef inline dtype_t kernel_maximum(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_mean(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -120,7 +120,7 @@ cdef inline dtype_t kernel_mean(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_meansubtraction(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_meansubtraction(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -135,7 +135,7 @@ cdef inline dtype_t kernel_meansubtraction(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_median(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_median(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -152,7 +152,7 @@ cdef inline dtype_t kernel_median(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_minimum(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_minimum(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -166,7 +166,7 @@ cdef inline dtype_t kernel_minimum(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_modal(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_modal(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -182,7 +182,7 @@ cdef inline dtype_t kernel_modal(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -205,14 +205,14 @@ cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_pop(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): return (pop) -cdef inline dtype_t kernel_threshold(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_threshold(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -227,7 +227,7 @@ cdef inline dtype_t kernel_threshold(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_tophat(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_tophat(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -242,7 +242,7 @@ cdef inline dtype_t kernel_tophat(Py_ssize_t * histo, float pop, else: return (0) -cdef inline dtype_t kernel_noise_filter(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_noise_filter(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -266,7 +266,7 @@ cdef inline dtype_t kernel_noise_filter(Py_ssize_t * histo, float pop, return min_i -cdef inline dtype_t kernel_entropy(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_entropy(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i @@ -284,7 +284,7 @@ cdef inline dtype_t kernel_entropy(Py_ssize_t * histo, float pop, else: return (0) -cdef inline dtype_t kernel_otsu(Py_ssize_t * histo, float pop, dtype_t g, +cdef inline dtype_t kernel_otsu(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i diff --git a/skimage/filter/rank/percentile16_cy.pyx b/skimage/filter/rank/percentile16_cy.pyx index 8680aae4..d99dc3c8 100644 --- a/skimage/filter/rank/percentile16_cy.pyx +++ b/skimage/filter/rank/percentile16_cy.pyx @@ -11,7 +11,7 @@ from .core16_cy cimport dtype_t, _core16, uint16_min, uint16_max # kernels uint16 (SOFT version using percentiles) # ----------------------------------------------------------------- -cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -45,7 +45,7 @@ cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_gradient(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -73,7 +73,7 @@ cdef inline dtype_t kernel_gradient(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_mean(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -99,7 +99,7 @@ cdef inline dtype_t kernel_mean(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_mean_subtraction(Py_ssize_t * histo, +cdef inline dtype_t kernel_mean_subtraction(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, @@ -127,7 +127,7 @@ cdef inline dtype_t kernel_mean_subtraction(Py_ssize_t * histo, return (0) -cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t * histo, +cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, @@ -164,7 +164,7 @@ cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t * histo, return (0) -cdef inline dtype_t kernel_percentile(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_percentile(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -184,7 +184,7 @@ cdef inline dtype_t kernel_percentile(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_pop(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, @@ -204,7 +204,7 @@ cdef inline dtype_t kernel_pop(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_threshold(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_threshold(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, float p0, float p1, diff --git a/skimage/filter/rank/percentile8_cy.pyx b/skimage/filter/rank/percentile8_cy.pyx index 6c37cf66..3ce63478 100644 --- a/skimage/filter/rank/percentile8_cy.pyx +++ b/skimage/filter/rank/percentile8_cy.pyx @@ -12,7 +12,7 @@ from .core8_cy cimport dtype_t, _core8, uint8_max, uint8_min # ----------------------------------------------------------------- -cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): cdef int i, imin, imax, sum, delta @@ -44,7 +44,7 @@ cdef inline dtype_t kernel_autolevel(Py_ssize_t * histo, float pop, return (128) -cdef inline dtype_t kernel_gradient(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): cdef int i, imin, imax, sum, delta @@ -69,7 +69,7 @@ cdef inline dtype_t kernel_gradient(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_mean(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): cdef int i, sum, mean, n @@ -91,7 +91,7 @@ cdef inline dtype_t kernel_mean(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_mean_subtraction(Py_ssize_t * histo, +cdef inline dtype_t kernel_mean_subtraction(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, @@ -115,7 +115,7 @@ cdef inline dtype_t kernel_mean_subtraction(Py_ssize_t * histo, return (0) -cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t * histo, +cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): @@ -147,7 +147,7 @@ cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t * histo, return (0) -cdef inline dtype_t kernel_percentile(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_percentile(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): cdef int i @@ -164,7 +164,7 @@ cdef inline dtype_t kernel_percentile(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_pop(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): cdef int i, sum, n @@ -181,7 +181,7 @@ cdef inline dtype_t kernel_pop(Py_ssize_t * histo, float pop, return (0) -cdef inline dtype_t kernel_threshold(Py_ssize_t * histo, float pop, +cdef inline dtype_t kernel_threshold(Py_ssize_t* histo, float pop, dtype_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): cdef int i From ea8111d0e3ee414461888588a040a2eae3ba83f8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 10:52:56 +0200 Subject: [PATCH 04/43] Use typed memoryviews for diff array --- skimage/filter/rank/core16_cy.pyx | 8 ++++---- skimage/filter/rank/core8_cy.pyx | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/skimage/filter/rank/core16_cy.pyx b/skimage/filter/rank/core16_cy.pyx index 02acc93d..8fe72423 100644 --- a/skimage/filter/rank/core16_cy.pyx +++ b/skimage/filter/rank/core16_cy.pyx @@ -97,16 +97,16 @@ cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, # build attack and release borders # by using difference along axis t = np.hstack((selem, np.zeros((selem.shape[0], 1)))) - t_e = np.diff(t, axis=1) < 0 + cdef char[:, :] t_e = np.diff(t, axis=1) < 0 t = np.hstack((np.zeros((selem.shape[0], 1)), selem)) - t_w = np.diff(t, axis=1) > 0 + cdef char[:, :] t_w = np.diff(t, axis=1) > 0 t = np.vstack((selem, np.zeros((1, selem.shape[1])))) - t_s = np.diff(t, axis=0) < 0 + cdef char[:, :] t_s = np.diff(t, axis=0) < 0 t = np.vstack((np.zeros((1, selem.shape[1])), selem)) - t_n = np.diff(t, axis=0) > 0 + cdef char[:, :] t_n = np.diff(t, axis=0) > 0 num_se_n = num_se_s = num_se_e = num_se_w = 0 diff --git a/skimage/filter/rank/core8_cy.pyx b/skimage/filter/rank/core8_cy.pyx index 357a1051..0b6ac554 100644 --- a/skimage/filter/rank/core8_cy.pyx +++ b/skimage/filter/rank/core8_cy.pyx @@ -100,16 +100,16 @@ cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, # build attack and release borders # by using difference along axis t = np.hstack((selem, np.zeros((selem.shape[0], 1)))) - t_e = np.diff(t, axis=1) < 0 + cdef char[:, :] t_e = np.diff(t, axis=1) < 0 t = np.hstack((np.zeros((selem.shape[0], 1)), selem)) - t_w = np.diff(t, axis=1) > 0 + cdef char[:, :] t_w = np.diff(t, axis=1) > 0 t = np.vstack((selem, np.zeros((1, selem.shape[1])))) - t_s = np.diff(t, axis=0) < 0 + cdef char[:, :] t_s = np.diff(t, axis=0) < 0 t = np.vstack((np.zeros((1, selem.shape[1])), selem)) - t_n = np.diff(t, axis=0) > 0 + cdef char[:, :] t_n = np.diff(t, axis=0) > 0 num_se_n = num_se_s = num_se_e = num_se_w = 0 From cd7959dd0836c135a64045a34ca590e59206c37b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 10:55:48 +0200 Subject: [PATCH 05/43] Fix styling of some comments --- skimage/filter/rank/core16_cy.pyx | 9 ++++----- skimage/filter/rank/core8_cy.pyx | 9 ++++----- 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/skimage/filter/rank/core16_cy.pyx b/skimage/filter/rank/core16_cy.pyx index 8fe72423..04d829e2 100644 --- a/skimage/filter/rank/core16_cy.pyx +++ b/skimage/filter/rank/core16_cy.pyx @@ -94,8 +94,7 @@ cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, cdef Py_ssize_t* se_s_r = malloc(max_se * sizeof(Py_ssize_t)) cdef Py_ssize_t* se_s_c = malloc(max_se * sizeof(Py_ssize_t)) - # build attack and release borders - # by using difference along axis + # build attack and release borders by using difference along axis t = np.hstack((selem, np.zeros((selem.shape[0], 1)))) cdef char[:, :] t_e = np.diff(t, axis=1) < 0 @@ -172,11 +171,11 @@ cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, midbin, p0, p1, s0, s1) # kernel ------------------------------------------- - r += 1 # pass to the next row + r += 1 # pass to the next row if r >= rows: break - # ---> north to south + # ---> north to south for s in range(num_se_s): rr = r + se_s_r[s] cc = c + se_s_c[s] @@ -213,7 +212,7 @@ cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, midbin, p0, p1, s0, s1) # kernel ------------------------------------------- - r += 1 # pass to the next row + r += 1 # pass to the next row if r >= rows: break diff --git a/skimage/filter/rank/core8_cy.pyx b/skimage/filter/rank/core8_cy.pyx index 0b6ac554..ad7c7ac4 100644 --- a/skimage/filter/rank/core8_cy.pyx +++ b/skimage/filter/rank/core8_cy.pyx @@ -97,8 +97,7 @@ cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, cdef Py_ssize_t* se_s_r = malloc(max_se * sizeof(Py_ssize_t)) cdef Py_ssize_t* se_s_c = malloc(max_se * sizeof(Py_ssize_t)) - # build attack and release borders - # by using difference along axis + # build attack and release borders by using difference along axis t = np.hstack((selem, np.zeros((selem.shape[0], 1)))) cdef char[:, :] t_e = np.diff(t, axis=1) < 0 @@ -174,11 +173,11 @@ cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, out[r, c] = kernel(histo, pop, image[r, c], p0, p1, s0, s1) # kernel ---------------------------------------------------------- - r += 1 # pass to the next row + r += 1 # pass to the next row if r >= rows: break - # ---> north to south + # ---> north to south for s in range(num_se_s): rr = r + se_s_r[s] cc = c + se_s_c[s] @@ -214,7 +213,7 @@ cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, histo, pop, image[r, c], p0, p1, s0, s1) # kernel ---------------------------------------------------------- - r += 1 # pass to the next row + r += 1 # pass to the next row if r >= rows: break From aa973aeff227dd1d8b6b9ac43c31bf96cd956454 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 10:59:34 +0200 Subject: [PATCH 06/43] Fix wrong module name --- skimage/filter/rank/bilateral.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skimage/filter/rank/bilateral.py b/skimage/filter/rank/bilateral.py index a111dd7c..4eafac19 100644 --- a/skimage/filter/rank/bilateral.py +++ b/skimage/filter/rank/bilateral.py @@ -130,7 +130,7 @@ def bilateral_mean(image, selem, out=None, mask=None, shift_x=False, >>> bilat_ima = bilateral_mean(ima, disk(20), s0=10,s1=10) """ - return _apply(None, _bilateral16_cy.mean, image, selem, out=out, + return _apply(None, bilateral16_cy.mean, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, s0=s0, s1=s1) @@ -188,5 +188,5 @@ def bilateral_pop(image, selem, out=None, mask=None, shift_x=False, """ - return _apply(None, _bilateral16_cy.pop, image, selem, out=out, + return _apply(None, bilateral16_cy.pop, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, s0=s0, s1=s1) From c9e81053f78fb326257d63e3c1442876adf0cfec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 11:02:21 +0200 Subject: [PATCH 07/43] Capitalize parameter description in doc string --- skimage/filter/rank/bilateral.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/skimage/filter/rank/bilateral.py b/skimage/filter/rank/bilateral.py index 4eafac19..13bfe37a 100644 --- a/skimage/filter/rank/bilateral.py +++ b/skimage/filter/rank/bilateral.py @@ -103,7 +103,7 @@ def bilateral_mean(image, selem, out=None, mask=None, shift_x=False, to the structuring element sizes (center must be inside the given structuring element). s0, s1 : int - define the [s0, s1] interval to be considered for computing the value. + Define the [s0, s1] interval to be considered for computing the value. Returns ------- @@ -157,7 +157,7 @@ def bilateral_pop(image, selem, out=None, mask=None, shift_x=False, to the structuring element sizes (center must be inside the given structuring element). s0, s1 : int - define the [s0, s1] interval to be considered for computing the value. + Define the [s0, s1] interval to be considered for computing the value. Returns ------- From ccd902fcb492ef1a0635346d49318f48b70d377b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 11:14:55 +0200 Subject: [PATCH 08/43] Extend bitdepth from 12bit to full 16bit --- skimage/filter/rank/bilateral.py | 15 ++---- skimage/filter/rank/core16_cy.pyx | 6 +-- skimage/filter/rank/generic.py | 76 ++++++++----------------------- skimage/filter/rank/percentile.py | 39 ++++------------ 4 files changed, 38 insertions(+), 98 deletions(-) diff --git a/skimage/filter/rank/bilateral.py b/skimage/filter/rank/bilateral.py index 13bfe37a..26784df8 100644 --- a/skimage/filter/rank/bilateral.py +++ b/skimage/filter/rank/bilateral.py @@ -3,8 +3,7 @@ The local histogram is computed using a sliding window similar to the method described in [1]_. -Input image must be 16-bit with a value < 4096 (i.e. 12 bit), -the number of histogram bins is determined from the +Input image must be 16-bit, the number of histogram bins is determined from the maximum value present in the image. The pixel neighborhood is defined by: @@ -61,8 +60,6 @@ def _apply(func8, func16, image, selem, out, mask, shift_x, shift_y, s0, s1): if out is None: out = np.zeros(image.shape, dtype=np.uint16) bitdepth = find_bitdepth(image) - if bitdepth > 11: - raise ValueError("Only uint16 <4096 image (12bit) supported.") func16(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, bitdepth=bitdepth + 1, out=out, s0=s0, s1=s1) else: @@ -88,9 +85,8 @@ def bilateral_mean(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- - image : ndarray - Image array (uint16). As the algorithm uses max. 12bit histogram, - an exception will be raised if image has a value > 4095 + image : ndarray (uint16) + Input image. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -142,9 +138,8 @@ def bilateral_pop(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- - image : ndarray - Image array (uint16). As the algorithm uses max. 12bit histogram, - an exception will be raised if image has a value > 4095 + image : ndarray (uint16) + Input image. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray diff --git a/skimage/filter/rank/core16_cy.pyx b/skimage/filter/rank/core16_cy.pyx index 04d829e2..2b01f246 100644 --- a/skimage/filter/rank/core16_cy.pyx +++ b/skimage/filter/rank/core16_cy.pyx @@ -56,10 +56,10 @@ cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, assert centre_c >= 0 assert centre_r < srows assert centre_c < scols - assert bitdepth in range(2, 13) - maxbin_list = [0, 0, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096] - midbin_list = [0, 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048] + maxbin_list = [0, 0, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, + 8192, 16384, 32768, 65536] + midbin_list = [m / 2 for m in maxbin_list] # set maxbin and midbin cdef Py_ssize_t maxbin = maxbin_list[bitdepth] diff --git a/skimage/filter/rank/generic.py b/skimage/filter/rank/generic.py index 124d4f25..bcfda1bc 100644 --- a/skimage/filter/rank/generic.py +++ b/skimage/filter/rank/generic.py @@ -1,11 +1,10 @@ """The local histogram is computed using a sliding window similar to the method described in [1]_. -Input image can be 8-bit or 16-bit with a value < 4096 (i.e. 12 bit), for 16-bit -input images, the number of histogram bins is determined from the maximum value -present in the image. +Input image can be 8-bit or 16-bit, for 16-bit input images, the number of +histogram bins is determined from the maximum value present in the image. -Result image is 8 or 16-bit with respect to the input image. +Result image is 8- or 16-bit with respect to the input image. References ---------- @@ -61,9 +60,6 @@ def _apply(func8, func16, image, selem, out, mask, shift_x, shift_y): if out is None: out = np.zeros(image.shape, dtype=np.uint16) bitdepth = find_bitdepth(image) - if bitdepth > 11: - image = image >> 4 - bitdepth = find_bitdepth(image) func16(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, bitdepth=bitdepth + 1, out=out) @@ -85,9 +81,7 @@ def autolevel(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -127,9 +121,7 @@ def bottomhat(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -159,9 +151,7 @@ def equalize(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -203,9 +193,7 @@ def gradient(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -236,9 +224,7 @@ def maximum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -278,9 +264,7 @@ def mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -321,9 +305,7 @@ def meansubtraction(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -354,9 +336,7 @@ def median(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -396,9 +376,7 @@ def minimum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -438,9 +416,7 @@ def modal(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -473,9 +449,7 @@ def morph_contr_enh(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -517,9 +491,7 @@ def pop(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -566,9 +538,7 @@ def threshold(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -615,9 +585,7 @@ def tophat(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -648,9 +616,7 @@ def noise_filter(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -694,9 +660,7 @@ def entropy(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- image : ndarray - Image array (uint8 array or uint16). If image is uint16, the algorithm - uses max. 12bit histogram, an exception will be raised if image has a - value > 4095. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -712,7 +676,7 @@ def entropy(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- out : uint8 array or uint16 array (same as input image) - entropy x10 (uint8 images) and entropy x1000 (uint16 images) + Entropy x10 (uint8 images) and entropy x1000 (uint16 images) References ---------- diff --git a/skimage/filter/rank/percentile.py b/skimage/filter/rank/percentile.py index 25758115..56c67983 100644 --- a/skimage/filter/rank/percentile.py +++ b/skimage/filter/rank/percentile.py @@ -7,9 +7,8 @@ not produce halos. The local histogram is computed using a sliding window similar to the method described in [1]_. -Input image can be 8-bit or 16-bit with a value < 4096 (i.e. 12 bit), for 16-bit -input images, the number of histogram bins is determined from the maximum value -present in the image. +Input image can be 8-bit or 16-bit, for 16-bit input images, the number of +histogram bins is determined from the maximum value present in the image. Result image is 8 or 16-bit with respect to the input image. @@ -60,8 +59,6 @@ def _apply(func8, func16, image, selem, out, mask, shift_x, shift_y, p0, p1): if out is None: out = np.zeros(image.shape, dtype=np.uint16) bitdepth = find_bitdepth(image) - if bitdepth > 11: - raise ValueError("Only uint16 <4096 image (12bit) supported.") func16(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, bitdepth=bitdepth + 1, out=out, p0=p0, p1=p1) else: @@ -80,9 +77,7 @@ def percentile_autolevel(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- 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. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -121,9 +116,7 @@ def percentile_gradient(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- 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. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -161,9 +154,7 @@ def percentile_mean(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- 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. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -201,9 +192,7 @@ def percentile_mean_subtraction(image, selem, out=None, mask=None, Parameters ---------- 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. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -243,9 +232,7 @@ def percentile_morph_contr_enh( Parameters ---------- 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. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -284,9 +271,7 @@ def percentile(image, selem, out=None, mask=None, shift_x=False, shift_y=False, Parameters ---------- 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. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -324,9 +309,7 @@ def percentile_pop(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- 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. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray @@ -366,9 +349,7 @@ def percentile_threshold(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- 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. + Image array (uint8 array or uint16). selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray From e9fcdc4a56c21ac0f1a668f6ac19e03e0853c0b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 12:21:08 +0200 Subject: [PATCH 09/43] Fix attack-release border initialization --- skimage/filter/rank/core16_cy.pyx | 8 ++++---- skimage/filter/rank/core8_cy.pyx | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/skimage/filter/rank/core16_cy.pyx b/skimage/filter/rank/core16_cy.pyx index 2b01f246..5641d2f1 100644 --- a/skimage/filter/rank/core16_cy.pyx +++ b/skimage/filter/rank/core16_cy.pyx @@ -96,16 +96,16 @@ cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, # build attack and release borders by using difference along axis t = np.hstack((selem, np.zeros((selem.shape[0], 1)))) - cdef char[:, :] t_e = np.diff(t, axis=1) < 0 + cdef char[:, :] t_e = (np.diff(t, axis=1) < 0).view(np.uint8) t = np.hstack((np.zeros((selem.shape[0], 1)), selem)) - cdef char[:, :] t_w = np.diff(t, axis=1) > 0 + cdef char[:, :] t_w = (np.diff(t, axis=1) > 0).view(np.uint8) t = np.vstack((selem, np.zeros((1, selem.shape[1])))) - cdef char[:, :] t_s = np.diff(t, axis=0) < 0 + cdef char[:, :] t_s = (np.diff(t, axis=0) < 0).view(np.uint8) t = np.vstack((np.zeros((1, selem.shape[1])), selem)) - cdef char[:, :] t_n = np.diff(t, axis=0) > 0 + cdef char[:, :] t_n = (np.diff(t, axis=0) > 0).view(np.uint8) num_se_n = num_se_s = num_se_e = num_se_w = 0 diff --git a/skimage/filter/rank/core8_cy.pyx b/skimage/filter/rank/core8_cy.pyx index ad7c7ac4..e6c0a714 100644 --- a/skimage/filter/rank/core8_cy.pyx +++ b/skimage/filter/rank/core8_cy.pyx @@ -99,16 +99,16 @@ cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, # build attack and release borders by using difference along axis t = np.hstack((selem, np.zeros((selem.shape[0], 1)))) - cdef char[:, :] t_e = np.diff(t, axis=1) < 0 + cdef char[:, :] t_e = (np.diff(t, axis=1) < 0).view(np.uint8) t = np.hstack((np.zeros((selem.shape[0], 1)), selem)) - cdef char[:, :] t_w = np.diff(t, axis=1) > 0 + cdef char[:, :] t_w = (np.diff(t, axis=1) > 0).view(np.uint8) t = np.vstack((selem, np.zeros((1, selem.shape[1])))) - cdef char[:, :] t_s = np.diff(t, axis=0) < 0 + cdef char[:, :] t_s = (np.diff(t, axis=0) < 0).view(np.uint8) t = np.vstack((np.zeros((1, selem.shape[1])), selem)) - cdef char[:, :] t_n = np.diff(t, axis=0) > 0 + cdef char[:, :] t_n = (np.diff(t, axis=0) > 0).view(np.uint8) num_se_n = num_se_s = num_se_e = num_se_w = 0 From d1fb0137886af647d848c1397c7e2df949b3efe2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 12:21:46 +0200 Subject: [PATCH 10/43] Fix test cases for full 16bit support --- skimage/filter/rank/tests/test_rank.py | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/skimage/filter/rank/tests/test_rank.py b/skimage/filter/rank/tests/test_rank.py index d39386c6..ab584776 100644 --- a/skimage/filter/rank/tests/test_rank.py +++ b/skimage/filter/rank/tests/test_rank.py @@ -130,17 +130,6 @@ def test_structuring_element8(): assert_array_equal(r, out) -def test_fail_on_bitdepth(): - # should fail because data bitdepth is too high for the function - - image = np.ones((100, 100), dtype=np.uint16) * 2 ** 12 - elem = np.ones((3, 3), dtype=np.uint8) - out = np.empty_like(image) - mask = np.ones(image.shape, dtype=np.uint8) - assert_raises(ValueError, rank.percentile_mean, image=image, - selem=elem, out=out, mask=mask, shift_x=0, shift_y=0) - - def test_pass_on_bitdepth(): # should pass because data bitdepth is not too high for the function @@ -192,7 +181,7 @@ def test_compare_uint_vs_float(): # dynamic) should be identical # Create signed int8 image that and convert it to uint8 - image_uint = img_as_uint(data.camera()) + image_uint = img_as_uint(data.camera()[:50, :50]) image_float = img_as_float(image_uint) methods = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'threshold', @@ -438,5 +427,17 @@ def test_selem_dtypes(): assert_array_equal(image, out) +def test_16bit(): + image = np.zeros((21, 21), dtype=np.uint16) + selem = np.ones((3, 3), dtype=np.uint8) + + for bitdepth in range(17): + value = 2 ** bitdepth - 1 + image[10, 10] = value + assert rank.minimum(image, selem)[10, 10] == 0 + assert rank.maximum(image, selem)[10, 10] == value + assert rank.mean(image, selem)[10, 10] == value / selem.size + + if __name__ == "__main__": run_module_suite() From 7fa8e704952c506faadb21da2da5195f237cca3a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 12:41:42 +0200 Subject: [PATCH 11/43] Fix README for full 16bit support --- skimage/filter/rank/README.rst | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/skimage/filter/rank/README.rst b/skimage/filter/rank/README.rst index cdf8205c..e5c5a9ad 100644 --- a/skimage/filter/rank/README.rst +++ b/skimage/filter/rank/README.rst @@ -23,10 +23,10 @@ size. This implementation gives better results for large structuring elements. The local histogram is updated at each pixel as the structuring element window moves by, i.e. only those pixels entering and leaving the structuring element update the local histogram. The histogram size is 8-bit (256 bins) for 8-bit -images and 2 to 12-bit (up to 4096 bins) for 16-bit images depending on the -maximum value of the image. Pixel values higher than 4095 raise a ValueError. +images and 2 to 16-bit for 16-bit images depending on the maximum value of the +image. -The filter is applied up to the image border, the neighboorhood used is adjusted -accordingly. The user may provide a mask image (same size as input image) where -non zero values are the part of the image participating in the histogram -computation. By default the entire image is filtered. +The filter is applied up to the image border, the neighboorhood used is +adjusted accordingly. The user may provide a mask image (same size as input +image) where non zero values are the part of the image participating in the +histogram computation. By default the entire image is filtered. From 984e542425a1dbb8086e892cb8af1a45a5698648 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 12:42:11 +0200 Subject: [PATCH 12/43] Use missing memoryviews for bilateral kernels --- skimage/filter/rank/bilateral16_cy.pyx | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/skimage/filter/rank/bilateral16_cy.pyx b/skimage/filter/rank/bilateral16_cy.pyx index 63a89453..f5614157 100644 --- a/skimage/filter/rank/bilateral16_cy.pyx +++ b/skimage/filter/rank/bilateral16_cy.pyx @@ -4,7 +4,7 @@ #cython: wraparound=False cimport numpy as cnp -from .core16_cy cimport _core16 +from .core16_cy cimport dtype_t, _core16 # ----------------------------------------------------------------- @@ -12,9 +12,6 @@ from .core16_cy cimport _core16 # ----------------------------------------------------------------- -ctypedef cnp.uint16_t dtype_t - - cdef inline dtype_t kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t bitdepth, Py_ssize_t maxbin, Py_ssize_t midbin, @@ -59,10 +56,10 @@ cdef inline dtype_t kernel_pop(Py_ssize_t* histo, float pop, # ----------------------------------------------------------------- -def mean(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def mean(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, int bitdepth=8, int s0=1, int s1=1): """average greylevel (clipped on uint8) """ @@ -70,10 +67,10 @@ def mean(cnp.ndarray[dtype_t, ndim=2] image, bitdepth, 0., 0., s0, s1) -def pop(cnp.ndarray[dtype_t, ndim=2] image, - cnp.ndarray[cnp.uint8_t, ndim=2] selem, - cnp.ndarray[cnp.uint8_t, ndim=2] mask=None, - cnp.ndarray[dtype_t, ndim=2] out=None, +def pop(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask=None, + dtype_t[:, ::1] out=None, char shift_x=0, char shift_y=0, int bitdepth=8, int s0=1, int s1=1): """returns the number of actual pixels of the structuring element inside the mask From ce792d5e1a564a183baa17454cdbb9f744dc39b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 12:57:05 +0200 Subject: [PATCH 13/43] Improve description of bilateral filter --- skimage/filter/rank/bilateral.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/skimage/filter/rank/bilateral.py b/skimage/filter/rank/bilateral.py index 26784df8..386c88bc 100644 --- a/skimage/filter/rank/bilateral.py +++ b/skimage/filter/rank/bilateral.py @@ -9,7 +9,7 @@ maximum value present in the image. The pixel neighborhood is defined by: * the given structuring element -* an interval [g-s0,g+s1] in greylevel around g the processed pixel greylevel +* an interval [g-s0, g+s1] in greylevel around g the processed pixel greylevel The kernel is flat (i.e. each pixel belonging to the neighborhood contributes equally). @@ -78,7 +78,7 @@ def bilateral_mean(image, selem, out=None, mask=None, shift_x=False, Spatial closeness is measured by considering only the local pixel neighborhood given by a structuring element (selem). - Radiometric similarity is defined by the greylevel interval [g-s0,g+s1] + Radiometric similarity is defined by the greylevel interval [g-s0, g+s1] where g is the current pixel greylevel. Only pixels belonging to the structuring element AND having a greylevel inside this interval are averaged. Return greyscale local bilateral_mean of an image. @@ -99,7 +99,8 @@ def bilateral_mean(image, selem, out=None, mask=None, shift_x=False, to the structuring element sizes (center must be inside the given structuring element). s0, s1 : int - Define the [s0, s1] interval to be considered for computing the value. + Define the [s0, s1] interval around the greyvalue of the center pixel + to be considered for computing the value. Returns ------- @@ -152,7 +153,8 @@ def bilateral_pop(image, selem, out=None, mask=None, shift_x=False, to the structuring element sizes (center must be inside the given structuring element). s0, s1 : int - Define the [s0, s1] interval to be considered for computing the value. + Define the [s0, s1] interval around the greyvalue of the center pixel + to be considered for computing the value. Returns ------- From f74c073da155c404792a906759f01a37046f7941 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 12:57:29 +0200 Subject: [PATCH 14/43] Add test case for bilateral filters --- skimage/filter/rank/tests/test_rank.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/skimage/filter/rank/tests/test_rank.py b/skimage/filter/rank/tests/test_rank.py index ab584776..1efe2bff 100644 --- a/skimage/filter/rank/tests/test_rank.py +++ b/skimage/filter/rank/tests/test_rank.py @@ -356,13 +356,11 @@ def test_otsu(): # test the local Otsu segmentation on a synthetic image # (left to right ramp * sinus) - test = np.tile( - [128, 145, 103, 127, 165, 83, 127, 185, 63, 127, 205, 43, - 127, 225, 23, 127], - (16, 1)) + test = np.tile([128, 145, 103, 127, 165, 83, 127, 185, 63, 127, 205, 43, + 127, 225, 23, 127], + (16, 1)) test = test.astype(np.uint8) - res = np.tile([1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1], - (16, 1)) + res = np.tile([1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1], (16, 1)) selem = np.ones((6, 6), dtype=np.uint8) th = 1 * (test >= rank.otsu(test, selem)) assert_array_equal(th, res) @@ -439,5 +437,19 @@ def test_16bit(): assert rank.mean(image, selem)[10, 10] == value / selem.size +def test_bilateral(): + image = np.zeros((21, 21), dtype=np.uint16) + selem = np.ones((3, 3), dtype=np.uint8) + + image[10, 10] = 1000 + image[10, 11] = 1010 + image[10, 9] = 900 + + assert rank.bilateral_mean(image, selem, s0=1, s1=1)[10, 10] == 1000 + assert rank.bilateral_pop(image, selem, s0=1, s1=1)[10, 10] == 1 + assert rank.bilateral_mean(image, selem, s0=11, s1=11)[10, 10] == 1005 + assert rank.bilateral_pop(image, selem, s0=11, s1=11)[10, 10] == 2 + + if __name__ == "__main__": run_module_suite() From 663092aca0e5ad59aeb211bc27d266cc559772c0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 13:02:45 +0200 Subject: [PATCH 15/43] Improve indentation --- skimage/filter/rank/percentile.py | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/skimage/filter/rank/percentile.py b/skimage/filter/rank/percentile.py index 56c67983..f302074c 100644 --- a/skimage/filter/rank/percentile.py +++ b/skimage/filter/rank/percentile.py @@ -100,10 +100,9 @@ def percentile_autolevel(image, selem, out=None, mask=None, shift_x=False, """ - return _apply( - percentile8_cy.autolevel, percentile16_cy.autolevel, - image, selem, out=out, mask=mask, shift_x=shift_x, - shift_y=shift_y, p0=p0, p1=p1) + return _apply(percentile8_cy.autolevel, percentile16_cy.autolevel, + image, selem, out=out, mask=mask, shift_x=shift_x, + shift_y=shift_y, p0=p0, p1=p1) def percentile_gradient(image, selem, out=None, mask=None, shift_x=False, @@ -221,9 +220,8 @@ def percentile_mean_subtraction(image, selem, out=None, mask=None, shift_y=shift_y, p0=p0, p1=p1) -def percentile_morph_contr_enh( - image, selem, out=None, mask=None, shift_x=False, - shift_y=False, p0=.0, p1=1.): +def percentile_morph_contr_enh(image, selem, out=None, mask=None, + shift_x=False, shift_y=False, p0=.0, p1=1.): """Return greyscale local morph_contr_enh of an image. morph_contr_enh is computed on the given structuring element. Only levels @@ -371,7 +369,6 @@ def percentile_threshold(image, selem, out=None, mask=None, shift_x=False, """ - return _apply( - percentile8_cy.threshold, percentile16_cy.threshold, - image, selem, out=out, mask=mask, shift_x=shift_x, - shift_y=shift_y, p0=p0, p1=0.) + return _apply(percentile8_cy.threshold, percentile16_cy.threshold, + image, selem, out=out, mask=mask, shift_x=shift_x, + shift_y=shift_y, p0=p0, p1=0.) From 6c5eb12df8c040bfcbbe5065de88bcc826016c5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 30 Jun 2013 13:37:13 +0200 Subject: [PATCH 16/43] Cast to int for python 3 --- skimage/filter/rank/core16_cy.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/filter/rank/core16_cy.pyx b/skimage/filter/rank/core16_cy.pyx index 5641d2f1..7de39bf8 100644 --- a/skimage/filter/rank/core16_cy.pyx +++ b/skimage/filter/rank/core16_cy.pyx @@ -59,7 +59,7 @@ cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, maxbin_list = [0, 0, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536] - midbin_list = [m / 2 for m in maxbin_list] + midbin_list = [int(m / 2) for m in maxbin_list] # set maxbin and midbin cdef Py_ssize_t maxbin = maxbin_list[bitdepth] From 68461dbf0016b5d479d459f987885c7632b4291b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Mon, 1 Jul 2013 18:52:19 +0200 Subject: [PATCH 17/43] Update bento.info for refactored rank package --- bento.info | 34 ++++++++++++++-------------------- 1 file changed, 14 insertions(+), 20 deletions(-) diff --git a/bento.info b/bento.info index b1366173..fe07dc5d 100644 --- a/bento.info +++ b/bento.info @@ -123,33 +123,27 @@ Library: Extension: skimage._shared.geometry Sources: skimage/_shared/geometry.pyx - Extension: skimage.filter.rank._core16 + Extension: skimage.filter.rank.bilateral16_cy Sources: - skimage/filter/rank/_core16.pyx - Extension: skimage.filter.rank._crank8 + skimage/filter/rank/bilateral16_cy.pyx + Extension: skimage.filter.rank.generic8_cy Sources: - skimage/filter/rank/_crank8.pyx - Extension: skimage.filter.rank._crank16 + skimage/filter/rank/generic8_cy.pyx + Extension: skimage.filter.rank.percentile16_cy Sources: - skimage/filter/rank/_crank16.pyx - Extension: skimage.filter.rank._core8 + skimage/filter/rank/percentile16_cy.pyx + Extension: skimage.filter.rank.core16_cy Sources: - skimage/filter/rank/_core8.pyx - Extension: skimage.filter.rank.bilateral_rank + skimage/filter/rank/core16_cy.pyx + Extension: skimage.filter.rank.core8_cy Sources: - skimage/filter/rank/bilateral_rank.pyx - Extension: skimage.filter.rank._crank16_percentiles + skimage/filter/rank/core8_cy.pyx + Extension: skimage.filter.rank.generic16_cy Sources: - skimage/filter/rank/_crank16_percentiles.pyx - Extension: skimage.filter.rank.percentile_rank + skimage/filter/rank/generic16_cy.pyx + Extension: skimage.filter.rank.percentile8_cy Sources: - skimage/filter/rank/percentile_rank.pyx - Extension: skimage.filter.rank._crank8_percentiles - Sources: - skimage/filter/rank/_crank8_percentiles.pyx - Extension: skimage.filter.rank._crank16_bilateral - Sources: - skimage/filter/rank/_crank16_bilateral.pyx + skimage/filter/rank/percentile8_cy.pyx Executable: skivi Module: skimage.scripts.skivi From 9a36e3b27082d41f07cbe7f88b89d7d51d2478e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Mon, 1 Jul 2013 19:19:20 +0200 Subject: [PATCH 18/43] Log warning when bitdepth > 10 --- skimage/filter/rank/bilateral.py | 6 ++++++ skimage/filter/rank/generic.py | 6 ++++++ skimage/filter/rank/percentile.py | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/skimage/filter/rank/bilateral.py b/skimage/filter/rank/bilateral.py index 386c88bc..e159d512 100644 --- a/skimage/filter/rank/bilateral.py +++ b/skimage/filter/rank/bilateral.py @@ -27,6 +27,9 @@ References import numpy as np from skimage import img_as_ubyte +from ... import get_log +log = get_log() + from . import bilateral16_cy from .generic import find_bitdepth @@ -60,6 +63,9 @@ def _apply(func8, func16, image, selem, out, mask, shift_x, shift_y, s0, s1): if out is None: out = np.zeros(image.shape, dtype=np.uint16) bitdepth = find_bitdepth(image) + if bitdepth > 10: + log.warn("Bitdepth of %d may result in bad rank filter " + "performance." % bitdepth) func16(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, bitdepth=bitdepth + 1, out=out, s0=s0, s1=s1) else: diff --git a/skimage/filter/rank/generic.py b/skimage/filter/rank/generic.py index bcfda1bc..d9b3569b 100644 --- a/skimage/filter/rank/generic.py +++ b/skimage/filter/rank/generic.py @@ -17,6 +17,9 @@ References import numpy as np from skimage import img_as_ubyte, img_as_uint +from ... import get_log +log = get_log() + from . import generic8_cy, generic16_cy @@ -60,6 +63,9 @@ def _apply(func8, func16, image, selem, out, mask, shift_x, shift_y): if out is None: out = np.zeros(image.shape, dtype=np.uint16) bitdepth = find_bitdepth(image) + if bitdepth > 10: + log.warn("Bitdepth of %d may result in bad rank filter " + "performance." % bitdepth) func16(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, bitdepth=bitdepth + 1, out=out) diff --git a/skimage/filter/rank/percentile.py b/skimage/filter/rank/percentile.py index f302074c..b75d994f 100644 --- a/skimage/filter/rank/percentile.py +++ b/skimage/filter/rank/percentile.py @@ -23,6 +23,9 @@ References import numpy as np from skimage import img_as_ubyte +from ... import get_log +log = get_log() + from . import percentile8_cy, percentile16_cy from .generic import find_bitdepth @@ -59,6 +62,9 @@ def _apply(func8, func16, image, selem, out, mask, shift_x, shift_y, p0, p1): if out is None: out = np.zeros(image.shape, dtype=np.uint16) bitdepth = find_bitdepth(image) + if bitdepth > 10: + log.warn("Bitdepth of %d may result in bad rank filter " + "performance." % bitdepth) func16(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, bitdepth=bitdepth + 1, out=out, p0=p0, p1=p1) else: From 4de4053a9f1727232878c7dc5478d7916f9b5a30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Tue, 2 Jul 2013 00:16:28 +0200 Subject: [PATCH 19/43] Refactor rank filter package as combined implementation for 8- and 16-bit --- skimage/filter/rank/bilateral.py | 93 +-- skimage/filter/rank/bilateral16_cy.pyx | 79 --- skimage/filter/rank/bilateral_cy.pyx | 80 +++ skimage/filter/rank/core16_cy.pxd | 20 - skimage/filter/rank/core16_cy.pyx | 247 -------- skimage/filter/rank/core8_cy.pxd | 25 - skimage/filter/rank/core_cy.pxd | 23 + .../filter/rank/{core8_cy.pyx => core_cy.pyx} | 95 ++- skimage/filter/rank/generic.py | 272 ++++----- skimage/filter/rank/generic16_cy.pyx | 418 ------------- skimage/filter/rank/generic8_cy.pyx | 480 --------------- skimage/filter/rank/generic_cy.pyx | 576 ++++++++++++++++++ skimage/filter/rank/percentile.py | 156 ++--- skimage/filter/rank/percentile16_cy.pyx | 326 ---------- skimage/filter/rank/percentile8_cy.pyx | 291 --------- skimage/filter/rank/percentile_cy.pyx | 325 ++++++++++ skimage/filter/rank/tests/test_rank.py | 20 +- skimage/filter/setup.py | 26 +- 18 files changed, 1279 insertions(+), 2273 deletions(-) delete mode 100644 skimage/filter/rank/bilateral16_cy.pyx create mode 100644 skimage/filter/rank/bilateral_cy.pyx delete mode 100644 skimage/filter/rank/core16_cy.pxd delete mode 100644 skimage/filter/rank/core16_cy.pyx delete mode 100644 skimage/filter/rank/core8_cy.pxd create mode 100644 skimage/filter/rank/core_cy.pxd rename skimage/filter/rank/{core8_cy.pyx => core_cy.pyx} (74%) delete mode 100644 skimage/filter/rank/generic16_cy.pyx delete mode 100644 skimage/filter/rank/generic8_cy.pyx create mode 100644 skimage/filter/rank/generic_cy.pyx delete mode 100644 skimage/filter/rank/percentile16_cy.pyx delete mode 100644 skimage/filter/rank/percentile8_cy.pyx create mode 100644 skimage/filter/rank/percentile_cy.pyx diff --git a/skimage/filter/rank/bilateral.py b/skimage/filter/rank/bilateral.py index e159d512..834a24a8 100644 --- a/skimage/filter/rank/bilateral.py +++ b/skimage/filter/rank/bilateral.py @@ -3,9 +3,6 @@ The local histogram is computed using a sliding window similar to the method described in [1]_. -Input image must be 16-bit, the number of histogram bins is determined from the -maximum value present in the image. - The pixel neighborhood is defined by: * the given structuring element @@ -14,8 +11,6 @@ The pixel neighborhood is defined by: The kernel is flat (i.e. each pixel belonging to the neighborhood contributes equally). -Result image is 16-bit with respect to the input image. - References ---------- @@ -30,46 +25,19 @@ from skimage import img_as_ubyte from ... import get_log log = get_log() -from . import bilateral16_cy -from .generic import find_bitdepth +from . import bilateral_cy +from .generic import _handle_input __all__ = ['bilateral_mean', 'bilateral_pop'] -def _apply(func8, func16, image, selem, out, mask, shift_x, shift_y, s0, s1): - selem = img_as_ubyte(selem > 0) - image = np.ascontiguousarray(image) +def _apply(func, image, selem, out, mask, shift_x, shift_y, s0, s1): - if mask is None: - mask = np.ones(image.shape, dtype=np.uint8) - else: - mask = np.ascontiguousarray(mask) - mask = img_as_ubyte(mask) + image, selem, out, mask, max_bin = _handle_input(image, selem, out, mask) - 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, s0=s0, s1=s1) - elif image.dtype == np.uint16: - if func16 is None: - raise TypeError("Not implemented for uint16 image.") - if out is None: - out = np.zeros(image.shape, dtype=np.uint16) - bitdepth = find_bitdepth(image) - if bitdepth > 10: - log.warn("Bitdepth of %d may result in bad rank filter " - "performance." % bitdepth) - func16(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, - bitdepth=bitdepth + 1, out=out, s0=s0, s1=s1) - else: - raise TypeError("Only uint8 and uint16 image supported.") + func(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, + out=out, max_bin=max_bin, s0=s0, s1=s1) return out @@ -91,16 +59,16 @@ def bilateral_mean(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- - image : ndarray (uint16) - Input image. + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : (int) + shift_x, shift_y : int Offset added to the structuring element center point. Shift is bounded to the structuring element sizes (center must be inside the given structuring element). @@ -110,17 +78,12 @@ def bilateral_mean(image, selem, out=None, mask=None, shift_x=False, Returns ------- - out : uint16 array + out : ndarray (same dtype as input) The result of the local bilateral mean. See also -------- - skimage.filter.denoise_bilateral() for a gaussian bilateral filter. - - Notes - ----- - - * input image are 16-bit only + skimage.filter.denoise_bilateral for a gaussian bilateral filter. Examples -------- @@ -131,9 +94,10 @@ def bilateral_mean(image, selem, out=None, mask=None, shift_x=False, >>> ima = data.camera().astype(np.uint16) >>> # bilateral filtering of cameraman image using a flat kernel >>> bilat_ima = bilateral_mean(ima, disk(20), s0=10,s1=10) + """ - return _apply(None, bilateral16_cy.mean, image, selem, out=out, + return _apply(bilateral_cy._mean, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, s0=s0, s1=s1) @@ -145,16 +109,16 @@ def bilateral_pop(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- - image : ndarray (uint16) - Input image. + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : (int) + shift_x, shift_y : int Offset added to the structuring element center point. Shift is bounded to the structuring element sizes (center must be inside the given structuring element). @@ -164,24 +128,19 @@ def bilateral_pop(image, selem, out=None, mask=None, shift_x=False, Returns ------- - out : uint16 array + out : ndarray (same dtype as input) the local number of pixels inside the bilateral neighborhood - Notes - ----- - - * input image are 16-bit only - Examples -------- >>> # Local mean >>> from skimage.morphology import square >>> import skimage.filter.rank as rank >>> ima16 = 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.uint16) + ... [0, 1, 1, 1, 0], + ... [0, 1, 1, 1, 0], + ... [0, 1, 1, 1, 0], + ... [0, 0, 0, 0, 0]], dtype=np.uint16) >>> rank.bilateral_pop(ima16, square(3), s0=10,s1=10) array([[3, 4, 3, 4, 3], [4, 4, 6, 4, 4], @@ -191,5 +150,5 @@ def bilateral_pop(image, selem, out=None, mask=None, shift_x=False, """ - return _apply(None, bilateral16_cy.pop, image, selem, out=out, + return _apply(bilateral_cy._pop, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, s0=s0, s1=s1) diff --git a/skimage/filter/rank/bilateral16_cy.pyx b/skimage/filter/rank/bilateral16_cy.pyx deleted file mode 100644 index f5614157..00000000 --- a/skimage/filter/rank/bilateral16_cy.pyx +++ /dev/null @@ -1,79 +0,0 @@ -#cython: cdivision=True -#cython: boundscheck=False -#cython: nonecheck=False -#cython: wraparound=False - -cimport numpy as cnp -from .core16_cy cimport dtype_t, _core16 - - -# ----------------------------------------------------------------- -# kernels uint16 take extra parameter for defining the bitdepth -# ----------------------------------------------------------------- - - -cdef inline dtype_t kernel_mean(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef int i, bilat_pop = 0 - cdef float mean = 0. - - if pop: - for i in range(maxbin): - if (g > (i - s0)) and (g < (i + s1)): - bilat_pop += histo[i] - mean += histo[i] * i - if bilat_pop: - return (mean / bilat_pop) - else: - return (0) - else: - return (0) - - -cdef inline dtype_t kernel_pop(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef int i, bilat_pop = 0 - - if pop: - for i in range(maxbin): - if (g > (i - s0)) and (g < (i + s1)): - bilat_pop += histo[i] - return (bilat_pop) - else: - return (0) - - -# ----------------------------------------------------------------- -# python wrappers -# ----------------------------------------------------------------- - - -def mean(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, int bitdepth=8, int s0=1, int s1=1): - """average greylevel (clipped on uint8) - """ - _core16(kernel_mean, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0., 0., s0, s1) - - -def pop(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, int bitdepth=8, int s0=1, int s1=1): - """returns the number of actual pixels of the structuring element inside - the mask - """ - _core16(kernel_pop, image, selem, mask, out, shift_x, shift_y, - bitdepth, .0, .0, s0, s1) diff --git a/skimage/filter/rank/bilateral_cy.pyx b/skimage/filter/rank/bilateral_cy.pyx new file mode 100644 index 00000000..d93fdb3c --- /dev/null +++ b/skimage/filter/rank/bilateral_cy.pyx @@ -0,0 +1,80 @@ +#cython: cdivision=True +#cython: boundscheck=False +#cython: nonecheck=False +#cython: wraparound=False + +cimport numpy as cnp +from libc.math cimport log + +from .core_cy cimport uint8_t, uint16_t, dtype_t, _core + + +cdef inline dtype_t _kernel_mean(Py_ssize_t* histo, float pop, + dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i + cdef Py_ssize_t bilat_pop = 0 + cdef Py_ssize_t mean = 0 + + if pop: + for i in range(max_bin): + if (g > (i - s0)) and (g < (i + s1)): + bilat_pop += histo[i] + mean += histo[i] * i + if bilat_pop: + return (mean / bilat_pop) + else: + return (0) + else: + return (0) + + +cdef inline dtype_t _kernel_pop(Py_ssize_t* histo, float pop, + dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i + cdef Py_ssize_t bilat_pop = 0 + + if pop: + for i in range(max_bin): + if (g > (i - s0)) and (g < (i + s1)): + bilat_pop += histo[i] + return (bilat_pop) + else: + return (0) + + +def _mean(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t s0, Py_ssize_t s1, + Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_mean[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, s0, s1, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_mean[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, s0, s1, max_bin) + + +def _pop(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t s0, Py_ssize_t s1, + Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_pop[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, s0, s1, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_pop[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, s0, s1, max_bin) diff --git a/skimage/filter/rank/core16_cy.pxd b/skimage/filter/rank/core16_cy.pxd deleted file mode 100644 index cebf0aab..00000000 --- a/skimage/filter/rank/core16_cy.pxd +++ /dev/null @@ -1,20 +0,0 @@ -cimport numpy as cnp - - -ctypedef cnp.uint16_t dtype_t - - -cdef dtype_t uint16_max(dtype_t a, dtype_t b) -cdef dtype_t uint16_min(dtype_t a, dtype_t b) - - -# 16-bit core kernel receives extra information about data bitdepth -cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, - Py_ssize_t, Py_ssize_t, Py_ssize_t, float, - float, Py_ssize_t, Py_ssize_t), - dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask, - dtype_t[:, ::1] out, - char shift_x, char shift_y, Py_ssize_t bitdepth, - float p0, float p1, Py_ssize_t s0, Py_ssize_t s1) except * diff --git a/skimage/filter/rank/core16_cy.pyx b/skimage/filter/rank/core16_cy.pyx deleted file mode 100644 index 7de39bf8..00000000 --- a/skimage/filter/rank/core16_cy.pyx +++ /dev/null @@ -1,247 +0,0 @@ -#cython: cdivision=True -#cython: boundscheck=False -#cython: nonecheck=False -#cython: wraparound=False - -import numpy as np - -cimport numpy as cnp -from libc.stdlib cimport malloc, free -from .core8_cy cimport is_in_mask - - -cdef inline dtype_t uint16_max(dtype_t a, dtype_t b): - return a if a >= b else b - - -cdef inline dtype_t uint16_min(dtype_t a, dtype_t b): - return a if a <= b else b - - -cdef inline void histogram_increment(Py_ssize_t* histo, float* pop, - dtype_t value): - histo[value] += 1 - pop[0] += 1 - - -cdef inline void histogram_decrement(Py_ssize_t* histo, float* pop, - dtype_t value): - histo[value] -= 1 - pop[0] -= 1 - - -cdef void _core16(dtype_t kernel(Py_ssize_t*, float, dtype_t, - Py_ssize_t, Py_ssize_t, Py_ssize_t, float, - float, Py_ssize_t, Py_ssize_t), - dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask, - dtype_t[:, ::1] out, - char shift_x, char shift_y, Py_ssize_t bitdepth, - float p0, float p1, Py_ssize_t s0, Py_ssize_t s1) except *: - """Compute histogram for each pixel neighborhood, apply kernel function and - use kernel function return value for output image. - """ - - cdef Py_ssize_t rows = image.shape[0] - cdef Py_ssize_t cols = image.shape[1] - cdef Py_ssize_t srows = selem.shape[0] - cdef Py_ssize_t scols = selem.shape[1] - - cdef Py_ssize_t centre_r = int(selem.shape[0] / 2) + shift_y - cdef Py_ssize_t centre_c = int(selem.shape[1] / 2) + shift_x - - # check that structuring element center is inside the element bounding box - assert centre_r >= 0 - assert centre_c >= 0 - assert centre_r < srows - assert centre_c < scols - - maxbin_list = [0, 0, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, - 8192, 16384, 32768, 65536] - midbin_list = [int(m / 2) for m in maxbin_list] - - # set maxbin and midbin - cdef Py_ssize_t maxbin = maxbin_list[bitdepth] - cdef Py_ssize_t midbin = midbin_list[bitdepth] - - # define pointers to the data - cdef char* mask_data = &mask[0, 0] - - # define local variable types - cdef Py_ssize_t r, c, rr, cc, s, value, local_max, i, even_row - # number of pixels actually inside the neighborhood (float) - cdef float pop - - # allocate memory with malloc - cdef Py_ssize_t max_se = srows * scols - - # number of element in each attack border - cdef Py_ssize_t num_se_n, num_se_s, num_se_e, num_se_w - - # the current local histogram distribution - cdef Py_ssize_t* histo = malloc(maxbin * sizeof(Py_ssize_t)) - - # these lists contain the relative pixel row and column for each of the 4 - # attack borders east, west, north and south e.g. se_e_r lists the rows of - # the east structuring element border - cdef Py_ssize_t* se_e_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t* se_e_c = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t* se_w_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t* se_w_c = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t* se_n_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t* se_n_c = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t* se_s_r = malloc(max_se * sizeof(Py_ssize_t)) - cdef Py_ssize_t* se_s_c = malloc(max_se * sizeof(Py_ssize_t)) - - # build attack and release borders by using difference along axis - t = np.hstack((selem, np.zeros((selem.shape[0], 1)))) - cdef char[:, :] t_e = (np.diff(t, axis=1) < 0).view(np.uint8) - - t = np.hstack((np.zeros((selem.shape[0], 1)), selem)) - cdef char[:, :] t_w = (np.diff(t, axis=1) > 0).view(np.uint8) - - t = np.vstack((selem, np.zeros((1, selem.shape[1])))) - cdef char[:, :] t_s = (np.diff(t, axis=0) < 0).view(np.uint8) - - t = np.vstack((np.zeros((1, selem.shape[1])), selem)) - cdef char[:, :] t_n = (np.diff(t, axis=0) > 0).view(np.uint8) - - num_se_n = num_se_s = num_se_e = num_se_w = 0 - - for r in range(srows): - for c in range(scols): - if t_e[r, c]: - se_e_r[num_se_e] = r - centre_r - se_e_c[num_se_e] = c - centre_c - num_se_e += 1 - if t_w[r, c]: - se_w_r[num_se_w] = r - centre_r - se_w_c[num_se_w] = c - centre_c - num_se_w += 1 - if t_n[r, c]: - se_n_r[num_se_n] = r - centre_r - se_n_c[num_se_n] = c - centre_c - num_se_n += 1 - if t_s[r, c]: - se_s_r[num_se_s] = r - centre_r - se_s_c[num_se_s] = c - centre_c - num_se_s += 1 - - # initial population and histogram - for i in range(maxbin): - histo[i] = 0 - - pop = 0 - - for r in range(srows): - for c in range(scols): - rr = r - centre_r - cc = c - centre_c - if selem[r, c]: - if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_increment(histo, &pop, image[rr, cc]) - - r = 0 - c = 0 - # kernel ------------------------------------------- - out[r, c] = kernel(histo, pop, image[r, c], bitdepth, maxbin, midbin, - p0, p1, s0, s1) - # kernel ------------------------------------------- - - # main loop - r = 0 - for even_row in range(0, rows, 2): - # ---> west to east - for c in range(1, cols): - for s in range(num_se_e): - rr = r + se_e_r[s] - cc = c + se_e_c[s] - if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_increment(histo, &pop, image[rr, cc]) - - for s in range(num_se_w): - rr = r + se_w_r[s] - cc = c + se_w_c[s] - 1 - if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_decrement(histo, &pop, image[rr, cc]) - - # kernel ------------------------------------------- - out[r, c] = kernel(histo, pop, image[r, c], bitdepth, maxbin, - midbin, p0, p1, s0, s1) - # kernel ------------------------------------------- - - r += 1 # pass to the next row - if r >= rows: - break - - # ---> north to south - for s in range(num_se_s): - rr = r + se_s_r[s] - cc = c + se_s_c[s] - if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_increment(histo, &pop, image[rr, cc]) - - for s in range(num_se_n): - rr = r + se_n_r[s] - 1 - cc = c + se_n_c[s] - if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_decrement(histo, &pop, image[rr, cc]) - - # kernel ------------------------------------------- - out[r, c] = kernel(histo, pop, image[r, c], - bitdepth, maxbin, midbin, p0, p1, s0, s1) - # kernel ------------------------------------------- - - # ---> east to west - for c in range(cols - 2, -1, -1): - for s in range(num_se_w): - rr = r + se_w_r[s] - cc = c + se_w_c[s] - if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_increment(histo, &pop, image[rr, cc]) - - for s in range(num_se_e): - rr = r + se_e_r[s] - cc = c + se_e_c[s] + 1 - if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_decrement(histo, &pop, image[rr, cc]) - - # kernel ------------------------------------------- - out[r, c] = kernel(histo, pop, image[r, c], bitdepth, maxbin, - midbin, p0, p1, s0, s1) - # kernel ------------------------------------------- - - r += 1 # pass to the next row - if r >= rows: - break - - # ---> north to south - for s in range(num_se_s): - rr = r + se_s_r[s] - cc = c + se_s_c[s] - if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_increment(histo, &pop, image[rr, cc]) - - for s in range(num_se_n): - rr = r + se_n_r[s] - 1 - cc = c + se_n_c[s] - if is_in_mask(rows, cols, rr, cc, mask_data): - histogram_decrement(histo, &pop, image[rr, cc]) - - # kernel ------------------------------------------- - out[r, c] = kernel(histo, pop, image[r, c], bitdepth, maxbin, midbin, - p0, p1, s0, s1) - # kernel ------------------------------------------- - - # release memory allocated by malloc - free(se_e_r) - free(se_e_c) - free(se_w_r) - free(se_w_c) - free(se_n_r) - free(se_n_c) - free(se_s_r) - free(se_s_c) - - free(histo) diff --git a/skimage/filter/rank/core8_cy.pxd b/skimage/filter/rank/core8_cy.pxd deleted file mode 100644 index c2b709d4..00000000 --- a/skimage/filter/rank/core8_cy.pxd +++ /dev/null @@ -1,25 +0,0 @@ -cimport numpy as cnp - - -ctypedef cnp.uint8_t dtype_t - - -cdef dtype_t uint8_max(dtype_t a, dtype_t b) -cdef dtype_t uint8_min(dtype_t a, dtype_t b) - - -cdef dtype_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols, - Py_ssize_t r, Py_ssize_t c, - char* mask) - - -# 8-bit core kernel receives extra information about data inferior and superior -# percentiles -cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, - float, Py_ssize_t, Py_ssize_t), - dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask, - dtype_t[:, ::1] out, - char shift_x, char shift_y, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1) except * diff --git a/skimage/filter/rank/core_cy.pxd b/skimage/filter/rank/core_cy.pxd new file mode 100644 index 00000000..544368a0 --- /dev/null +++ b/skimage/filter/rank/core_cy.pxd @@ -0,0 +1,23 @@ +from numpy cimport uint8_t, uint16_t + + +ctypedef fused dtype_t: + uint8_t + uint16_t + + +cdef dtype_t _max(dtype_t a, dtype_t b) +cdef dtype_t _min(dtype_t a, dtype_t b) + + +cdef void _core(dtype_t kernel(Py_ssize_t*, float, dtype_t, + Py_ssize_t, Py_ssize_t, float, + float, Py_ssize_t, Py_ssize_t), + dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1, + Py_ssize_t max_bin) except * diff --git a/skimage/filter/rank/core8_cy.pyx b/skimage/filter/rank/core_cy.pyx similarity index 74% rename from skimage/filter/rank/core8_cy.pyx rename to skimage/filter/rank/core_cy.pyx index e6c0a714..898e1775 100644 --- a/skimage/filter/rank/core8_cy.pyx +++ b/skimage/filter/rank/core_cy.pyx @@ -9,11 +9,11 @@ cimport numpy as cnp from libc.stdlib cimport malloc, free -cdef inline dtype_t uint8_max(dtype_t a, dtype_t b): +cdef inline dtype_t _max(dtype_t a, dtype_t b): return a if a >= b else b -cdef inline dtype_t uint8_min(dtype_t a, dtype_t b): +cdef inline dtype_t _min(dtype_t a, dtype_t b): return a if a <= b else b @@ -29,9 +29,9 @@ cdef inline void histogram_decrement(Py_ssize_t* histo, float* pop, pop[0] -= 1 -cdef inline dtype_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols, - Py_ssize_t r, Py_ssize_t c, - char* mask): +cdef inline char is_in_mask(Py_ssize_t rows, Py_ssize_t cols, + Py_ssize_t r, Py_ssize_t c, + char* mask): """Check whether given coordinate is within image and mask is true.""" if r < 0 or r > rows - 1 or c < 0 or c > cols - 1: return 0 @@ -42,14 +42,17 @@ cdef inline dtype_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols, return 0 -cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, - float, Py_ssize_t, Py_ssize_t), - dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask, - dtype_t[:, ::1] out, - char shift_x, char shift_y, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1) except *: +cdef void _core(dtype_t kernel(Py_ssize_t*, float, dtype_t, + Py_ssize_t, Py_ssize_t, float, + float, Py_ssize_t, Py_ssize_t), + dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1, + Py_ssize_t max_bin) except *: """Compute histogram for each pixel neighborhood, apply kernel function and use kernel function return value for output image. """ @@ -59,8 +62,8 @@ cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, cdef Py_ssize_t srows = selem.shape[0] cdef Py_ssize_t scols = selem.shape[1] - cdef Py_ssize_t centre_r = int(selem.shape[0] / 2) + shift_y - cdef Py_ssize_t centre_c = int(selem.shape[1] / 2) + shift_x + cdef Py_ssize_t centre_r = (selem.shape[0] / 2) + shift_y + cdef Py_ssize_t centre_c = (selem.shape[1] / 2) + shift_x # check that structuring element center is inside the element bounding box assert centre_r >= 0 @@ -68,26 +71,35 @@ cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, assert centre_r < srows assert centre_c < scols + # add 1 to ensure maximum value is included in histogram -> range(max_bin) + max_bin += 1 + + cdef Py_ssize_t mid_bin = max_bin / 2 + + # define pointers to the data cdef char* mask_data = &mask[0, 0] # define local variable types cdef Py_ssize_t r, c, rr, cc, s, value, local_max, i, even_row # number of pixels actually inside the neighborhood (float) - cdef float pop - - # allocate memory with malloc - cdef Py_ssize_t max_se = srows * scols - - # number of element in each attack border - cdef Py_ssize_t num_se_n, num_se_s, num_se_e, num_se_w + cdef float pop = 0 # the current local histogram distribution - cdef Py_ssize_t* histo = malloc(256 * sizeof(Py_ssize_t)) + cdef Py_ssize_t* histo = malloc(max_bin * sizeof(Py_ssize_t)) + for i in range(max_bin): + histo[i] = 0 # these lists contain the relative pixel row and column for each of the 4 # attack borders east, west, north and south e.g. se_e_r lists the rows of # the east structuring element border + + cdef Py_ssize_t max_se = srows * scols + + # number of element in each attack border + cdef Py_ssize_t num_se_n, num_se_s, num_se_e, num_se_w + num_se_n = num_se_s = num_se_e = num_se_w = 0 + cdef Py_ssize_t* se_e_r = malloc(max_se * sizeof(Py_ssize_t)) cdef Py_ssize_t* se_e_c = malloc(max_se * sizeof(Py_ssize_t)) cdef Py_ssize_t* se_w_r = malloc(max_se * sizeof(Py_ssize_t)) @@ -110,8 +122,6 @@ cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, t = np.vstack((np.zeros((1, selem.shape[1])), selem)) cdef char[:, :] t_n = (np.diff(t, axis=0) > 0).view(np.uint8) - num_se_n = num_se_s = num_se_e = num_se_w = 0 - for r in range(srows): for c in range(scols): if t_e[r, c]: @@ -131,13 +141,6 @@ cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, se_s_c[num_se_s] = c - centre_c num_se_s += 1 - # initial population and histogram (kernel is centered on the first row and - # column) - for i in range(256): - histo[i] = 0 - - pop = 0 - for r in range(srows): for c in range(scols): rr = r - centre_r @@ -148,13 +151,13 @@ cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, r = 0 c = 0 - # kernel ------------------------------------------------------------------ - out[r, c] = kernel(histo, pop, image[r, c], p0, p1, s0, s1) - # kernel ------------------------------------------------------------------ + out[r, c] = kernel(histo, pop, image[r, c], max_bin, mid_bin, + p0, p1, s0, s1) # main loop r = 0 for even_row in range(0, rows, 2): + # ---> west to east for c in range(1, cols): for s in range(num_se_e): @@ -169,9 +172,8 @@ cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, if is_in_mask(rows, cols, rr, cc, mask_data): histogram_decrement(histo, &pop, image[rr, cc]) - # kernel ---------------------------------------------------------- - out[r, c] = kernel(histo, pop, image[r, c], p0, p1, s0, s1) - # kernel ---------------------------------------------------------- + out[r, c] = kernel(histo, pop, image[r, c], max_bin, + mid_bin, p0, p1, s0, s1) r += 1 # pass to the next row if r >= rows: @@ -190,9 +192,8 @@ cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, if is_in_mask(rows, cols, rr, cc, mask_data): histogram_decrement(histo, &pop, image[rr, cc]) - # kernel -------------------------------------------------------------- - out[r, c] = kernel(histo, pop, image[r, c], p0, p1, s0, s1) - # kernel -------------------------------------------------------------- + out[r, c] = kernel(histo, pop, image[r, c], + max_bin, mid_bin, p0, p1, s0, s1) # ---> east to west for c in range(cols - 2, -1, -1): @@ -208,10 +209,8 @@ cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, if is_in_mask(rows, cols, rr, cc, mask_data): histogram_decrement(histo, &pop, image[rr, cc]) - # kernel ---------------------------------------------------------- - out[r, c] = kernel( - histo, pop, image[r, c], p0, p1, s0, s1) - # kernel ---------------------------------------------------------- + out[r, c] = kernel(histo, pop, image[r, c], max_bin, + mid_bin, p0, p1, s0, s1) r += 1 # pass to the next row if r >= rows: @@ -230,9 +229,8 @@ cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, if is_in_mask(rows, cols, rr, cc, mask_data): histogram_decrement(histo, &pop, image[rr, cc]) - # kernel -------------------------------------------------------------- - out[r, c] = kernel(histo, pop, image[r, c], p0, p1, s0, s1) - # kernel -------------------------------------------------------------- + out[r, c] = kernel(histo, pop, image[r, c], max_bin, mid_bin, + p0, p1, s0, s1) # release memory allocated by malloc free(se_e_r) @@ -243,5 +241,4 @@ cdef void _core8(dtype_t kernel(Py_ssize_t*, float, dtype_t, float, free(se_n_c) free(se_s_r) free(se_s_c) - free(histo) diff --git a/skimage/filter/rank/generic.py b/skimage/filter/rank/generic.py index d9b3569b..e09bfba5 100644 --- a/skimage/filter/rank/generic.py +++ b/skimage/filter/rank/generic.py @@ -20,7 +20,7 @@ from skimage import img_as_ubyte, img_as_uint from ... import get_log log = get_log() -from . import generic8_cy, generic16_cy +from . import generic_cy __all__ = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'maximum', 'mean', @@ -28,56 +28,43 @@ __all__ = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'maximum', 'mean', 'pop', 'threshold', 'tophat', 'noise_filter', 'entropy', 'otsu'] -import numpy as np +def _handle_input(image, selem, out, mask): + if image.dtype not in (np.uint8, np.uint16): + image = img_as_ubyte(image) -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 _apply(func8, func16, image, selem, out, mask, shift_x, shift_y): - selem = img_as_ubyte(selem > 0) + selem = np.ascontiguousarray(img_as_ubyte(selem > 0)) image = np.ascontiguousarray(image) if mask is None: mask = np.ones(image.shape, dtype=np.uint8) else: - mask = np.ascontiguousarray(mask) mask = img_as_ubyte(mask) + mask = np.ascontiguousarray(mask) + + if out is None: + out = np.empty_like(image, dtype=image.dtype) if image is out: raise NotImplementedError("Cannot perform rank operation in place.") 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) + if is_8bit: + max_bin = 255 else: - image = img_as_uint(image) - if out is None: - out = np.zeros(image.shape, dtype=np.uint16) - bitdepth = find_bitdepth(image) - if bitdepth > 10: - log.warn("Bitdepth of %d may result in bad rank filter " - "performance." % bitdepth) - func16(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, - bitdepth=bitdepth + 1, out=out) + max_bin = max(4, image.max()) - return out + return image, selem, out, mask, max_bin -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) +def _apply(func, image, selem, out, mask, shift_x, shift_y): + + image, selem, out, mask, max_bin = _handle_input(image, selem, out, mask) + + func(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, + out=out, max_bin=max_bin) + return out @@ -86,13 +73,13 @@ def autolevel(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -102,7 +89,7 @@ def autolevel(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- - out : uint8 array or uint16 array (same as input image) + out : ndarray (same dtype as input image) The result of the local autolevel. Examples @@ -117,7 +104,7 @@ def autolevel(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ - return _apply(generic8_cy.autolevel, generic16_cy.autolevel, image, selem, + return _apply(generic_cy._autolevel, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) @@ -126,13 +113,13 @@ def bottomhat(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -142,12 +129,12 @@ def bottomhat(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- - local bottomhat : uint8 array or uint16 array depending on input image + bottomhat : ndarray (same dtype as input image) The result of the local bottomhat. """ - return _apply(generic8_cy.bottomhat, generic16_cy.bottomhat, image, selem, + return _apply(generic_cy._bottomhat, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) @@ -156,13 +143,13 @@ def equalize(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -172,7 +159,7 @@ def equalize(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- - out : uint8 array or uint16 array (same as input image) + out : ndarray (same dtype as input image) The result of the local equalize. Examples @@ -187,7 +174,7 @@ def equalize(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ - return _apply(generic8_cy.equalize, generic16_cy.equalize, image, selem, + return _apply(generic_cy._equalize, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) @@ -198,13 +185,13 @@ def gradient(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -214,12 +201,12 @@ def gradient(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- - out : uint8 array or uint16 array (same as input image) + out : ndarray (same dtype as input image) The local gradient. """ - return _apply(generic8_cy.gradient, generic16_cy.gradient, image, selem, + return _apply(generic_cy._gradient, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) @@ -229,13 +216,13 @@ def maximum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -245,7 +232,7 @@ def maximum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- - out : uint8 array or uint16 array (same as input image) + out : ndarray (same dtype as input image) The local maximum. See also @@ -254,13 +241,12 @@ def maximum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Note ---- - * input image can be 8-bit or 16-bit with a value < 4096 (i.e. 12 bit) * the lower algorithm complexity makes the rank.maximum() more efficient for larger images and structuring elements """ - return _apply(generic8_cy.maximum, generic16_cy.maximum, image, selem, + return _apply(generic_cy._maximum, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) @@ -269,13 +255,13 @@ def mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -285,7 +271,7 @@ def mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- - out : uint8 array or uint16 array (same as input image) + out : ndarray (same dtype as input image) The local mean. Examples @@ -300,7 +286,7 @@ def mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ - return _apply(generic8_cy.mean, generic16_cy.mean, image, selem, out=out, + return _apply(generic_cy._mean, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) @@ -310,13 +296,13 @@ def meansubtraction(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -326,14 +312,13 @@ def meansubtraction(image, selem, out=None, mask=None, shift_x=False, Returns ------- - out : uint8 array or uint16 array (same as input image) + out : ndarray (same dtype as input image) The result of the local meansubtraction. """ - return _apply(generic8_cy.meansubtraction, generic16_cy.meansubtraction, - image, selem, out=out, mask=mask, shift_x=shift_x, - shift_y=shift_y) + return _apply(generic_cy._meansubtraction, image, selem, + out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) def median(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -341,13 +326,13 @@ def median(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -357,7 +342,7 @@ def median(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- - out : uint8 array or uint16 array (same as input image) + out : ndarray (same dtype as input image) The local median. Examples @@ -372,7 +357,7 @@ def median(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ - return _apply(generic8_cy.median, generic16_cy.median, image, selem, + return _apply(generic_cy._median, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) @@ -381,13 +366,13 @@ def minimum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -397,7 +382,7 @@ def minimum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- - out : uint8 array or uint16 array (same as input image) + out : ndarray (same dtype as input image) The local minimum. See also @@ -406,13 +391,12 @@ def minimum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Note ---- - * input image can be 8-bit or 16-bit with a value < 4096 (i.e. 12 bit) * the lower algorithm complexity makes the rank.minimum() more efficient for larger images and structuring elements """ - return _apply(generic8_cy.minimum, generic16_cy.minimum, image, selem, + return _apply(generic_cy._minimum, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) @@ -421,13 +405,13 @@ def modal(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -437,12 +421,12 @@ def modal(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- - out : uint8 array or uint16 array (same as input image) + out : ndarray (same dtype as input image) The local modal. """ - return _apply(generic8_cy.modal, generic16_cy.modal, image, selem, + return _apply(generic_cy._modal, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) @@ -454,13 +438,13 @@ def morph_contr_enh(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -470,7 +454,7 @@ def morph_contr_enh(image, selem, out=None, mask=None, shift_x=False, Returns ------- - out : uint8 array or uint16 array (same as input image) + out : ndarray (same dtype as input image) The result of the local morph_contr_enh. Examples @@ -485,9 +469,8 @@ def morph_contr_enh(image, selem, out=None, mask=None, shift_x=False, """ - return _apply(generic8_cy.morph_contr_enh, generic16_cy.morph_contr_enh, - image, selem, out=out, mask=mask, shift_x=shift_x, - shift_y=shift_y) + return _apply(generic_cy._morph_contr_enh, image, selem, + out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) def pop(image, selem, out=None, mask=None, shift_x=False, shift_y=False): @@ -496,13 +479,13 @@ def pop(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -512,7 +495,7 @@ def pop(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- - out : uint8 array or uint16 array (same as input image) + out : ndarray (same dtype as input image) The number of pixels belonging to the neighborhood. Examples @@ -534,7 +517,7 @@ def pop(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ - return _apply(generic8_cy.pop, generic16_cy.pop, image, selem, out=out, + return _apply(generic_cy._pop, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) @@ -543,13 +526,13 @@ def threshold(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -559,7 +542,7 @@ def threshold(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- - out : uint8 array or uint16 array (same as input image) + out : ndarray (same dtype as input image) The result of the local threshold. Examples @@ -581,7 +564,7 @@ def threshold(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ - return _apply(generic8_cy.threshold, generic16_cy.threshold, image, selem, + return _apply(generic_cy._threshold, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) @@ -590,13 +573,13 @@ def tophat(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -606,12 +589,12 @@ def tophat(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- - out : uint8 array or uint16 array (same as input image) + out : ndarray (same dtype as input image) The image tophat. """ - return _apply(generic8_cy.tophat, generic16_cy.tophat, image, selem, + return _apply(generic_cy._tophat, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) @@ -621,13 +604,13 @@ def noise_filter(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -642,7 +625,7 @@ def noise_filter(image, selem, out=None, mask=None, shift_x=False, Returns ------- - out : uint8 array or uint16 array (same as input image) + out : ndarray (same dtype as input image) The image noise. """ @@ -654,7 +637,7 @@ def noise_filter(image, selem, out=None, mask=None, shift_x=False, selem_cpy = selem.copy() selem_cpy[centre_r, centre_c] = 0 - return _apply(generic8_cy.noise_filter, None, image, selem_cpy, out=out, + return _apply(generic_cy._noise_filter, image, selem_cpy, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) @@ -665,13 +648,13 @@ def entropy(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -681,8 +664,8 @@ def entropy(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- - out : uint8 array or uint16 array (same as input image) - Entropy x10 (uint8 images) and entropy x1000 (uint16 images) + out : ndarray (same dtype as input image) + Entropy of image. References ---------- @@ -694,17 +677,12 @@ def entropy(image, selem, out=None, mask=None, shift_x=False, shift_y=False): >>> from skimage import data >>> from skimage.filter.rank import entropy >>> from skimage.morphology import disk - >>> # defining a 8- and a 16-bit test images >>> a8 = data.camera() - >>> a16 = data.camera().astype(np.uint16) * 4 - >>> # pixel values contain 10x the local entropy >>> ent8 = entropy(a8, disk(5)) - >>> # pixel values contain 1000x the local entropy - >>> ent16 = entropy(a16, disk(5)) """ - return _apply(generic8_cy.entropy, generic16_cy.entropy, image, selem, + return _apply(generic_cy._entropy, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) @@ -719,7 +697,7 @@ def otsu(image, selem, out=None, mask=None, shift_x=False, shift_y=False): The neighborhood expressed as a 2-D array of 1's and 0's. out : ndarray If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -729,17 +707,13 @@ def otsu(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- - out : uint8 array - Otsu's threshold values + out : ndarray (same dtype as input image) + Otsu's threshold values. References ---------- .. [otsu] http://en.wikipedia.org/wiki/Otsu's_method - Notes - ----- - * input image are 8-bit only - Examples -------- >>> # Local entropy @@ -753,5 +727,5 @@ def otsu(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ - return _apply(generic8_cy.otsu, None, image, selem, out=out, + return _apply(generic_cy._otsu, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) diff --git a/skimage/filter/rank/generic16_cy.pyx b/skimage/filter/rank/generic16_cy.pyx deleted file mode 100644 index 32021e78..00000000 --- a/skimage/filter/rank/generic16_cy.pyx +++ /dev/null @@ -1,418 +0,0 @@ -#cython: cdivision=True -#cython: boundscheck=False -#cython: nonecheck=False -#cython: wraparound=False - -cimport numpy as cnp -from libc.math cimport log -from .core16_cy cimport dtype_t, _core16 - - -# ----------------------------------------------------------------- -# kernels uint16 take extra parameter for defining the bitdepth -# ----------------------------------------------------------------- - -cdef inline dtype_t kernel_autolevel(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i, imin, imax, delta - - if pop: - for i in range(maxbin - 1, -1, -1): - if histo[i]: - imax = i - break - for i in range(maxbin): - if histo[i]: - imin = i - break - delta = imax - imin - if delta > 0: - return (1. * (maxbin - 1) * (g - imin) / delta) - else: - return (imax - imin) - - -cdef inline dtype_t kernel_bottomhat(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i - - if pop: - for i in range(maxbin): - if histo[i]: - break - - return (g - i) - else: - return (0) - -cdef inline dtype_t kernel_equalize(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i - cdef float sum = 0. - - if pop: - for i in range(maxbin): - sum += histo[i] - if i >= g: - break - - return (((maxbin - 1) * sum) / pop) - else: - return (0) - - -cdef inline dtype_t kernel_gradient(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i, imin, imax - - if pop: - for i in range(maxbin - 1, -1, -1): - if histo[i]: - imax = i - break - for i in range(maxbin): - if histo[i]: - imin = i - break - return (imax - imin) - else: - return (0) - - -cdef inline dtype_t kernel_maximum(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i - - if pop: - for i in range(maxbin - 1, -1, -1): - if histo[i]: - return (i) - - return (0) - - -cdef inline dtype_t kernel_mean(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i - cdef float mean = 0. - - if pop: - for i in range(maxbin): - mean += histo[i] * i - return (mean / pop) - else: - return (0) - - -cdef inline dtype_t kernel_meansubtraction(Py_ssize_t* histo, - float pop, - dtype_t g, - Py_ssize_t bitdepth, - Py_ssize_t maxbin, - Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i - cdef float mean = 0. - - if pop: - for i in range(maxbin): - mean += histo[i] * i - return ((g - mean / pop) / 2. + (midbin - 1)) - else: - return (0) - - -cdef inline dtype_t kernel_median(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i - cdef float sum = pop / 2.0 - - if pop: - for i in range(maxbin): - if histo[i]: - sum -= histo[i] - if sum < 0: - return (i) - else: - return (0) - - -cdef inline dtype_t kernel_minimum(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i - - if pop: - for i in range(maxbin): - if histo[i]: - return (i) - else: - return (0) - - -cdef inline dtype_t kernel_modal(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t hmax = 0, imax = 0 - - if pop: - for i in range(maxbin): - if histo[i] > hmax: - hmax = histo[i] - imax = i - return (imax) - else: - return (0) - - -cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t* histo, - float pop, - dtype_t g, - Py_ssize_t bitdepth, - Py_ssize_t maxbin, - Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i, imin, imax - - if pop: - for i in range(maxbin - 1, -1, -1): - if histo[i]: - imax = i - break - for i in range(maxbin): - if histo[i]: - imin = i - break - if imax - g < g - imin: - return (imax) - else: - return (imin) - else: - return (0) - - -cdef inline dtype_t kernel_pop(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - return (pop) - - -cdef inline dtype_t kernel_threshold(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i - cdef float mean = 0. - - if pop: - for i in range(maxbin): - mean += histo[i] * i - return (g > (mean / pop)) - else: - return (0) - - -cdef inline dtype_t kernel_tophat(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i - - if pop: - for i in range(maxbin - 1, -1, -1): - if histo[i]: - break - - return (i - g) - else: - return (0) - -cdef inline dtype_t kernel_entropy(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i - cdef float e, p - - if pop: - e = 0. - - for i in range(maxbin): - p = histo[i] / pop - if p > 0: - e -= p * log(p) / 0.6931471805599453 - - return e * 1000 - else: - return (0) - -# ----------------------------------------------------------------- -# python wrappers -# ----------------------------------------------------------------- - - -def autolevel(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): - _core16(kernel_autolevel, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0, 0, 0, 0) - - -def bottomhat(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): - _core16(kernel_bottomhat, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0, 0, 0, 0) - - -def equalize(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): - _core16(kernel_equalize, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0, 0, 0, 0) - - -def gradient(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): - _core16(kernel_gradient, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0, 0, 0, 0) - - -def maximum(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): - _core16(kernel_maximum, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0, 0, 0, 0) - - -def mean(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): - _core16(kernel_mean, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0, 0, 0, 0) - - -def meansubtraction(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): - _core16(kernel_meansubtraction, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0, 0, 0, 0) - - -def median(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): - _core16(kernel_median, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0, 0, 0, 0) - - -def minimum(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): - _core16(kernel_minimum, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0, 0, 0, 0) - - -def morph_contr_enh(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): - _core16(kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0, 0, 0, 0) - - -def modal(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): - _core16(kernel_modal, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0, 0, 0, 0) - - -def pop(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): - _core16(kernel_pop, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0, 0, 0, 0) - - -def threshold(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): - _core16(kernel_threshold, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0, 0, 0, 0) - - -def tophat(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): - _core16(kernel_tophat, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0, 0, 0, 0) - - -def entropy(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8): - _core16(kernel_entropy, image, selem, mask, out, shift_x, shift_y, - bitdepth, 0, 0, 0, 0) diff --git a/skimage/filter/rank/generic8_cy.pyx b/skimage/filter/rank/generic8_cy.pyx deleted file mode 100644 index 93473a85..00000000 --- a/skimage/filter/rank/generic8_cy.pyx +++ /dev/null @@ -1,480 +0,0 @@ -#cython: cdivision=True -#cython: boundscheck=False -#cython: nonecheck=False -#cython: wraparound=False - -cimport numpy as cnp -from libc.math cimport log -from .core8_cy cimport dtype_t, _core8 - - -# ----------------------------------------------------------------- -# kernels uint8 -# ----------------------------------------------------------------- - - -cdef inline dtype_t kernel_autolevel(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef Py_ssize_t i, imin, imax, delta - - if pop: - for i in range(255, -1, -1): - if histo[i]: - imax = i - break - for i in range(256): - if histo[i]: - imin = i - break - delta = imax - imin - if delta > 0: - return (255. * (g - imin) / delta) - else: - return (imax - imin) - else: - return (0) - - -cdef inline dtype_t kernel_bottomhat(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef Py_ssize_t i - - if pop: - for i in range(256): - if histo[i]: - break - - return (g - i) - else: - return (0) - - -cdef inline dtype_t kernel_equalize(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef Py_ssize_t i - cdef float sum = 0. - - if pop: - for i in range(256): - sum += histo[i] - if i >= g: - break - - return ((255 * sum) / pop) - else: - return (0) - - -cdef inline dtype_t kernel_gradient(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef Py_ssize_t i, imin, imax - - if pop: - for i in range(255, -1, -1): - if histo[i]: - imax = i - break - for i in range(256): - if histo[i]: - imin = i - break - return (imax - imin) - else: - return (0) - - -cdef inline dtype_t kernel_maximum(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef Py_ssize_t i - - if pop: - for i in range(255, -1, -1): - if histo[i]: - return (i) - else: - return (0) - - -cdef inline dtype_t kernel_mean(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef Py_ssize_t i - cdef float mean = 0. - - if pop: - for i in range(256): - mean += histo[i] * i - return (mean / pop) - else: - return (0) - - -cdef inline dtype_t kernel_meansubtraction(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef Py_ssize_t i - cdef float mean = 0. - - if pop: - for i in range(256): - mean += histo[i] * i - return ((g - mean / pop) / 2. + 127) - else: - return (0) - - -cdef inline dtype_t kernel_median(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef Py_ssize_t i - cdef float sum = pop / 2.0 - - if pop: - for i in range(256): - if histo[i]: - sum -= histo[i] - if sum < 0: - return (i) - else: - return (0) - - -cdef inline dtype_t kernel_minimum(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef Py_ssize_t i - - if pop: - for i in range(256): - if histo[i]: - return (i) - else: - return (0) - - -cdef inline dtype_t kernel_modal(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef Py_ssize_t hmax = 0, imax = 0 - - if pop: - for i in range(256): - if histo[i] > hmax: - hmax = histo[i] - imax = i - return (imax) - else: - return (0) - - -cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef Py_ssize_t i, imin, imax - - if pop: - for i in range(255, -1, -1): - if histo[i]: - imax = i - break - for i in range(256): - if histo[i]: - imin = i - break - if imax - g < g - imin: - return (imax) - else: - return (imin) - else: - return (0) - - -cdef inline dtype_t kernel_pop(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - return (pop) - - -cdef inline dtype_t kernel_threshold(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef Py_ssize_t i - cdef float mean = 0. - - if pop: - for i in range(256): - mean += histo[i] * i - return (g > (mean / pop)) - else: - return (0) - - -cdef inline dtype_t kernel_tophat(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef Py_ssize_t i - - if pop: - for i in range(255, -1, -1): - if histo[i]: - break - - return (i - g) - else: - return (0) - -cdef inline dtype_t kernel_noise_filter(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef Py_ssize_t i - cdef Py_ssize_t min_i - - # early stop if at least one pixel of the neighborhood has the same g - if histo[g] > 0: - return 0 - - for i in range(g, -1, -1): - if histo[i]: - break - min_i = g - i - for i in range(g, 256): - if histo[i]: - break - if i - g < min_i: - return (i - g) - else: - return min_i - - -cdef inline dtype_t kernel_entropy(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i - cdef float e, p - - if pop: - e = 0. - - for i in range(256): - p = histo[i] / pop - if p > 0: - e -= p * log(p) / 0.6931471805599453 - - return e * 10 - else: - return (0) - -cdef inline dtype_t kernel_otsu(Py_ssize_t* histo, float pop, dtype_t g, - float p0, float p1, Py_ssize_t s0, - Py_ssize_t s1): - cdef Py_ssize_t i - cdef Py_ssize_t max_i - cdef float P, mu1, mu2, q1, new_q1, sigma_b, max_sigma_b - cdef float mu = 0. - - # compute local mean - if pop: - for i in range(256): - mu += histo[i] * i - mu = (mu / pop) - else: - return (0) - - # maximizing the between class variance - max_i = 0 - q1 = histo[0] / pop - m1 = 0. - max_sigma_b = 0. - - for i in range(1, 256): - P = histo[i] / pop - new_q1 = q1 + P - if new_q1 > 0: - mu1 = (q1 * mu1 + i * P) / new_q1 - mu2 = (mu - new_q1 * mu1) / (1. - new_q1) - sigma_b = new_q1 * (1. - new_q1) * (mu1 - mu2) ** 2 - if sigma_b > max_sigma_b: - max_sigma_b = sigma_b - max_i = i - q1 = new_q1 - - return max_i - - -# ----------------------------------------------------------------- -# python wrappers -# used only internally -# ----------------------------------------------------------------- - - -def autolevel(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_autolevel, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) - - -def bottomhat(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_bottomhat, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) - - -def equalize(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_equalize, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) - - -def gradient(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_gradient, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) - - -def maximum(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_maximum, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) - - -def mean(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_mean, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) - - -def meansubtraction(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_meansubtraction, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) - - -def median(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_median, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) - - -def minimum(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_minimum, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) - - -def morph_contr_enh(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) - - -def modal(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_modal, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) - - -def pop(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_pop, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) - - -def threshold(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_threshold, image, selem, mask, out, shift_x, shift_y, 0, 0, - 0, 0) - - -def tophat(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_tophat, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) - - -def noise_filter(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_noise_filter, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) - - -def entropy(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_entropy, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) - - -def otsu(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0): - _core8(kernel_otsu, image, selem, mask, out, shift_x, shift_y, - 0, 0, 0, 0) diff --git a/skimage/filter/rank/generic_cy.pyx b/skimage/filter/rank/generic_cy.pyx new file mode 100644 index 00000000..0e972c30 --- /dev/null +++ b/skimage/filter/rank/generic_cy.pyx @@ -0,0 +1,576 @@ +#cython: cdivision=True +#cython: boundscheck=False +#cython: nonecheck=False +#cython: wraparound=False + +cimport numpy as cnp +from libc.math cimport log + +from .core_cy cimport uint8_t, uint16_t, dtype_t, _core + + +cdef inline dtype_t _kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i, imin, imax, delta + + if pop: + for i in range(max_bin - 1, -1, -1): + if histo[i]: + imax = i + break + for i in range(max_bin): + if histo[i]: + imin = i + break + delta = imax - imin + if delta > 0: + return ((max_bin - 1) * (g - imin) / delta) + else: + return (imax - imin) + else: + return (0) + + +cdef inline dtype_t _kernel_bottomhat(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i + + if pop: + for i in range(max_bin): + if histo[i]: + break + + return (g - i) + else: + return (0) + + +cdef inline dtype_t _kernel_equalize(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i + cdef Py_ssize_t sum = 0 + + if pop: + for i in range(max_bin): + sum += histo[i] + if i >= g: + break + + return (((max_bin - 1) * sum) / pop) + else: + return (0) + + +cdef inline dtype_t _kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i, imin, imax + + if pop: + for i in range(max_bin - 1, -1, -1): + if histo[i]: + imax = i + break + for i in range(max_bin): + if histo[i]: + imin = i + break + return (imax - imin) + else: + return (0) + + +cdef inline dtype_t _kernel_maximum(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i + + if pop: + for i in range(max_bin - 1, -1, -1): + if histo[i]: + return (i) + else: + return (0) + + +cdef inline dtype_t _kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i + cdef Py_ssize_t mean = 0 + + if pop: + for i in range(max_bin): + mean += histo[i] * i + return (mean / pop) + else: + return (0) + + +cdef inline dtype_t _kernel_meansubtraction(Py_ssize_t* histo, float pop, + dtype_t g, Py_ssize_t max_bin, + Py_ssize_t mid_bin, float p0, + float p1, Py_ssize_t s0, + Py_ssize_t s1): + + cdef Py_ssize_t i + cdef Py_ssize_t mean = 0 + + if pop: + for i in range(max_bin): + mean += histo[i] * i + return ((g - mean / pop) / 2. + 127) + else: + return (0) + + +cdef inline dtype_t _kernel_median(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i + cdef float sum = pop / 2.0 + + if pop: + for i in range(max_bin): + if histo[i]: + sum -= histo[i] + if sum < 0: + return (i) + else: + return (0) + + +cdef inline dtype_t _kernel_minimum(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i + + if pop: + for i in range(max_bin): + if histo[i]: + return (i) + else: + return (0) + + +cdef inline dtype_t _kernel_modal(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t hmax = 0, imax = 0 + + if pop: + for i in range(max_bin): + if histo[i] > hmax: + hmax = histo[i] + imax = i + return (imax) + else: + return (0) + + +cdef inline dtype_t _kernel_morph_contr_enh(Py_ssize_t* histo, float pop, + dtype_t g, Py_ssize_t max_bin, + Py_ssize_t mid_bin, float p0, + float p1, Py_ssize_t s0, + Py_ssize_t s1): + + cdef Py_ssize_t i, imin, imax + + if pop: + for i in range(max_bin - 1, -1, -1): + if histo[i]: + imax = i + break + for i in range(max_bin): + if histo[i]: + imin = i + break + if imax - g < g - imin: + return (imax) + else: + return (imin) + else: + return (0) + + +cdef inline dtype_t _kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + return (pop) + + +cdef inline dtype_t _kernel_threshold(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i + cdef Py_ssize_t mean = 0 + + if pop: + for i in range(max_bin): + mean += histo[i] * i + return (g > (mean / pop)) + else: + return (0) + + +cdef inline dtype_t _kernel_tophat(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i + + if pop: + for i in range(max_bin - 1, -1, -1): + if histo[i]: + break + + return (i - g) + else: + return (0) + + +cdef inline dtype_t _kernel_noise_filter(Py_ssize_t* histo, float pop, + dtype_t g, Py_ssize_t max_bin, + Py_ssize_t mid_bin, float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i + cdef Py_ssize_t min_i + + # early stop if at least one pixel of the neighborhood has the same g + if histo[g] > 0: + return 0 + + for i in range(g, -1, -1): + if histo[i]: + break + min_i = g - i + for i in range(g, max_bin): + if histo[i]: + break + if i - g < min_i: + return (i - g) + else: + return min_i + + +cdef inline dtype_t _kernel_entropy(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + cdef Py_ssize_t i + cdef float e, p + + if pop: + e = 0. + + for i in range(max_bin): + p = histo[i] / pop + if p > 0: + e -= p * log(p) / 0.6931471805599453 + + return e + else: + return (0) + + +cdef inline dtype_t _kernel_otsu(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + cdef Py_ssize_t i + cdef Py_ssize_t max_i + cdef float P, mu1, mu2, q1, new_q1, sigma_b, max_sigma_b + cdef float mu = 0. + + # compute local mean + if pop: + for i in range(max_bin): + mu += histo[i] * i + mu = (mu / pop) + else: + return (0) + + # maximizing the between class variance + max_i = 0 + q1 = histo[0] / pop + m1 = 0. + max_sigma_b = 0. + + for i in range(1, max_bin): + P = histo[i] / pop + new_q1 = q1 + P + if new_q1 > 0: + mu1 = (q1 * mu1 + i * P) / new_q1 + mu2 = (mu - new_q1 * mu1) / (1. - new_q1) + sigma_b = new_q1 * (1. - new_q1) * (mu1 - mu2) ** 2 + if sigma_b > max_sigma_b: + max_sigma_b = sigma_b + max_i = i + q1 = new_q1 + + return max_i + + +def _autolevel(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_autolevel[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_autolevel[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _bottomhat(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_bottomhat[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_bottomhat[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _equalize(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_equalize[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_equalize[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _gradient(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_gradient[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_gradient[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _maximum(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_maximum[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_maximum[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _mean(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_mean[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_mean[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _meansubtraction(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_meansubtraction[uint8_t], image, selem, mask, + out, shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_meansubtraction[uint16_t], image, selem, mask, + out, shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _median(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_median[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_median[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _minimum(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_minimum[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_minimum[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _morph_contr_enh(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_morph_contr_enh[uint8_t], image, selem, mask, + out, shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_morph_contr_enh[uint16_t], image, selem, mask, + out, shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _modal(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_modal[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_modal[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _pop(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_pop[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_pop[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _threshold(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_threshold[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_threshold[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _tophat(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_tophat[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_tophat[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _noise_filter(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_noise_filter[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_noise_filter[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _entropy(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_entropy[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_entropy[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + + +def _otsu(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_otsu[uint8_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_otsu[uint16_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) diff --git a/skimage/filter/rank/percentile.py b/skimage/filter/rank/percentile.py index b75d994f..3b0a04ba 100644 --- a/skimage/filter/rank/percentile.py +++ b/skimage/filter/rank/percentile.py @@ -26,8 +26,8 @@ from skimage import img_as_ubyte from ... import get_log log = get_log() -from . import percentile8_cy, percentile16_cy -from .generic import find_bitdepth +from . import percentile_cy +from .generic import _handle_input __all__ = ['percentile_autolevel', 'percentile_gradient', @@ -36,45 +36,18 @@ __all__ = ['percentile_autolevel', 'percentile_gradient', 'percentile_threshold'] -def _apply(func8, func16, image, selem, out, mask, shift_x, shift_y, p0, p1): - selem = img_as_ubyte(selem > 0) - image = np.ascontiguousarray(image) +def _apply(func, image, selem, out, mask, shift_x, shift_y, p0, p1): - if mask is None: - mask = np.ones(image.shape, dtype=np.uint8) - else: - mask = np.ascontiguousarray(mask) - mask = img_as_ubyte(mask) + image, selem, out, mask, max_bin = _handle_input(image, selem, out, mask) - 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, p0=p0, p1=p1) - elif image.dtype == np.uint16: - if func16 is None: - raise TypeError("Not implemented for uint16 image.") - if out is None: - out = np.zeros(image.shape, dtype=np.uint16) - bitdepth = find_bitdepth(image) - if bitdepth > 10: - log.warn("Bitdepth of %d may result in bad rank filter " - "performance." % bitdepth) - func16(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.") + func(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, + out=out, max_bin=max_bin, p0=p0, p1=p1) return out def percentile_autolevel(image, selem, out=None, mask=None, shift_x=False, - shift_y=False, p0=.0, p1=1.): + shift_y=False, p0=0, p1=1): """Return greyscale local autolevel of an image. Autolevel is computed on the given structuring element. Only levels between @@ -82,13 +55,13 @@ def percentile_autolevel(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -101,18 +74,18 @@ def percentile_autolevel(image, selem, out=None, mask=None, shift_x=False, Returns ------- - local autolevel : uint8 array or uint16 + local autolevel : ndarray (same dtype as input) The result of the local autolevel. """ - return _apply(percentile8_cy.autolevel, percentile16_cy.autolevel, + return _apply(percentile_cy._autolevel, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1) def percentile_gradient(image, selem, out=None, mask=None, shift_x=False, - shift_y=False, p0=.0, p1=1.): + shift_y=False, p0=0, p1=1): """Return greyscale local percentile_gradient of an image. percentile_gradient is computed on the given structuring element. Only @@ -120,13 +93,13 @@ def percentile_gradient(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -139,18 +112,18 @@ def percentile_gradient(image, selem, out=None, mask=None, shift_x=False, Returns ------- - local percentile_gradient : uint8 array or uint16 + local percentile_gradient : ndarray (same dtype as input) The result of the local percentile_gradient. """ - return _apply(percentile8_cy.gradient, percentile16_cy.gradient, + return _apply(percentile_cy._gradient, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1) def percentile_mean(image, selem, out=None, mask=None, shift_x=False, - shift_y=False, p0=.0, p1=1.): + shift_y=False, p0=0, p1=1): """Return greyscale local mean of an image. Mean is computed on the given structuring element. Only levels between @@ -158,13 +131,13 @@ def percentile_mean(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -177,18 +150,18 @@ def percentile_mean(image, selem, out=None, mask=None, shift_x=False, Returns ------- - local mean : uint8 array or uint16 + local mean : ndarray (same dtype as input) The result of the local mean. """ - return _apply(percentile8_cy.mean, percentile16_cy.mean, + return _apply(percentile_cy._mean, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1) def percentile_mean_subtraction(image, selem, out=None, mask=None, - shift_x=False, shift_y=False, p0=.0, p1=1.): + shift_x=False, shift_y=False, p0=0, p1=1): """Return greyscale local mean_subtraction of an image. mean_subtraction is computed on the given structuring element. Only levels @@ -196,13 +169,13 @@ def percentile_mean_subtraction(image, selem, out=None, mask=None, Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -215,19 +188,18 @@ def percentile_mean_subtraction(image, selem, out=None, mask=None, Returns ------- - local mean_subtraction : uint8 array or uint16 + local mean_subtraction : ndarray (same dtype as input) The result of the local mean_subtraction. """ - return _apply(percentile8_cy.mean_subtraction, - percentile16_cy.mean_subtraction, + return _apply(percentile_cy._mean_subtraction, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1) def percentile_morph_contr_enh(image, selem, out=None, mask=None, - shift_x=False, shift_y=False, p0=.0, p1=1.): + shift_x=False, shift_y=False, p0=0, p1=1): """Return greyscale local morph_contr_enh of an image. morph_contr_enh is computed on the given structuring element. Only levels @@ -235,13 +207,13 @@ def percentile_morph_contr_enh(image, selem, out=None, mask=None, Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -254,19 +226,18 @@ def percentile_morph_contr_enh(image, selem, out=None, mask=None, Returns ------- - local morph_contr_enh : uint8 array or uint16 + local morph_contr_enh : ndarray (same dtype as input) The result of the local morph_contr_enh. """ - return _apply(percentile8_cy.morph_contr_enh, - percentile16_cy.morph_contr_enh, + return _apply(percentile_cy._morph_contr_enh, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1) def percentile(image, selem, out=None, mask=None, shift_x=False, shift_y=False, - p0=.0): + p0=0): """Return greyscale local percentile of an image. percentile is computed on the given structuring element. Returns the value @@ -274,13 +245,13 @@ def percentile(image, selem, out=None, mask=None, shift_x=False, shift_y=False, Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -292,19 +263,18 @@ def percentile(image, selem, out=None, mask=None, shift_x=False, shift_y=False, Returns ------- - local percentile : uint8 array or uint16 + local percentile : ndarray (same dtype as input) The result of the local percentile. """ - return _apply(percentile8_cy.percentile, - percentile16_cy.percentile, + return _apply(percentile_cy._percentile, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=0.) def percentile_pop(image, selem, out=None, mask=None, shift_x=False, - shift_y=False, p0=.0, p1=1.): + shift_y=False, p0=0, p1=1): """Return greyscale local pop of an image. pop is computed on the given structuring element. Only levels between @@ -312,13 +282,13 @@ def percentile_pop(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -331,18 +301,18 @@ def percentile_pop(image, selem, out=None, mask=None, shift_x=False, Returns ------- - local pop : uint8 array or uint16 + local pop : ndarray (same dtype as input) The result of the local pop. """ - return _apply(percentile8_cy.pop, percentile16_cy.pop, + return _apply(percentile_cy._pop, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1) def percentile_threshold(image, selem, out=None, mask=None, shift_x=False, - shift_y=False, p0=.0): + shift_y=False, p0=0): """Return greyscale local threshold of an image. threshold is computed on the given structuring element. Returns @@ -352,13 +322,13 @@ def percentile_threshold(image, selem, out=None, mask=None, shift_x=False, Parameters ---------- - image : ndarray - Image array (uint8 array or uint16). + image : ndarray (uint8, uint16) + Image array. selem : ndarray The neighborhood expressed as a 2-D array of 1's and 0's. - out : ndarray + out : ndarray (same dtype as input) If None, a new array will be allocated. - mask : ndarray (uint8) + mask : ndarray 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 : int @@ -370,11 +340,11 @@ def percentile_threshold(image, selem, out=None, mask=None, shift_x=False, Returns ------- - local threshold : uint8 array or uint16 + local threshold : ndarray (same dtype as input) The result of the local threshold. """ - return _apply(percentile8_cy.threshold, percentile16_cy.threshold, + return _apply(percentile_cy._threshold, image, selem, out=out, mask=mask, shift_x=shift_x, - shift_y=shift_y, p0=p0, p1=0.) + shift_y=shift_y, p0=p0, p1=0) diff --git a/skimage/filter/rank/percentile16_cy.pyx b/skimage/filter/rank/percentile16_cy.pyx deleted file mode 100644 index d99dc3c8..00000000 --- a/skimage/filter/rank/percentile16_cy.pyx +++ /dev/null @@ -1,326 +0,0 @@ -#cython: cdivision=True -#cython: boundscheck=False -#cython: nonecheck=False -#cython: wraparound=False - -cimport numpy as cnp -from .core16_cy cimport dtype_t, _core16, uint16_min, uint16_max - - -# ----------------------------------------------------------------- -# kernels uint16 (SOFT version using percentiles) -# ----------------------------------------------------------------- - -cdef inline dtype_t kernel_autolevel(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef int i, imin, imax, sum, delta - - if pop: - sum = 0 - p1 = 1.0 - p1 - for i in range(maxbin): - sum += histo[i] - if sum > p0 * pop: - imin = i - break - sum = 0 - for i in range(maxbin - 1, -1, -1): - sum += histo[i] - if sum > p1 * pop: - imax = i - break - - delta = imax - imin - if delta > 0: - return (1.0 * (maxbin - 1) - * (uint16_min(uint16_max(imin, g), imax) - - imin) / delta) - else: - return (imax - imin) - else: - return (0) - - -cdef inline dtype_t kernel_gradient(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef int i, imin, imax, sum, delta - - if pop: - sum = 0 - p1 = 1.0 - p1 - for i in range(maxbin): - sum += histo[i] - if sum >= p0 * pop: - imin = i - break - sum = 0 - for i in range((maxbin - 1), -1, -1): - sum += histo[i] - if sum >= p1 * pop: - imax = i - break - - return (imax - imin) - else: - return (0) - - -cdef inline dtype_t kernel_mean(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef int i, sum, mean, n - - if pop: - sum = 0 - mean = 0 - n = 0 - for i in range(maxbin): - sum += histo[i] - if (sum >= p0 * pop) and (sum <= p1 * pop): - n += histo[i] - mean += histo[i] * i - - if n > 0: - return (1.0 * mean / n) - else: - return (0) - else: - return (0) - - -cdef inline dtype_t kernel_mean_subtraction(Py_ssize_t* histo, - float pop, - dtype_t g, - Py_ssize_t bitdepth, - Py_ssize_t maxbin, - Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef int i, sum, mean, n - - if pop: - sum = 0 - mean = 0 - n = 0 - for i in range(maxbin): - sum += histo[i] - if (sum >= p0 * pop) and (sum <= p1 * pop): - n += histo[i] - mean += histo[i] * i - if n > 0: - return ((g - (mean / n)) * .5 + midbin) - else: - return (0) - else: - return (0) - - -cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t* histo, - float pop, - dtype_t g, - Py_ssize_t bitdepth, - Py_ssize_t maxbin, - Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef int i, imin, imax, sum, delta - - if pop: - sum = 0 - p1 = 1.0 - p1 - for i in range(maxbin): - sum += histo[i] - if sum > p0 * pop: - imin = i - break - sum = 0 - for i in range((maxbin - 1), -1, -1): - sum += histo[i] - if sum > p1 * pop: - imax = i - break - if g > imax: - return imax - if g < imin: - return imin - if imax - g < g - imin: - return imax - else: - return imin - else: - return (0) - - -cdef inline dtype_t kernel_percentile(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef int i - cdef float sum = 0. - - if pop: - for i in range(maxbin): - sum += histo[i] - if sum >= p0 * pop: - break - - return (i) - else: - return (0) - - -cdef inline dtype_t kernel_pop(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef int i, sum, n - - if pop: - sum = 0 - n = 0 - for i in range(maxbin): - sum += histo[i] - if (sum >= p0 * pop) and (sum <= p1 * pop): - n += histo[i] - return (n) - else: - return (0) - - -cdef inline dtype_t kernel_threshold(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t bitdepth, - Py_ssize_t maxbin, Py_ssize_t midbin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - - cdef int i - cdef float sum = 0. - - if pop: - for i in range(maxbin): - sum += histo[i] - if sum >= p0 * pop: - break - - return ((maxbin - 1) * (g >= i)) - else: - return (0) - - -# ----------------------------------------------------------------- -# python wrappers -# ----------------------------------------------------------------- - - -def autolevel(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, int bitdepth=8, - float p0=0., float p1=0.): - """bottom hat - """ - _core16(kernel_autolevel, image, selem, mask, out, shift_x, shift_y, - bitdepth, p0, p1, 0, 0) - - -def gradient(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, int bitdepth=8, - float p0=0., float p1=0.): - """return p0,p1 percentile gradient - """ - _core16(kernel_gradient, image, selem, mask, out, shift_x, shift_y, - bitdepth, p0, p1, 0, 0) - - -def mean(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, int bitdepth=8, - float p0=0., float p1=0.): - """return mean between [p0 and p1] percentiles - """ - _core16(kernel_mean, image, selem, mask, out, shift_x, shift_y, - bitdepth, p0, p1, 0, 0) - - -def mean_subtraction(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, int bitdepth=8, - float p0=0., float p1=0.): - """return original - mean between [p0 and p1] percentiles *.5 +127 - """ - _core16( - kernel_mean_subtraction, image, selem, mask, out, shift_x, shift_y, - bitdepth, p0, p1, 0, 0) - - -def morph_contr_enh(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, int bitdepth=8, - float p0=0., float p1=0.): - """reforce contrast using percentiles - """ - _core16(kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y, - bitdepth, p0, p1, 0, 0) - - -def percentile(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, int bitdepth=8, - float p0=0.): - """return p0 percentile - """ - _core16(kernel_percentile, image, selem, mask, out, shift_x, shift_y, - bitdepth, p0, .0, 0, 0) - - -def pop(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, int bitdepth=8, - float p0=0., float p1=0.): - """return nb of pixels between [p0 and p1] - """ - _core16(kernel_pop, image, selem, mask, out, shift_x, shift_y, - bitdepth, p0, p1, 0, 0) - - -def threshold(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, int bitdepth=8, - float p0=0.): - """return (maxbin-1) if g > percentile p0 - """ - _core16(kernel_threshold, image, selem, mask, out, shift_x, shift_y, - bitdepth, p0, 0., 0, 0) diff --git a/skimage/filter/rank/percentile8_cy.pyx b/skimage/filter/rank/percentile8_cy.pyx deleted file mode 100644 index 3ce63478..00000000 --- a/skimage/filter/rank/percentile8_cy.pyx +++ /dev/null @@ -1,291 +0,0 @@ -#cython: cdivision=True -#cython: boundscheck=False -#cython: nonecheck=False -#cython: wraparound=False - -cimport numpy as cnp -from .core8_cy cimport dtype_t, _core8, uint8_max, uint8_min - - -# ----------------------------------------------------------------- -# kernels uint8 (SOFT version using percentiles) -# ----------------------------------------------------------------- - - -cdef inline dtype_t kernel_autolevel(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef int i, imin, imax, sum, delta - - if pop: - sum = 0 - p1 = 1.0 - p1 - imin = 0 - imax = 255 - - for i in range(256): - sum += histo[i] - if sum > (p0 * pop): - imin = i - break - sum = 0 - for i in range(255, -1, -1): - sum += histo[i] - if sum > (p1 * pop): - imax = i - break - delta = imax - imin - if delta > 0: - return (255 * (uint8_min(uint8_max(imin, g), imax) - - imin) / delta) - else: - return (imax - imin) - else: - return (128) - - -cdef inline dtype_t kernel_gradient(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef int i, imin, imax, sum, delta - - if pop: - sum = 0 - p1 = 1.0 - p1 - for i in range(256): - sum += histo[i] - if sum >= p0 * pop: - imin = i - break - sum = 0 - for i in range(255, -1, -1): - sum += histo[i] - if sum >= p1 * pop: - imax = i - break - - return (imax - imin) - else: - return (0) - - -cdef inline dtype_t kernel_mean(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef int i, sum, mean, n - - if pop: - sum = 0 - mean = 0 - n = 0 - for i in range(256): - sum += histo[i] - if (sum >= p0 * pop) and (sum <= p1 * pop): - n += histo[i] - mean += histo[i] * i - if n > 0: - return (1.0 * mean / n) - else: - return (0) - else: - return (0) - - -cdef inline dtype_t kernel_mean_subtraction(Py_ssize_t* histo, - float pop, - dtype_t g, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef int i, sum, mean, n - - if pop: - sum = 0 - mean = 0 - n = 0 - for i in range(256): - sum += histo[i] - if (sum >= p0 * pop) and (sum <= p1 * pop): - n += histo[i] - mean += histo[i] * i - if n > 0: - return ((g - (mean / n)) * .5 + 127) - else: - return (0) - else: - return (0) - - -cdef inline dtype_t kernel_morph_contr_enh(Py_ssize_t* histo, - float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef int i, imin, imax, sum, delta - - if pop: - sum = 0 - p1 = 1.0 - p1 - for i in range(256): - sum += histo[i] - if sum >= p0 * pop: - imin = i - break - sum = 0 - for i in range(255, -1, -1): - sum += histo[i] - if sum >= p1 * pop: - imax = i - break - if g > imax: - return imax - if g < imin: - return imin - if imax - g < g - imin: - return imax - else: - return imin - else: - return (0) - - -cdef inline dtype_t kernel_percentile(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef int i - cdef float sum = 0. - - if pop: - for i in range(256): - sum += histo[i] - if sum >= p0 * pop: - break - - return (i) - else: - return (0) - - -cdef inline dtype_t kernel_pop(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef int i, sum, n - - if pop: - sum = 0 - n = 0 - for i in range(256): - sum += histo[i] - if (sum >= p0 * pop) and (sum <= p1 * pop): - n += histo[i] - return (n) - else: - return (0) - - -cdef inline dtype_t kernel_threshold(Py_ssize_t* histo, float pop, - dtype_t g, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef int i - cdef float sum = 0. - - if pop: - for i in range(256): - sum += histo[i] - if sum >= p0 * pop: - break - - return (255 * (g >= i)) - else: - return (0) - - -# ----------------------------------------------------------------- -# python wrappers -# ----------------------------------------------------------------- - - -def autolevel(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, float p0=0., float p1=0.): - """autolevel - """ - _core8(kernel_autolevel, image, selem, mask, out, shift_x, shift_y, p0, p1, - 0, 0) - - -def gradient(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, float p0=0., float p1=0.): - """return p0,p1 percentile gradient - """ - _core8(kernel_gradient, image, selem, mask, out, shift_x, shift_y, p0, p1, - 0, 0) - - -def mean(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, float p0=0., float p1=0.): - """return mean between [p0 and p1] percentiles - """ - _core8(kernel_mean, image, selem, mask, out, shift_x, shift_y, p0, p1, - 0, 0) - - -def mean_subtraction(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, float p0=0., float p1=0.): - """return original - mean between [p0 and p1] percentiles *.5 +127 - """ - _core8(kernel_mean_subtraction, image, selem, mask, out, shift_x, shift_y, - p0, p1, 0, 0) - - -def morph_contr_enh(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, float p0=0., float p1=0.): - """reforce contrast using percentiles - """ - _core8(kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y, - p0, p1, 0, 0) - - -def percentile(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, float p0=0.): - """return p0 percentile - """ - _core8(kernel_percentile, image, selem, mask, out, shift_x, shift_y, - p0, 0., 0, 0) - - -def pop(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, float p0=0., float p1=0.): - """return nb of pixels between [p0 and p1] - """ - _core8(kernel_pop, image, selem, mask, out, shift_x, shift_y, p0, p1, - 0, 0) - - -def threshold(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask=None, - dtype_t[:, ::1] out=None, - char shift_x=0, char shift_y=0, float p0=0.): - """return 255 if g > percentile p0 - """ - _core8(kernel_threshold, image, selem, mask, out, shift_x, shift_y, p0, 0., - 0, 0) diff --git a/skimage/filter/rank/percentile_cy.pyx b/skimage/filter/rank/percentile_cy.pyx new file mode 100644 index 00000000..6df271fa --- /dev/null +++ b/skimage/filter/rank/percentile_cy.pyx @@ -0,0 +1,325 @@ +#cython: cdivision=True +#cython: boundscheck=False +#cython: nonecheck=False +#cython: wraparound=False + +cimport numpy as cnp +from .core_cy cimport uint8_t, uint16_t, dtype_t, _core, _min, _max + + +cdef inline dtype_t _kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i, imin, imax, sum, delta + + if pop: + sum = 0 + p1 = 1.0 - p1 + for i in range(max_bin - 1): + sum += histo[i] + if sum > p0 * pop: + imin = i + break + sum = 0 + for i in range(max_bin - 1, -1, -1): + sum += histo[i] + if sum > p1 * pop: + imax = i + break + + delta = imax - imin + if delta > 0: + return ((max_bin - 1) * (_min(_max(imin, g), imax) + - imin) / delta) + else: + return (imax - imin) + else: + return (0) + + +cdef inline dtype_t _kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i, imin, imax, sum, delta + + if pop: + sum = 0 + p1 = 1.0 - p1 + for i in range(max_bin): + sum += histo[i] + if sum >= p0 * pop: + imin = i + break + sum = 0 + for i in range((max_bin - 1), -1, -1): + sum += histo[i] + if sum >= p1 * pop: + imax = i + break + + return (imax - imin) + else: + return (0) + + +cdef inline dtype_t _kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i, sum, mean, n + + if pop: + sum = 0 + mean = 0 + n = 0 + for i in range(max_bin): + sum += histo[i] + if (sum >= p0 * pop) and (sum <= p1 * pop): + n += histo[i] + mean += histo[i] * i + + if n > 0: + return (mean / n) + else: + return (0) + else: + return (0) + + +cdef inline dtype_t _kernel_mean_subtraction(Py_ssize_t* histo, float pop, + dtype_t g, Py_ssize_t max_bin, + Py_ssize_t mid_bin, float p0, + float p1, Py_ssize_t s0, + Py_ssize_t s1): + + cdef Py_ssize_t i, sum, mean, n + + if pop: + sum = 0 + mean = 0 + n = 0 + for i in range(max_bin): + sum += histo[i] + if (sum >= p0 * pop) and (sum <= p1 * pop): + n += histo[i] + mean += histo[i] * i + if n > 0: + return ((g - (mean / n)) * .5 + mid_bin) + else: + return (0) + else: + return (0) + + +cdef inline dtype_t _kernel_morph_contr_enh(Py_ssize_t* histo, float pop, + dtype_t g, Py_ssize_t max_bin, + Py_ssize_t mid_bin, float p0, + float p1, Py_ssize_t s0, + Py_ssize_t s1): + + cdef Py_ssize_t i, imin, imax, sum, delta + + if pop: + sum = 0 + p1 = 1.0 - p1 + for i in range(max_bin): + sum += histo[i] + if sum > p0 * pop: + imin = i + break + sum = 0 + for i in range((max_bin - 1), -1, -1): + sum += histo[i] + if sum > p1 * pop: + imax = i + break + if g > imax: + return imax + if g < imin: + return imin + if imax - g < g - imin: + return imax + else: + return imin + else: + return (0) + + +cdef inline dtype_t _kernel_percentile(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i + cdef Py_ssize_t sum = 0 + + if pop: + for i in range(max_bin): + sum += histo[i] + if sum >= p0 * pop: + break + + return (i) + else: + return (0) + + +cdef inline dtype_t _kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i, sum, n + + if pop: + sum = 0 + n = 0 + for i in range(max_bin): + sum += histo[i] + if (sum >= p0 * pop) and (sum <= p1 * pop): + n += histo[i] + return (n) + else: + return (0) + + +cdef inline dtype_t _kernel_threshold(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef int i + cdef Py_ssize_t sum = 0 + + if pop: + for i in range(max_bin): + sum += histo[i] + if sum >= p0 * pop: + break + + return ((max_bin - 1) * (g >= i)) + else: + return (0) + + +def _autolevel(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, float p0, float p1, + Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_autolevel[uint8_t], image, selem, mask, out, + shift_x, shift_y, p0, p1, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_autolevel[uint16_t], image, selem, mask, out, + shift_x, shift_y, p0, p1, 0, 0, max_bin) + + +def _gradient(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, float p0, float p1, + Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_gradient[uint8_t], image, selem, mask, out, + shift_x, shift_y, p0, p1, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_gradient[uint16_t], image, selem, mask, out, + shift_x, shift_y, p0, p1, 0, 0, max_bin) + + +def _mean(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, float p0, float p1, + Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_mean[uint8_t], image, selem, mask, out, + shift_x, shift_y, p0, p1, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_mean[uint16_t], image, selem, mask, out, + shift_x, shift_y, p0, p1, 0, 0, max_bin) + + +def _mean_subtraction(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, float p0, float p1, + Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_mean_subtraction[uint8_t], image, selem, mask, + out, shift_x, shift_y, p0, p1, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_mean_subtraction[uint16_t], image, selem, mask, + out, shift_x, shift_y, p0, p1, 0, 0, max_bin) + + +def _morph_contr_enh(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, float p0, float p1, + Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_morph_contr_enh[uint8_t], image, selem, mask, + out, shift_x, shift_y, p0, p1, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_morph_contr_enh[uint16_t], image, selem, mask, + out, shift_x, shift_y, p0, p1, 0, 0, max_bin) + + +def _percentile(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, float p0, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_percentile[uint8_t], image, selem, mask, out, + shift_x, shift_y, p0, 1, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_percentile[uint16_t], image, selem, mask, out, + shift_x, shift_y, p0, 1, 0, 0, max_bin) + + +def _pop(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, float p0, float p1, + Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_pop[uint8_t], image, selem, mask, out, + shift_x, shift_y, p0, p1, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_pop[uint16_t], image, selem, mask, out, + shift_x, shift_y, p0, p1, 0, 0, max_bin) + + +def _threshold(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, float p0, Py_ssize_t max_bin): + + if dtype_t is uint8_t: + _core[uint8_t](_kernel_threshold[uint8_t], image, selem, mask, out, + shift_x, shift_y, p0, 1, 0, 0, max_bin) + elif dtype_t is uint16_t: + _core[uint16_t](_kernel_threshold[uint16_t], image, selem, mask, out, + shift_x, shift_y, p0, 1, 0, 0, max_bin) diff --git a/skimage/filter/rank/tests/test_rank.py b/skimage/filter/rank/tests/test_rank.py index 1efe2bff..f55d3522 100644 --- a/skimage/filter/rank/tests/test_rank.py +++ b/skimage/filter/rank/tests/test_rank.py @@ -176,12 +176,10 @@ def test_compare_autolevels_16bit(): assert_array_equal(loc_autolevel, loc_perc_autolevel) -def test_compare_uint_vs_float(): - # filters applied on 8-bit image ore 16-bit image (having only real 8-bit of - # dynamic) should be identical +def test_compare_ubyte_vs_float(): # Create signed int8 image that and convert it to uint8 - image_uint = img_as_uint(data.camera()[:50, :50]) + image_uint = img_as_ubyte(data.camera()[:50, :50]) image_float = img_as_float(image_uint) methods = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'threshold', @@ -372,37 +370,37 @@ def test_entropy(): selem = np.ones((16, 16), dtype=np.uint8) # 1 bit per pixel data = np.tile(np.asarray([0, 1]), (100, 100)).astype(np.uint8) - assert(np.max(rank.entropy(data, selem)) == 10) + assert(np.max(rank.entropy(data, selem)) == 1) # 2 bit per pixel data = np.tile(np.asarray([[0, 1], [2, 3]]), (10, 10)).astype(np.uint8) - assert(np.max(rank.entropy(data, selem)) == 20) + assert(np.max(rank.entropy(data, selem)) == 2) # 3 bit per pixel data = np.tile( np.asarray([[0, 1, 2, 3], [4, 5, 6, 7]]), (10, 10)).astype(np.uint8) - assert(np.max(rank.entropy(data, selem)) == 30) + assert(np.max(rank.entropy(data, selem)) == 3) # 4 bit per pixel data = np.tile( np.reshape(np.arange(16), (4, 4)), (10, 10)).astype(np.uint8) - assert(np.max(rank.entropy(data, selem)) == 40) + assert(np.max(rank.entropy(data, selem)) == 4) # 6 bit per pixel data = np.tile( np.reshape(np.arange(64), (8, 8)), (10, 10)).astype(np.uint8) - assert(np.max(rank.entropy(data, selem)) == 60) + assert(np.max(rank.entropy(data, selem)) == 6) # 8-bit per pixel data = np.tile( np.reshape(np.arange(256), (16, 16)), (10, 10)).astype(np.uint8) - assert(np.max(rank.entropy(data, selem)) == 80) + assert(np.max(rank.entropy(data, selem)) == 8) # 12 bit per pixel selem = np.ones((64, 64), dtype=np.uint8) data = np.tile( np.reshape(np.arange(4096), (64, 64)), (2, 2)).astype(np.uint16) - assert(np.max(rank.entropy(data, selem)) == 12000) + assert(np.max(rank.entropy(data, selem)) == 12) def test_selem_dtypes(): diff --git a/skimage/filter/setup.py b/skimage/filter/setup.py index 35626114..33ad97df 100644 --- a/skimage/filter/setup.py +++ b/skimage/filter/setup.py @@ -14,34 +14,24 @@ def configuration(parent_package='', top_path=None): cython(['_ctmf.pyx'], working_path=base_path) cython(['_denoise_cy.pyx'], working_path=base_path) - cython(['rank/core8_cy.pyx'], working_path=base_path) - cython(['rank/core16_cy.pyx'], working_path=base_path) - cython(['rank/generic8_cy.pyx'], working_path=base_path) - cython(['rank/percentile8_cy.pyx'], working_path=base_path) - cython(['rank/generic16_cy.pyx'], working_path=base_path) - cython(['rank/percentile16_cy.pyx'], working_path=base_path) - cython(['rank/bilateral16_cy.pyx'], working_path=base_path) + cython(['rank/core_cy.pyx'], working_path=base_path) + cython(['rank/generic_cy.pyx'], working_path=base_path) + cython(['rank/percentile_cy.pyx'], working_path=base_path) + cython(['rank/bilateral_cy.pyx'], working_path=base_path) config.add_extension('_ctmf', sources=['_ctmf.c'], include_dirs=[get_numpy_include_dirs()]) config.add_extension('_denoise_cy', sources=['_denoise_cy.c'], include_dirs=[get_numpy_include_dirs(), '../_shared']) - config.add_extension('rank.core8_cy', sources=['rank/core8_cy.c'], + config.add_extension('rank.core_cy', sources=['rank/core_cy.c'], include_dirs=[get_numpy_include_dirs()]) - config.add_extension('rank.core16_cy', sources=['rank/core16_cy.c'], - include_dirs=[get_numpy_include_dirs()]) - config.add_extension('rank.generic8_cy', sources=['rank/generic8_cy.c'], + config.add_extension('rank.generic_cy', sources=['rank/generic_cy.c'], include_dirs=[get_numpy_include_dirs()]) config.add_extension( - 'rank.percentile8_cy', sources=['rank/percentile8_cy.c'], - include_dirs=[get_numpy_include_dirs()]) - config.add_extension('rank.generic16_cy', sources=['rank/generic16_cy.c'], + 'rank.percentile_cy', sources=['rank/percentile_cy.c'], include_dirs=[get_numpy_include_dirs()]) config.add_extension( - 'rank.percentile16_cy', sources=['rank/percentile16_cy.c'], - include_dirs=[get_numpy_include_dirs()]) - config.add_extension( - 'rank.bilateral16_cy', sources=['rank/bilateral16_cy.c'], + 'rank.bilateral_cy', sources=['rank/bilateral_cy.c'], include_dirs=[get_numpy_include_dirs()]) return config From 68914b8934414e7ed62b26e6d43de2c0d48bd500 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Tue, 2 Jul 2013 00:18:14 +0200 Subject: [PATCH 20/43] Update bento config --- bento.info | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/bento.info b/bento.info index fe07dc5d..d7ddcecc 100644 --- a/bento.info +++ b/bento.info @@ -123,27 +123,18 @@ Library: Extension: skimage._shared.geometry Sources: skimage/_shared/geometry.pyx - Extension: skimage.filter.rank.bilateral16_cy + Extension: skimage.filter.rank.generic_cy Sources: - skimage/filter/rank/bilateral16_cy.pyx - Extension: skimage.filter.rank.generic8_cy + skimage/filter/rank/generic_cy.pyx + Extension: skimage.filter.rank.percentile_cy Sources: - skimage/filter/rank/generic8_cy.pyx - Extension: skimage.filter.rank.percentile16_cy + skimage/filter/rank/percentile_cy.pyx + Extension: skimage.filter.rank.core_cy Sources: - skimage/filter/rank/percentile16_cy.pyx - Extension: skimage.filter.rank.core16_cy + skimage/filter/rank/core_cy.pyx + Extension: skimage.filter.rank.bilateral_cy Sources: - skimage/filter/rank/core16_cy.pyx - Extension: skimage.filter.rank.core8_cy - Sources: - skimage/filter/rank/core8_cy.pyx - Extension: skimage.filter.rank.generic16_cy - Sources: - skimage/filter/rank/generic16_cy.pyx - Extension: skimage.filter.rank.percentile8_cy - Sources: - skimage/filter/rank/percentile8_cy.pyx + skimage/filter/rank/bilateral_cy.pyx Executable: skivi Module: skimage.scripts.skivi From 34ad95d9175588db0c53095289c151c609eef0dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Tue, 2 Jul 2013 00:24:36 +0200 Subject: [PATCH 21/43] Improve entropy example --- doc/examples/plot_entropy.py | 34 +++++++++++----------------------- 1 file changed, 11 insertions(+), 23 deletions(-) diff --git a/doc/examples/plot_entropy.py b/doc/examples/plot_entropy.py index db230d8b..2c06c2bb 100644 --- a/doc/examples/plot_entropy.py +++ b/doc/examples/plot_entropy.py @@ -3,6 +3,9 @@ Entropy ======= +Image entropy is a quantity which is used to describe the amount of information +coded in an image. + """ import numpy as np import matplotlib.pyplot as plt @@ -13,33 +16,18 @@ from skimage.morphology import disk from skimage.util import img_as_ubyte -# defining a 8- and a 16-bit test images -a8 = img_as_ubyte(data.camera()) -a16 = a8.astype(np.uint16) * 4 +image = img_as_ubyte(data.camera()) -ent8 = entropy(a8, disk(5)) # pixel value contain 10x the local entropy -ent16 = entropy(a16, disk(5)) # pixel value contain 1000x the local entropy +plt.figure(figsize=(10, 4)) -# display results -plt.figure(figsize=(10, 10)) - -plt.subplot(2,2,1) -plt.imshow(a8, cmap=plt.cm.gray) -plt.xlabel('8-bit image') +plt.subplot(121) +plt.imshow(image, cmap=plt.cm.gray) +plt.title('Image') plt.colorbar() -plt.subplot(2,2,2) -plt.imshow(ent8, cmap=plt.cm.jet) -plt.xlabel('entropy*10') +plt.subplot(122) +plt.imshow(entropy(image, disk(5)), cmap=plt.cm.jet) +plt.title('Entropy') plt.colorbar() -plt.subplot(2,2,3) -plt.imshow(a16, cmap=plt.cm.gray) -plt.xlabel('16-bit image') -plt.colorbar() - -plt.subplot(2,2,4) -plt.imshow(ent16, cmap=plt.cm.jet) -plt.xlabel('entropy*1000') -plt.colorbar() plt.show() From 73492045b263c20f9b0c6f84055ef0af0b197085 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Tue, 2 Jul 2013 00:28:16 +0200 Subject: [PATCH 22/43] Improve mean example --- doc/examples/plot_rank_mean.py | 37 ++++++++++++++++++++-------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/doc/examples/plot_rank_mean.py b/doc/examples/plot_rank_mean.py index e23beb18..013535cb 100644 --- a/doc/examples/plot_rank_mean.py +++ b/doc/examples/plot_rank_mean.py @@ -6,9 +6,9 @@ Mean filters This example compares the following mean filters of the rank filter package: * **local mean**: all pixels belonging to the structuring element to compute - average gray level + average gray level. * **percentile mean**: only use values between percentiles p0 and p1 - (here 10% and 90%) + (here 10% and 90%). * **bilateral mean**: only use pixels of the structuring element having a gray level situated inside g-s0 and g+s1 (here g-500 and g+500) @@ -23,23 +23,30 @@ import matplotlib.pyplot as plt from skimage import data from skimage.morphology import disk -import skimage.filter.rank as rank +from skimage.filter import rank -a16 = (data.coins()).astype(np.uint16) * 16 + +image = (data.coins()).astype(np.uint16) * 16 selem = disk(20) -f1 = rank.percentile_mean(a16, selem=selem, p0=.1, p1=.9) -f2 = rank.bilateral_mean(a16, selem=selem, s0=500, s1=500) -f3 = rank.mean(a16, selem=selem) +percentile_result = rank.percentile_mean(image, selem=selem, p0=.1, p1=.9) +bilateral_result = rank.bilateral_mean(image, selem=selem, s0=500, s1=500) +normal_result = rank.mean(image, selem=selem) -# display results -fig, axes = plt.subplots(nrows=3, figsize=(15, 10)) + +fig, axes = plt.subplots(nrows=3, figsize=(8, 10)) ax0, ax1, ax2 = axes -ax0.imshow(np.hstack((a16, f1))) -ax0.set_title('percentile mean') -ax1.imshow(np.hstack((a16, f2))) -ax1.set_title('bilateral mean') -ax2.imshow(np.hstack((a16, f3))) -ax2.set_title('local mean') +ax0.imshow(np.hstack((image, percentile_result))) +ax0.set_title('Percentile mean') +ax0.axis('off') + +ax1.imshow(np.hstack((image, bilateral_result))) +ax1.set_title('Bilateral mean') +ax1.axis('off') + +ax2.imshow(np.hstack((image, normal_result))) +ax2.set_title('Local mean') +ax2.axis('off') + plt.show() From d1e0949533ad30e2cd3e5afccbf59d835c1b0fe3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Tue, 2 Jul 2013 00:32:46 +0200 Subject: [PATCH 23/43] Update entropy example with improved matplotlib usage --- doc/examples/plot_entropy.py | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/doc/examples/plot_entropy.py b/doc/examples/plot_entropy.py index 2c06c2bb..ed5519bd 100644 --- a/doc/examples/plot_entropy.py +++ b/doc/examples/plot_entropy.py @@ -18,16 +18,17 @@ from skimage.util import img_as_ubyte image = img_as_ubyte(data.camera()) -plt.figure(figsize=(10, 4)) +fig, (ax0, ax1) = plt.subplots(ncols=2, figsize=(10, 4)) -plt.subplot(121) -plt.imshow(image, cmap=plt.cm.gray) -plt.title('Image') -plt.colorbar() -plt.subplot(122) -plt.imshow(entropy(image, disk(5)), cmap=plt.cm.jet) -plt.title('Entropy') -plt.colorbar() +img0 = ax0.imshow(image, cmap=plt.cm.gray) +ax0.set_title('Image') +ax0.axis('off') +plt.colorbar(img0, ax=ax0) + +img1 = ax1.imshow(entropy(image, disk(5)), cmap=plt.cm.jet) +ax1.set_title('Entropy') +ax1.axis('off') +plt.colorbar(img1, ax=ax1) plt.show() From d6fb12a493abdce2a68cba5e6ed61cde303f5443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Tue, 2 Jul 2013 01:12:51 +0200 Subject: [PATCH 24/43] Improve long rank filter example --- .../applications/plot_rank_filters.py | 421 ++++++++++-------- doc/examples/plot_entropy.py | 1 - 2 files changed, 237 insertions(+), 185 deletions(-) diff --git a/doc/examples/applications/plot_rank_filters.py b/doc/examples/applications/plot_rank_filters.py index 31284226..ded335bd 100644 --- a/doc/examples/applications/plot_rank_filters.py +++ b/doc/examples/applications/plot_rank_filters.py @@ -3,11 +3,11 @@ Rank filters ============ -Rank filters are non-linear filters using the local greylevels ordering to +Rank filters are non-linear filters using the local gray-level ordering to compute the filtered value. This ensemble of filters share a common base: the -local grey-level histogram extraction computed on the neighborhood of a pixel -(defined by a 2D structuring element). If the filtered value is taken as the -middle value of the histogram, we get the classical median filter. +local gray-level histogram is computed on the neighborhood of a pixel (defined +by a 2-D structuring element). If the filtered value is taken as the middle +value of the histogram, we get the classical median filter. Rank filters can be used for several purposes such as: @@ -26,11 +26,9 @@ Rank filters can be used for several purposes such as: Some well known filters are specific cases of rank filters [1]_ e.g. morphological dilation, morphological erosion, median filters. -The different implementation availables in `skimage` are compared. - -In this example, we will see how to filter a greylevel image using some of the -linear and non-linear filters availables in skimage. We use the `camera` -image from `skimage.data`. +In this example, we will see how to filter a gray-level image using some of the +linear and non-linear filters available in skimage. We use the `camera` image +from `skimage.data` for all comparisons. .. [1] Pierre Soille, On morphological operators based on rank filters, Pattern Recognition 35 (2002) 527-535. @@ -42,16 +40,16 @@ import matplotlib.pyplot as plt from skimage import data -ima = data.camera() -hist = np.histogram(ima, bins=np.arange(0, 256)) +noisy_image = data.camera() +hist = np.histogram(noisy_image, bins=np.arange(0, 256)) plt.figure(figsize=(8, 3)) plt.subplot(1, 2, 1) -plt.imshow(ima, cmap=plt.cm.gray, interpolation='nearest') +plt.imshow(noisy_image, interpolation='nearest') plt.axis('off') plt.subplot(1, 2, 2) plt.plot(hist[1][:-1], hist[0], lw=2) -plt.title('histogram of grey values') +plt.title('Histogram of grey values') """ @@ -65,50 +63,56 @@ randomly set to 0. The **median** filter is applied to remove the noise. .. note:: - there are different implementations of median filter : + There are different implementations of median filter: `skimage.filter.median_filter` and `skimage.filter.rank.median` """ -noise = np.random.random(ima.shape) -nima = data.camera() -nima[noise > 0.99] = 255 -nima[noise < 0.01] = 0 - from skimage.filter.rank import median from skimage.morphology import disk -fig = plt.figure(figsize=[10, 7]) +noise = np.random.random(noisy_image.shape) +noisy_image = data.camera() +noisy_image[noise > 0.99] = 255 +noisy_image[noise < 0.01] = 0 + +fig = plt.figure(figsize=(10, 7)) -lo = median(nima, disk(1)) -hi = median(nima, disk(5)) -ext = median(nima, disk(20)) plt.subplot(2, 2, 1) -plt.imshow(nima, cmap=plt.cm.gray, vmin=0, vmax=255) -plt.xlabel('noised image') +plt.imshow(noisy_image, vmin=0, vmax=255) +plt.title('Noisy image') +plt.axis('off') + plt.subplot(2, 2, 2) -plt.imshow(lo, cmap=plt.cm.gray, vmin=0, vmax=255) -plt.xlabel('median $r=1$') +plt.imshow(median(noisy_image, disk(1)), vmin=0, vmax=255) +plt.title('Median $r=1$') +plt.axis('off') + plt.subplot(2, 2, 3) -plt.imshow(hi, cmap=plt.cm.gray, vmin=0, vmax=255) -plt.xlabel('median $r=5$') +plt.imshow(median(noisy_image, disk(5)), vmin=0, vmax=255) +plt.title('Median $r=5$') +plt.axis('off') + plt.subplot(2, 2, 4) -plt.imshow(ext, cmap=plt.cm.gray, vmin=0, vmax=255) -plt.xlabel('median $r=20$') +plt.imshow(median(noisy_image, disk(20)), vmin=0, vmax=255) +plt.title('Median $r=20$') +plt.axis('off') """ .. image:: PLOT2RST.current_figure -The added noise is efficiently removed, as the image defaults are small (1 pixel -wide), a small filter radius is sufficient. As the radius is increasing, objects -with a bigger size are filtered as well, such as the camera tripod. The median -filter is commonly used for noise removal because borders are preserved. +The added noise is efficiently removed, as the image defaults are small (1 +pixel wide), a small filter radius is sufficient. As the radius is increasing, +objects with bigger sizes are filtered as well, such as the camera tripod. The +median filter is often used for noise removal because borders are preserved and +e.g. salt and pepper noise typically does not distort the gray-level. Image smoothing ================ -The example hereunder shows how a local **mean** smoothes the camera man image. +The example hereunder shows how a local **mean** filter smooths the camera man +image. """ @@ -116,13 +120,17 @@ from skimage.filter.rank import mean fig = plt.figure(figsize=[10, 7]) -loc_mean = mean(nima, disk(10)) +loc_mean = mean(noisy_image, disk(10)) + plt.subplot(1, 2, 1) -plt.imshow(ima, cmap=plt.cm.gray, vmin=0, vmax=255) -plt.xlabel('original') +plt.imshow(noisy_image, vmin=0, vmax=255) +plt.title('Original') +plt.axis('off') + plt.subplot(1, 2, 2) -plt.imshow(loc_mean, cmap=plt.cm.gray, vmin=0, vmax=255) -plt.xlabel('local mean $r=10$') +plt.imshow(loc_mean, vmin=0, vmax=255) +plt.title('Local mean $r=10$') +plt.axis('off') """ @@ -130,35 +138,42 @@ plt.xlabel('local mean $r=10$') One may be interested in smoothing an image while preserving important borders (median filters already achieved this), here we use the **bilateral** filter -that restricts the local neighborhood to pixel having a greylevel similar to +that restricts the local neighborhood to pixel having a gray-level similar to the central one. .. note:: - a different implementation is available for color images in + A different implementation is available for color images in `skimage.filter.denoise_bilateral`. """ from skimage.filter.rank import bilateral_mean -ima = data.camera() +noisy_image = data.camera() selem = disk(10) -bilat = bilateral_mean(ima.astype(np.uint16), disk(20), s0=10, s1=10) +bilat = bilateral_mean(noisy_image.astype(np.uint16), disk(20), s0=10, s1=10) -# display results fig = plt.figure(figsize=[10, 7]) + plt.subplot(2, 2, 1) -plt.imshow(ima, cmap=plt.cm.gray) -plt.xlabel('original') +plt.imshow(noisy_image, cmap=plt.cm.gray) +plt.title('Original') +plt.axis('off') + plt.subplot(2, 2, 3) plt.imshow(bilat, cmap=plt.cm.gray) -plt.xlabel('bilateral mean') +plt.title('Bilateral mean') +plt.axis('off') + plt.subplot(2, 2, 2) -plt.imshow(ima[200:350, 350:450], cmap=plt.cm.gray) +plt.imshow(noisy_image[200:350, 350:450], cmap=plt.cm.gray) +plt.axis('off') + plt.subplot(2, 2, 4) plt.imshow(bilat[200:350, 350:450], cmap=plt.cm.gray) +plt.axis('off') """ @@ -175,7 +190,7 @@ We compare here how the global histogram equalization is applied locally. The equalized image [2]_ has a roughly linear cumulative distribution function for each pixel neighborhood. The local version [3]_ of the histogram -equalization emphasizes every local greylevel variations. +equalization emphasizes every local gray-level variations. .. [2] http://en.wikipedia.org/wiki/Histogram_equalization .. [3] http://en.wikipedia.org/wiki/Adaptive_histogram_equalization @@ -185,74 +200,86 @@ equalization emphasizes every local greylevel variations. from skimage import exposure from skimage.filter import rank -ima = data.camera() +noisy_image = data.camera() + # equalize globally and locally -glob = exposure.equalize(ima) * 255 -loc = rank.equalize(ima, disk(20)) +glob = exposure.equalize(noisy_image) * 255 +loc = rank.equalize(noisy_image, disk(20)) # extract histogram for each image -hist = np.histogram(ima, bins=np.arange(0, 256)) +hist = np.histogram(noisy_image, bins=np.arange(0, 256)) glob_hist = np.histogram(glob, bins=np.arange(0, 256)) loc_hist = np.histogram(loc, bins=np.arange(0, 256)) plt.figure(figsize=(10, 10)) + plt.subplot(321) -plt.imshow(ima, cmap=plt.cm.gray, interpolation='nearest') +plt.imshow(noisy_image, interpolation='nearest') plt.axis('off') + plt.subplot(322) plt.plot(hist[1][:-1], hist[0], lw=2) -plt.title('histogram of grey values') +plt.title('Histogram of gray values') + plt.subplot(323) -plt.imshow(glob, cmap=plt.cm.gray, interpolation='nearest') +plt.imshow(glob, interpolation='nearest') plt.axis('off') + plt.subplot(324) plt.plot(glob_hist[1][:-1], glob_hist[0], lw=2) -plt.title('histogram of grey values') +plt.title('Histogram of gray values') + plt.subplot(325) -plt.imshow(loc, cmap=plt.cm.gray, interpolation='nearest') +plt.imshow(loc, interpolation='nearest') plt.axis('off') + plt.subplot(326) plt.plot(loc_hist[1][:-1], loc_hist[0], lw=2) -plt.title('histogram of grey values') +plt.title('Histogram of gray values') """ .. image:: PLOT2RST.current_figure -another way to maximize the number of greylevels used for an image is to apply -a local autoleveling, i.e. here a pixel greylevel is proportionally remapped -between local minimum and local maximum. +Another way to maximize the number of gray-levels used for an image is to apply +a local auto-leveling, i.e. the gray-value of a pixel is proportionally +remapped between local minimum and local maximum. -The following example shows how local autolevel enhances the camara man picture. +The following example shows how local auto-level enhances the camara man +picture. """ from skimage.filter.rank import autolevel -ima = data.camera() +noisy_image = data.camera() selem = disk(10) -auto = autolevel(ima.astype(np.uint16), disk(20)) +auto = autolevel(noisy_image.astype(np.uint16), disk(20)) -# display results fig = plt.figure(figsize=[10, 7]) + plt.subplot(1, 2, 1) -plt.imshow(ima, cmap=plt.cm.gray) -plt.xlabel('original') +plt.imshow(noisy_image, cmap=plt.cm.gray) +plt.title('Original') +plt.axis('off') + plt.subplot(1, 2, 2) plt.imshow(auto, cmap=plt.cm.gray) -plt.xlabel('local autolevel') +plt.title('Local autolevel') +plt.axis('off') """ .. image:: PLOT2RST.current_figure -This filter is very sensitive to local outlayers, see the little white spot in -the sky left part. This is due to a local maximum which is very high comparing -to the rest of the neighborhood. One can moderate this using the percentile -version of the autolevel filter which uses given percentiles (one inferior, -one superior) in place of local minimum and maximum. The example below -illustrates how the percentile parameters influence the local autolevel result. +This filter is very sensitive to local outliers, see the little white spot in +the left part of the sky. This is due to a local maximum which is very high +comparing to the rest of the neighborhood. One can moderate this using the +percentile version of the auto-level filter which uses given percentiles (one +inferior, one superior) in place of local minimum and maximum. The example +below illustrates how the percentile parameters influence the local auto-level +result. """ @@ -272,14 +299,14 @@ ax0, ax1, ax2 = axes plt.gray() ax0.imshow(np.hstack((image, loc_autolevel))) -ax0.set_title('original / autolevel') +ax0.set_title('Original / auto-level') ax1.imshow( np.hstack((loc_perc_autolevel0, loc_perc_autolevel1)), vmin=0, vmax=255) -ax1.set_title('percentile autolevel 0%,1%') +ax1.set_title('Percentile auto-level 0%,1%') ax2.imshow( np.hstack((loc_perc_autolevel2, loc_perc_autolevel3)), vmin=0, vmax=255) -ax2.set_title('percentile autolevel 5% and 10%') +ax2.set_title('Percentile auto-level 5% and 10%') for ax in axes: ax.axis('off') @@ -289,29 +316,35 @@ for ax in axes: .. image:: PLOT2RST.current_figure The morphological contrast enhancement filter replaces the central pixel by the -local maximum if the original pixel value is closest to local maximum, otherwise -by the minimum local. +local maximum if the original pixel value is closest to local maximum, +otherwise by the minimum local. """ from skimage.filter.rank import morph_contr_enh -ima = data.camera() +noisy_image = data.camera() -enh = morph_contr_enh(ima, disk(5)) +enh = morph_contr_enh(noisy_image, disk(5)) -# display results fig = plt.figure(figsize=[10, 7]) plt.subplot(2, 2, 1) -plt.imshow(ima, cmap=plt.cm.gray) -plt.xlabel('original') +plt.imshow(noisy_image, cmap=plt.cm.gray) +plt.title('Original') +plt.axis('off') + plt.subplot(2, 2, 3) plt.imshow(enh, cmap=plt.cm.gray) -plt.xlabel('local morphlogical contrast enhancement') +plt.title('Local morphological contrast enhancement') +plt.axis('off') + plt.subplot(2, 2, 2) -plt.imshow(ima[200:350, 350:450], cmap=plt.cm.gray) +plt.imshow(noisy_image[200:350, 350:450], cmap=plt.cm.gray) +plt.axis('off') + plt.subplot(2, 2, 4) plt.imshow(enh[200:350, 350:450], cmap=plt.cm.gray) +plt.axis('off') """ @@ -324,22 +357,28 @@ percentile *p0* and *p1* instead of the local minimum and maximum. from skimage.filter.rank import percentile_morph_contr_enh -ima = data.camera() +noisy_image = data.camera() -penh = percentile_morph_contr_enh(ima, disk(5), p0=.1, p1=.9) +penh = percentile_morph_contr_enh(noisy_image, disk(5), p0=.1, p1=.9) -# display results fig = plt.figure(figsize=[10, 7]) plt.subplot(2, 2, 1) -plt.imshow(ima, cmap=plt.cm.gray) -plt.xlabel('original') +plt.imshow(noisy_image, cmap=plt.cm.gray) +plt.title('Original') +plt.axis('off') + plt.subplot(2, 2, 3) plt.imshow(penh, cmap=plt.cm.gray) -plt.xlabel('local percentile morphlogical\n contrast enhancement') +plt.title('Local percentile morphological\n contrast enhancement') +plt.axis('off') + plt.subplot(2, 2, 2) -plt.imshow(ima[200:350, 350:450], cmap=plt.cm.gray) +plt.imshow(noisy_image[200:350, 350:450], cmap=plt.cm.gray) +plt.axis('off') + plt.subplot(2, 2, 4) plt.imshow(penh[200:350, 350:450], cmap=plt.cm.gray) +plt.axis('off') """ @@ -348,18 +387,18 @@ plt.imshow(penh[200:350, 350:450], cmap=plt.cm.gray) Image threshold =============== -The Otsu's threshold [1]_ method can be applied locally using the local -greylevel distribution. In the example below, for each pixel, an "optimal" -threshold is determined by maximizing the variance between two classes of pixels -of the local neighborhood defined by a structuring element. +The Otsu threshold [1]_ method can be applied locally using the local gray- +level distribution. In the example below, for each pixel, an "optimal" +threshold is determined by maximizing the variance between two classes of +pixels of the local neighborhood defined by a structuring element. The example compares the local threshold with the global threshold `skimage.filter.threshold_otsu`. .. note:: - Local thresholding is much slower than global one. There exists a function - for global Otsu thresholding: `skimage.filter.threshold_otsu`. + Local is much slower than global thresholding. A function for global Otsu + thresholding can be found in : `skimage.filter.threshold_otsu`. .. [4] http://en.wikipedia.org/wiki/Otsu's_method @@ -382,27 +421,35 @@ t_glob_otsu = threshold_otsu(p8) glob_otsu = p8 >= t_glob_otsu plt.figure() + plt.subplot(2, 2, 1) plt.imshow(p8, cmap=plt.cm.gray) -plt.xlabel('original') +plt.title('Original') plt.colorbar() +plt.axis('off') + plt.subplot(2, 2, 2) plt.imshow(t_loc_otsu, cmap=plt.cm.gray) -plt.xlabel('local Otsu ($radius=%d$)' % radius) +plt.title('Local Otsu ($r=%d$)' % radius) plt.colorbar() +plt.axis('off') + plt.subplot(2, 2, 3) plt.imshow(p8 >= t_loc_otsu, cmap=plt.cm.gray) -plt.xlabel('original>=local Otsu' % t_glob_otsu) +plt.title('Original >= local Otsu' % t_glob_otsu) +plt.axis('off') + plt.subplot(2, 2, 4) plt.imshow(glob_otsu, cmap=plt.cm.gray) -plt.xlabel('global Otsu ($t=%d$)' % t_glob_otsu) +plt.title('Global Otsu ($t=%d$)' % t_glob_otsu) +plt.axis('off') """ .. image:: PLOT2RST.current_figure -The following example shows how local Otsu's threshold handles a global level -shift applied to a synthetic image . +The following example shows how local Otsu thresholding handles a global level +shift applied to a synthetic image. """ @@ -413,13 +460,18 @@ m = (np.tile(x, (n, 1)) * np.linspace(0.1, 1, n) * 128 + 128).astype(np.uint8) radius = 10 t = rank.otsu(m, disk(radius)) + plt.figure() + plt.subplot(1, 2, 1) plt.imshow(m) -plt.xlabel('original') +plt.title('Original') +plt.axis('off') + plt.subplot(1, 2, 2) plt.imshow(m >= t, interpolation='nearest') -plt.xlabel('local Otsu ($radius=%d$)' % radius) +plt.title('Local Otsu ($r=%d$)' % radius) +plt.axis('off') """ @@ -428,7 +480,7 @@ plt.xlabel('local Otsu ($radius=%d$)' % radius) Image morphology ================ -Local maximum and local minimum are the base operators for greylevel +Local maximum and local minimum are the base operators for gray-level morphology. .. note:: @@ -436,33 +488,41 @@ morphology. `skimage.dilate` and `skimage.erode` are equivalent filters (see below for comparison). -Here is an example of the classical morphological greylevel filters: opening, +Here is an example of the classical morphological gray-level filters: opening, closing and morphological gradient. """ from skimage.filter.rank import maximum, minimum, gradient -ima = data.camera() +noisy_image = data.camera() -closing = maximum(minimum(ima, disk(5)), disk(5)) -opening = minimum(maximum(ima, disk(5)), disk(5)) -grad = gradient(ima, disk(5)) +closing = maximum(minimum(noisy_image, disk(5)), disk(5)) +opening = minimum(maximum(noisy_image, disk(5)), disk(5)) +grad = gradient(noisy_image, disk(5)) # display results fig = plt.figure(figsize=[10, 7]) + plt.subplot(2, 2, 1) -plt.imshow(ima, cmap=plt.cm.gray) -plt.xlabel('original') +plt.imshow(noisy_image, cmap=plt.cm.gray) +plt.title('Original') +plt.axis('off') + plt.subplot(2, 2, 2) plt.imshow(closing, cmap=plt.cm.gray) -plt.xlabel('greylevel closing') +plt.title('Gray-level closing') +plt.axis('off') + plt.subplot(2, 2, 3) plt.imshow(opening, cmap=plt.cm.gray) -plt.xlabel('greylevel opening') +plt.title('Gray-level opening') +plt.axis('off') + plt.subplot(2, 2, 4) plt.imshow(grad, cmap=plt.cm.gray) -plt.xlabel('morphological gradient') +plt.title('Morphological gradient') +plt.axis('off') """ @@ -471,13 +531,14 @@ plt.xlabel('morphological gradient') Feature extraction =================== -Local histogram can be exploited to compute local entropy, which is related to +Local histograms can be exploited to compute local entropy, which is related to the local image complexity. Entropy is computed using base 2 logarithm i.e. the -filter returns the minimum number of bits needed to encode local greylevel +filter returns the minimum number of bits needed to encode local gray-level distribution. -`skimage.rank.entropy` returns local entropy on a given structuring element. -The following example shows this filter applied on 8- and 16- bit images. +`skimage.rank.entropy` returns the local entropy on a given structuring +element. The following example shows applies this filter on 8- and 16-bit +images. .. note:: @@ -492,47 +553,36 @@ from skimage.morphology import disk import numpy as np import matplotlib.pyplot as plt -# defining a 8- and a 16-bit test images -a8 = data.camera() -a16 = data.camera().astype(np.uint16) * 4 +image = data.camera() -ent8 = entropy(a8, disk(5)) # pixel value contain 10x the local entropy -ent16 = entropy(a16, disk(5)) # pixel value contain 1000x the local entropy +plt.figure(figsize=(10, 4)) -# display results -plt.figure(figsize=(10, 10)) - -plt.subplot(2, 2, 1) -plt.imshow(a8, cmap=plt.cm.gray) -plt.xlabel('8-bit image') +plt.subplot(1, 2, 1) +plt.imshow(image, cmap=plt.cm.gray) +plt.title('Image') plt.colorbar() +plt.axis('off') -plt.subplot(2, 2, 2) -plt.imshow(ent8, cmap=plt.cm.jet) -plt.xlabel('entropy*10') -plt.colorbar() - -plt.subplot(2, 2, 3) -plt.imshow(a16, cmap=plt.cm.gray) -plt.xlabel('16-bit image') -plt.colorbar() - -plt.subplot(2, 2, 4) -plt.imshow(ent16, cmap=plt.cm.jet) -plt.xlabel('entropy*1000') +plt.subplot(1, 2, 2) +plt.imshow(entropy(image, disk(5)), cmap=plt.cm.jet) +plt.title('Entropy') plt.colorbar() +plt.axis('off') """ .. image:: PLOT2RST.current_figure Implementation -================ +============== -The central part of the `skimage.rank` filters is build on a sliding window that -update local greylevel histogram. This approach limits the algorithm complexity -to O(n) where n is the number of image pixels. The complexity is also limited -with respect to the structuring element size. +The central part of the `skimage.rank` filters is build on a sliding window +that updates the local gray-level histogram. This approach limits the algorithm +complexity to O(n) where n is the number of image pixels. The complexity is +also limited with respect to the structuring element size. + +In the following we compare the performance of different implementations +available in `skimage`. """ @@ -583,10 +633,10 @@ def ndi_med(image, n): Comparison between -* `rank.maximum` -* `cmorph.dilate` +* `filter.rank.maximum` +* `morphology.dilate` -on increasing structuring element size +on increasing structuring element size: """ @@ -603,18 +653,18 @@ for r in e_range: rec = np.asarray(rec) plt.figure() -plt.title('increasing element size') -plt.ylabel('time (ms)') -plt.xlabel('element radius') +plt.title('Performance with respect to element size') +plt.ylabel('Time (ms)') +plt.title('Element radius') plt.plot(e_range, rec) -plt.legend(['crank.maximum', 'cmorph.dilate']) +plt.legend(['filter.rank.maximum', 'morphology.dilate']) """ -and increasing image size - .. image:: PLOT2RST.current_figure +and increasing image size: + """ r = 9 @@ -623,7 +673,7 @@ elem = disk(r + 1) rec = [] s_range = range(100, 1000, 100) for s in s_range: - a = (np.random.random((s, s)) * 256).astype('uint8') + a = (np.random.random((s, s)) * 256).astype(np.uint8) (rc, ms_rc) = cr_max(a, elem) (rcm, ms_rcm) = cm_dil(a, elem) rec.append((ms_rc, ms_rcm)) @@ -631,11 +681,11 @@ for s in s_range: rec = np.asarray(rec) plt.figure() -plt.title('increasing image size') -plt.ylabel('time (ms)') -plt.xlabel('image size') +plt.title('Performance with respect to image size') +plt.ylabel('Time (ms)') +plt.title('Image size') plt.plot(s_range, rec) -plt.legend(['crank.maximum', 'cmorph.dilate']) +plt.legend(['filter.rank.maximum', 'morphology.dilate']) """ @@ -644,11 +694,11 @@ plt.legend(['crank.maximum', 'cmorph.dilate']) Comparison between: -* `rank.median` -* `ctmf.median_filter` -* `ndimage.percentile` +* `filter.rank.median` +* `filter.median_filter` +* `scipy.ndimage.percentile` -on increasing structuring element size +on increasing structuring element size: """ @@ -666,27 +716,29 @@ for r in e_range: rec = np.asarray(rec) plt.figure() -plt.title('increasing element size') +plt.title('Performance with respect to element size') plt.plot(e_range, rec) -plt.legend(['rank.median', 'ctmf.median_filter', 'ndimage.percentile']) -plt.ylabel('time (ms)') -plt.xlabel('element radius') +plt.legend(['filter.rank.median', 'filter.median_filter', + 'scipy.ndimage.percentile']) +plt.ylabel('Time (ms)') +plt.title('Element radius') """ .. image:: PLOT2RST.current_figure -comparison of outcome of the three methods +Comparison of outcome of the three methods: """ plt.figure() plt.imshow(np.hstack((rc, rctmf, rndi))) -plt.xlabel('rank.median vs ctmf.median_filter vs ndimage.percentile') +plt.title('filter.rank.median vs filtermedian_filter vs scipy.ndimage.percentile') +plt.axis('off') """ .. image:: PLOT2RST.current_figure -and increasing image size +and increasing image size: """ @@ -696,7 +748,7 @@ elem = disk(r + 1) rec = [] s_range = [100, 200, 500, 1000] for s in s_range: - a = (np.random.random((s, s)) * 256).astype('uint8') + a = (np.random.random((s, s)) * 256).astype(np.uint8) (rc, ms_rc) = cr_med(a, elem) rctmf, ms_rctmf = ctmf_med(a, r) rndi, ms_ndi = ndi_med(a, r) @@ -705,11 +757,12 @@ for s in s_range: rec = np.asarray(rec) plt.figure() -plt.title('increasing image size') +plt.title('Performance with respect to image size') plt.plot(s_range, rec) -plt.legend(['rank.median', 'ctmf.median_filter', 'ndimage.percentile']) -plt.ylabel('time (ms)') -plt.xlabel('image size') +plt.legend(['filter.rank.median', 'filter.median_filter', + 'scipy.ndimage.percentile']) +plt.ylabel('Time (ms)') +plt.title('Image size') """ .. image:: PLOT2RST.current_figure diff --git a/doc/examples/plot_entropy.py b/doc/examples/plot_entropy.py index ed5519bd..f5001e31 100644 --- a/doc/examples/plot_entropy.py +++ b/doc/examples/plot_entropy.py @@ -20,7 +20,6 @@ image = img_as_ubyte(data.camera()) fig, (ax0, ax1) = plt.subplots(ncols=2, figsize=(10, 4)) - img0 = ax0.imshow(image, cmap=plt.cm.gray) ax0.set_title('Image') ax0.axis('off') From 43feb4bf7844722b4d317325325a5a4408501f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Tue, 2 Jul 2013 01:17:12 +0200 Subject: [PATCH 25/43] Update bitdepth warning --- skimage/filter/rank/bilateral.py | 2 -- skimage/filter/rank/generic.py | 5 +++++ skimage/filter/rank/percentile.py | 3 --- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/skimage/filter/rank/bilateral.py b/skimage/filter/rank/bilateral.py index 834a24a8..6e11d6e5 100644 --- a/skimage/filter/rank/bilateral.py +++ b/skimage/filter/rank/bilateral.py @@ -22,8 +22,6 @@ References import numpy as np from skimage import img_as_ubyte -from ... import get_log -log = get_log() from . import bilateral_cy from .generic import _handle_input diff --git a/skimage/filter/rank/generic.py b/skimage/filter/rank/generic.py index e09bfba5..167d3aa0 100644 --- a/skimage/filter/rank/generic.py +++ b/skimage/filter/rank/generic.py @@ -55,6 +55,11 @@ def _handle_input(image, selem, out, mask): else: max_bin = max(4, image.max()) + bitdepth = int(np.log2(max_bin)) + if bitdepth > 10: + log.warn("Bitdepth of %d may result in bad rank filter " + "performance due to large number of bins." % bitdepth) + return image, selem, out, mask, max_bin diff --git a/skimage/filter/rank/percentile.py b/skimage/filter/rank/percentile.py index 3b0a04ba..10c4bb9e 100644 --- a/skimage/filter/rank/percentile.py +++ b/skimage/filter/rank/percentile.py @@ -22,9 +22,6 @@ References """ import numpy as np -from skimage import img_as_ubyte -from ... import get_log -log = get_log() from . import percentile_cy from .generic import _handle_input From 54c73fae066f7254f4bfef8b17b490772020b920 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 7 Jul 2013 18:20:00 +0200 Subject: [PATCH 26/43] Replace log warning with UserWarning --- skimage/filter/rank/generic.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/skimage/filter/rank/generic.py b/skimage/filter/rank/generic.py index 167d3aa0..44a4e05b 100644 --- a/skimage/filter/rank/generic.py +++ b/skimage/filter/rank/generic.py @@ -15,10 +15,9 @@ References """ +import warnings import numpy as np from skimage import img_as_ubyte, img_as_uint -from ... import get_log -log = get_log() from . import generic_cy @@ -57,8 +56,8 @@ def _handle_input(image, selem, out, mask): bitdepth = int(np.log2(max_bin)) if bitdepth > 10: - log.warn("Bitdepth of %d may result in bad rank filter " - "performance due to large number of bins." % bitdepth) + warnings.warn("Bitdepth of %d may result in bad rank filter " + "performance due to large number of bins." % bitdepth) return image, selem, out, mask, max_bin From 658201f8f674604432b726303ef2156de6abceea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 7 Jul 2013 18:29:42 +0200 Subject: [PATCH 27/43] Rename mean_subtraction, morph_contr_enh to subtract_mean and enhance_contrast --- skimage/filter/rank/__init__.py | 14 ++++---- skimage/filter/rank/generic.py | 18 +++++----- skimage/filter/rank/generic_cy.pyx | 48 +++++++++++++------------- skimage/filter/rank/percentile.py | 28 +++++++-------- skimage/filter/rank/percentile_cy.pyx | 42 +++++++++++----------- skimage/filter/rank/tests/test_rank.py | 10 +++--- 6 files changed, 80 insertions(+), 80 deletions(-) diff --git a/skimage/filter/rank/__init__.py b/skimage/filter/rank/__init__.py index 9ad816ce..023127e7 100644 --- a/skimage/filter/rank/__init__.py +++ b/skimage/filter/rank/__init__.py @@ -1,9 +1,9 @@ from .generic import (autolevel, bottomhat, equalize, gradient, maximum, mean, - meansubtraction, median, minimum, modal, morph_contr_enh, + subtract_mean, median, minimum, modal, enhance_contrast, pop, threshold, tophat, noise_filter, entropy, otsu) from .percentile import (percentile_autolevel, percentile_gradient, - percentile_mean, percentile_mean_subtraction, - percentile_morph_contr_enh, percentile, + percentile_mean, percentile_subtract_mean, + percentile_enhance_contrast, percentile, percentile_pop, percentile_threshold) from .bilateral import bilateral_mean, bilateral_pop @@ -14,11 +14,11 @@ __all__ = ['autolevel', 'gradient', 'maximum', 'mean', - 'meansubtraction', + 'subtract_mean', 'median', 'minimum', 'modal', - 'morph_contr_enh', + 'enhance_contrast', 'pop', 'threshold', 'tophat', @@ -28,8 +28,8 @@ __all__ = ['autolevel', 'percentile_autolevel', 'percentile_gradient', 'percentile_mean', - 'percentile_mean_subtraction', - 'percentile_morph_contr_enh', + 'percentile_subtract_mean', + 'percentile_enhance_contrast', 'percentile', 'percentile_pop', 'percentile_threshold', diff --git a/skimage/filter/rank/generic.py b/skimage/filter/rank/generic.py index 44a4e05b..f22dcc4c 100644 --- a/skimage/filter/rank/generic.py +++ b/skimage/filter/rank/generic.py @@ -23,7 +23,7 @@ from . import generic_cy __all__ = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'maximum', 'mean', - 'meansubtraction', 'median', 'minimum', 'modal', 'morph_contr_enh', + 'subtract_mean', 'median', 'minimum', 'modal', 'enhance_contrast', 'pop', 'threshold', 'tophat', 'noise_filter', 'entropy', 'otsu'] @@ -294,7 +294,7 @@ def mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False): mask=mask, shift_x=shift_x, shift_y=shift_y) -def meansubtraction(image, selem, out=None, mask=None, shift_x=False, +def subtract_mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """Return image subtracted from its local mean. @@ -317,11 +317,11 @@ def meansubtraction(image, selem, out=None, mask=None, shift_x=False, Returns ------- out : ndarray (same dtype as input image) - The result of the local meansubtraction. + The result of the local mean subtraction. """ - return _apply(generic_cy._meansubtraction, image, selem, + return _apply(generic_cy._subtract_mean, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) @@ -434,7 +434,7 @@ def modal(image, selem, out=None, mask=None, shift_x=False, shift_y=False): out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) -def morph_contr_enh(image, selem, out=None, mask=None, shift_x=False, +def enhance_contrast(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """Enhance an image replacing each pixel by the local maximum if pixel greylevel is closest to maximimum than local minimum OR local minimum @@ -459,21 +459,21 @@ def morph_contr_enh(image, selem, out=None, mask=None, shift_x=False, Returns ------- out : ndarray (same dtype as input image) - The result of the local morph_contr_enh. + The result of the local enhance_contrast. Examples -------- >>> from skimage import data >>> from skimage.morphology import disk - >>> from skimage.filter.rank import morph_contr_enh + >>> from skimage.filter.rank import enhance_contrast >>> # Load test image >>> ima = data.camera() >>> # Local mean - >>> avg = morph_contr_enh(ima, disk(20)) + >>> avg = enhance_contrast(ima, disk(20)) """ - return _apply(generic_cy._morph_contr_enh, image, selem, + return _apply(generic_cy._enhance_contrast, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) diff --git a/skimage/filter/rank/generic_cy.pyx b/skimage/filter/rank/generic_cy.pyx index 0e972c30..ffb52cc8 100644 --- a/skimage/filter/rank/generic_cy.pyx +++ b/skimage/filter/rank/generic_cy.pyx @@ -122,11 +122,11 @@ cdef inline dtype_t _kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, return (0) -cdef inline dtype_t _kernel_meansubtraction(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t max_bin, - Py_ssize_t mid_bin, float p0, - float p1, Py_ssize_t s0, - Py_ssize_t s1): +cdef inline dtype_t _kernel_subtract_mean(Py_ssize_t* histo, float pop, + dtype_t g, Py_ssize_t max_bin, + Py_ssize_t mid_bin, float p0, + float p1, Py_ssize_t s0, + Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t mean = 0 @@ -189,11 +189,11 @@ cdef inline dtype_t _kernel_modal(Py_ssize_t* histo, float pop, dtype_t g, return (0) -cdef inline dtype_t _kernel_morph_contr_enh(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t max_bin, - Py_ssize_t mid_bin, float p0, - float p1, Py_ssize_t s0, - Py_ssize_t s1): +cdef inline dtype_t _kernel_enhance_contrast(Py_ssize_t* histo, float pop, + dtype_t g, Py_ssize_t max_bin, + Py_ssize_t mid_bin, float p0, + float p1, Py_ssize_t s0, + Py_ssize_t s1): cdef Py_ssize_t i, imin, imax @@ -422,17 +422,17 @@ def _mean(dtype_t[:, ::1] image, shift_x, shift_y, 0, 0, 0, 0, max_bin) -def _meansubtraction(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask, - dtype_t[:, ::1] out, - char shift_x, char shift_y, Py_ssize_t max_bin): +def _subtract_mean(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): if dtype_t is uint8_t: - _core[uint8_t](_kernel_meansubtraction[uint8_t], image, selem, mask, + _core[uint8_t](_kernel_subtract_mean[uint8_t], image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0, max_bin) elif dtype_t is uint16_t: - _core[uint16_t](_kernel_meansubtraction[uint16_t], image, selem, mask, + _core[uint16_t](_kernel_subtract_mean[uint16_t], image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0, max_bin) @@ -464,17 +464,17 @@ def _minimum(dtype_t[:, ::1] image, shift_x, shift_y, 0, 0, 0, 0, max_bin) -def _morph_contr_enh(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask, - dtype_t[:, ::1] out, - char shift_x, char shift_y, Py_ssize_t max_bin): +def _enhance_contrast(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t max_bin): if dtype_t is uint8_t: - _core[uint8_t](_kernel_morph_contr_enh[uint8_t], image, selem, mask, + _core[uint8_t](_kernel_enhance_contrast[uint8_t], image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0, max_bin) elif dtype_t is uint16_t: - _core[uint16_t](_kernel_morph_contr_enh[uint16_t], image, selem, mask, + _core[uint16_t](_kernel_enhance_contrast[uint16_t], image, selem, mask, out, shift_x, shift_y, 0, 0, 0, 0, max_bin) diff --git a/skimage/filter/rank/percentile.py b/skimage/filter/rank/percentile.py index 10c4bb9e..73929b0a 100644 --- a/skimage/filter/rank/percentile.py +++ b/skimage/filter/rank/percentile.py @@ -28,8 +28,8 @@ from .generic import _handle_input __all__ = ['percentile_autolevel', 'percentile_gradient', - 'percentile_mean', 'percentile_mean_subtraction', - 'percentile_morph_contr_enh', 'percentile', 'percentile_pop', + 'percentile_mean', 'percentile_subtract_mean', + 'percentile_enhance_contrast', 'percentile', 'percentile_pop', 'percentile_threshold'] @@ -157,11 +157,11 @@ def percentile_mean(image, selem, out=None, mask=None, shift_x=False, shift_y=shift_y, p0=p0, p1=p1) -def percentile_mean_subtraction(image, selem, out=None, mask=None, +def percentile_subtract_mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False, p0=0, p1=1): - """Return greyscale local mean_subtraction of an image. + """Return greyscale local subtract_mean of an image. - mean_subtraction is computed on the given structuring element. Only levels + subtract_mean is computed on the given structuring element. Only levels between percentiles [p0, p1] are used. Parameters @@ -185,21 +185,21 @@ def percentile_mean_subtraction(image, selem, out=None, mask=None, Returns ------- - local mean_subtraction : ndarray (same dtype as input) - The result of the local mean_subtraction. + local subtract_mean : ndarray (same dtype as input) + The result of the local subtract_mean. """ - return _apply(percentile_cy._mean_subtraction, + return _apply(percentile_cy._subtract_mean, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1) -def percentile_morph_contr_enh(image, selem, out=None, mask=None, +def percentile_enhance_contrast(image, selem, out=None, mask=None, shift_x=False, shift_y=False, p0=0, p1=1): - """Return greyscale local morph_contr_enh of an image. + """Return greyscale local enhance_contrast of an image. - morph_contr_enh is computed on the given structuring element. Only levels + enhance_contrast is computed on the given structuring element. Only levels between percentiles [p0, p1] are used. Parameters @@ -223,12 +223,12 @@ def percentile_morph_contr_enh(image, selem, out=None, mask=None, Returns ------- - local morph_contr_enh : ndarray (same dtype as input) - The result of the local morph_contr_enh. + local enhance_contrast : ndarray (same dtype as input) + The result of the local enhance_contrast. """ - return _apply(percentile_cy._morph_contr_enh, + return _apply(percentile_cy._enhance_contrast, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1) diff --git a/skimage/filter/rank/percentile_cy.pyx b/skimage/filter/rank/percentile_cy.pyx index 6df271fa..bb4419de 100644 --- a/skimage/filter/rank/percentile_cy.pyx +++ b/skimage/filter/rank/percentile_cy.pyx @@ -91,11 +91,11 @@ cdef inline dtype_t _kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, return (0) -cdef inline dtype_t _kernel_mean_subtraction(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t max_bin, - Py_ssize_t mid_bin, float p0, - float p1, Py_ssize_t s0, - Py_ssize_t s1): +cdef inline dtype_t _kernel_subtract_mean(Py_ssize_t* histo, float pop, + dtype_t g, Py_ssize_t max_bin, + Py_ssize_t mid_bin, float p0, + float p1, Py_ssize_t s0, + Py_ssize_t s1): cdef Py_ssize_t i, sum, mean, n @@ -116,11 +116,11 @@ cdef inline dtype_t _kernel_mean_subtraction(Py_ssize_t* histo, float pop, return (0) -cdef inline dtype_t _kernel_morph_contr_enh(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t max_bin, - Py_ssize_t mid_bin, float p0, - float p1, Py_ssize_t s0, - Py_ssize_t s1): +cdef inline dtype_t _kernel_enhance_contrast(Py_ssize_t* histo, float pop, + dtype_t g, Py_ssize_t max_bin, + Py_ssize_t mid_bin, float p0, + float p1, Py_ssize_t s0, + Py_ssize_t s1): cdef Py_ssize_t i, imin, imax, sum, delta @@ -252,22 +252,22 @@ def _mean(dtype_t[:, ::1] image, shift_x, shift_y, p0, p1, 0, 0, max_bin) -def _mean_subtraction(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask, - dtype_t[:, ::1] out, - char shift_x, char shift_y, float p0, float p1, - Py_ssize_t max_bin): +def _subtract_mean(dtype_t[:, ::1] image, + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t[:, ::1] out, + char shift_x, char shift_y, float p0, float p1, + Py_ssize_t max_bin): if dtype_t is uint8_t: - _core[uint8_t](_kernel_mean_subtraction[uint8_t], image, selem, mask, + _core[uint8_t](_kernel_subtract_mean[uint8_t], image, selem, mask, out, shift_x, shift_y, p0, p1, 0, 0, max_bin) elif dtype_t is uint16_t: - _core[uint16_t](_kernel_mean_subtraction[uint16_t], image, selem, mask, + _core[uint16_t](_kernel_subtract_mean[uint16_t], image, selem, mask, out, shift_x, shift_y, p0, p1, 0, 0, max_bin) -def _morph_contr_enh(dtype_t[:, ::1] image, +def _enhance_contrast(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, dtype_t[:, ::1] out, @@ -275,10 +275,10 @@ def _morph_contr_enh(dtype_t[:, ::1] image, Py_ssize_t max_bin): if dtype_t is uint8_t: - _core[uint8_t](_kernel_morph_contr_enh[uint8_t], image, selem, mask, + _core[uint8_t](_kernel_enhance_contrast[uint8_t], image, selem, mask, out, shift_x, shift_y, p0, p1, 0, 0, max_bin) elif dtype_t is uint16_t: - _core[uint16_t](_kernel_morph_contr_enh[uint16_t], image, selem, mask, + _core[uint16_t](_kernel_enhance_contrast[uint16_t], image, selem, mask, out, shift_x, shift_y, p0, p1, 0, 0, max_bin) diff --git a/skimage/filter/rank/tests/test_rank.py b/skimage/filter/rank/tests/test_rank.py index f55d3522..166fe67d 100644 --- a/skimage/filter/rank/tests/test_rank.py +++ b/skimage/filter/rank/tests/test_rank.py @@ -183,7 +183,7 @@ def test_compare_ubyte_vs_float(): image_float = img_as_float(image_uint) methods = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'threshold', - 'meansubtraction', 'morph_contr_enh', 'pop', 'tophat'] + 'subtract_mean', 'enhance_contrast', 'pop', 'tophat'] for method in methods: func = getattr(rank, method) @@ -205,8 +205,8 @@ def test_compare_8bit_unsigned_vs_signed(): 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'] + 'mean', 'subtract_mean', 'median', 'minimum', 'modal', + 'enhance_contrast', 'pop', 'threshold', 'tophat'] for method in methods: func = getattr(rank, method) @@ -224,8 +224,8 @@ def test_compare_8bit_vs_16bit(): assert_array_equal(image8, image16) methods = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'maximum', - 'mean', 'meansubtraction', 'median', 'minimum', 'modal', - 'morph_contr_enh', 'pop', 'threshold', 'tophat'] + 'mean', 'subtract_mean', 'median', 'minimum', 'modal', + 'enhance_contrast', 'pop', 'threshold', 'tophat'] for method in methods: func = getattr(rank, method) From ed21622cafd60a744f287f339745d75dd9480595 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 7 Jul 2013 18:32:18 +0200 Subject: [PATCH 28/43] Use consistent description of output image --- skimage/filter/rank/bilateral.py | 8 ++++---- skimage/filter/rank/generic.py | 32 +++++++++++++++---------------- skimage/filter/rank/percentile.py | 32 +++++++++++++++---------------- 3 files changed, 36 insertions(+), 36 deletions(-) diff --git a/skimage/filter/rank/bilateral.py b/skimage/filter/rank/bilateral.py index 6e11d6e5..560bc68c 100644 --- a/skimage/filter/rank/bilateral.py +++ b/skimage/filter/rank/bilateral.py @@ -76,8 +76,8 @@ def bilateral_mean(image, selem, out=None, mask=None, shift_x=False, Returns ------- - out : ndarray (same dtype as input) - The result of the local bilateral mean. + out : ndarray (same dtype as input image) + Output image. See also -------- @@ -126,8 +126,8 @@ def bilateral_pop(image, selem, out=None, mask=None, shift_x=False, Returns ------- - out : ndarray (same dtype as input) - the local number of pixels inside the bilateral neighborhood + out : ndarray (same dtype as input image) + Output image. Examples -------- diff --git a/skimage/filter/rank/generic.py b/skimage/filter/rank/generic.py index f22dcc4c..595a55ee 100644 --- a/skimage/filter/rank/generic.py +++ b/skimage/filter/rank/generic.py @@ -94,7 +94,7 @@ def autolevel(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- out : ndarray (same dtype as input image) - The result of the local autolevel. + Output image. Examples -------- @@ -164,7 +164,7 @@ def equalize(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- out : ndarray (same dtype as input image) - The result of the local equalize. + Output image. Examples -------- @@ -206,7 +206,7 @@ def gradient(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- out : ndarray (same dtype as input image) - The local gradient. + Output image. """ @@ -237,7 +237,7 @@ def maximum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- out : ndarray (same dtype as input image) - The local maximum. + Output image. See also -------- @@ -276,7 +276,7 @@ def mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- out : ndarray (same dtype as input image) - The local mean. + Output image. Examples -------- @@ -317,7 +317,7 @@ def subtract_mean(image, selem, out=None, mask=None, shift_x=False, Returns ------- out : ndarray (same dtype as input image) - The result of the local mean subtraction. + Output image. """ @@ -347,7 +347,7 @@ def median(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- out : ndarray (same dtype as input image) - The local median. + Output image. Examples -------- @@ -387,7 +387,7 @@ def minimum(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- out : ndarray (same dtype as input image) - The local minimum. + Output image. See also -------- @@ -426,7 +426,7 @@ def modal(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- out : ndarray (same dtype as input image) - The local modal. + Output image. """ @@ -457,7 +457,7 @@ def enhance_contrast(image, selem, out=None, mask=None, shift_x=False, structuring element). Returns - ------- + Output image. out : ndarray (same dtype as input image) The result of the local enhance_contrast. @@ -500,7 +500,7 @@ def pop(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- out : ndarray (same dtype as input image) - The number of pixels belonging to the neighborhood. + Output image. Examples -------- @@ -547,7 +547,7 @@ def threshold(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- out : ndarray (same dtype as input image) - The result of the local threshold. + Output image. Examples -------- @@ -594,7 +594,7 @@ def tophat(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- out : ndarray (same dtype as input image) - The image tophat. + Output image. """ @@ -630,7 +630,7 @@ def noise_filter(image, selem, out=None, mask=None, shift_x=False, Returns ------- out : ndarray (same dtype as input image) - The image noise. + Output image. """ @@ -669,7 +669,7 @@ def entropy(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- out : ndarray (same dtype as input image) - Entropy of image. + Output image. References ---------- @@ -712,7 +712,7 @@ def otsu(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- out : ndarray (same dtype as input image) - Otsu's threshold values. + Output image. References ---------- diff --git a/skimage/filter/rank/percentile.py b/skimage/filter/rank/percentile.py index 73929b0a..b01d314d 100644 --- a/skimage/filter/rank/percentile.py +++ b/skimage/filter/rank/percentile.py @@ -71,8 +71,8 @@ def percentile_autolevel(image, selem, out=None, mask=None, shift_x=False, Returns ------- - local autolevel : ndarray (same dtype as input) - The result of the local autolevel. + out : ndarray (same dtype as input image) + Output image. """ @@ -109,8 +109,8 @@ def percentile_gradient(image, selem, out=None, mask=None, shift_x=False, Returns ------- - local percentile_gradient : ndarray (same dtype as input) - The result of the local percentile_gradient. + out : ndarray (same dtype as input image) + Output image. """ @@ -147,8 +147,8 @@ def percentile_mean(image, selem, out=None, mask=None, shift_x=False, Returns ------- - local mean : ndarray (same dtype as input) - The result of the local mean. + out : ndarray (same dtype as input image) + Output image. """ @@ -185,8 +185,8 @@ def percentile_subtract_mean(image, selem, out=None, mask=None, Returns ------- - local subtract_mean : ndarray (same dtype as input) - The result of the local subtract_mean. + out : ndarray (same dtype as input image) + Output image. """ @@ -223,8 +223,8 @@ def percentile_enhance_contrast(image, selem, out=None, mask=None, Returns ------- - local enhance_contrast : ndarray (same dtype as input) - The result of the local enhance_contrast. + out : ndarray (same dtype as input image) + Output image. """ @@ -260,8 +260,8 @@ def percentile(image, selem, out=None, mask=None, shift_x=False, shift_y=False, Returns ------- - local percentile : ndarray (same dtype as input) - The result of the local percentile. + out : ndarray (same dtype as input image) + Output image. """ @@ -298,8 +298,8 @@ def percentile_pop(image, selem, out=None, mask=None, shift_x=False, Returns ------- - local pop : ndarray (same dtype as input) - The result of the local pop. + out : ndarray (same dtype as input image) + Output image. """ @@ -335,8 +335,8 @@ def percentile_threshold(image, selem, out=None, mask=None, shift_x=False, p0 : float in [0, ..., 1] Set the percentile value. - Returns - ------- + out : ndarray (same dtype as input image) + Output image. local threshold : ndarray (same dtype as input) The result of the local threshold. From 6ee96054c9633a662432e52572788d4840c92013 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Sun, 7 Jul 2013 18:42:35 +0200 Subject: [PATCH 29/43] Append percentile, bilateral function name part --- skimage/filter/rank/__init__.py | 32 +++++++++++++------------- skimage/filter/rank/bilateral.py | 6 ++--- skimage/filter/rank/percentile.py | 32 +++++++++++++------------- skimage/filter/rank/tests/test_rank.py | 20 ++++++++-------- 4 files changed, 45 insertions(+), 45 deletions(-) diff --git a/skimage/filter/rank/__init__.py b/skimage/filter/rank/__init__.py index 023127e7..b25abb8c 100644 --- a/skimage/filter/rank/__init__.py +++ b/skimage/filter/rank/__init__.py @@ -1,37 +1,37 @@ from .generic import (autolevel, bottomhat, equalize, gradient, maximum, mean, subtract_mean, median, minimum, modal, enhance_contrast, pop, threshold, tophat, noise_filter, entropy, otsu) -from .percentile import (percentile_autolevel, percentile_gradient, - percentile_mean, percentile_subtract_mean, - percentile_enhance_contrast, percentile, - percentile_pop, percentile_threshold) -from .bilateral import bilateral_mean, bilateral_pop +from .percentile import (autolevel_percentile, gradient_percentile, + mean_percentile, subtract_mean_percentile, + enhance_contrast_percentile, percentile, + pop_percentile, threshold_percentile) +from .bilateral import mean_bilateral, pop_bilateral __all__ = ['autolevel', + 'autolevel_percentile', 'bottomhat', 'equalize', 'gradient', + 'gradient_percentile', 'maximum', 'mean', + 'mean_percentile', + 'mean_bilateral', 'subtract_mean', + 'subtract_mean_percentile', 'median', 'minimum', 'modal', 'enhance_contrast', + 'enhance_contrast_percentile', 'pop', + 'pop_percentile', + 'pop_bilateral', 'threshold', + 'threshold_percentile', 'tophat', 'noise_filter', 'entropy', - 'otsu', - 'percentile_autolevel', - 'percentile_gradient', - 'percentile_mean', - 'percentile_subtract_mean', - 'percentile_enhance_contrast', - 'percentile', - 'percentile_pop', - 'percentile_threshold', - 'bilateral_mean', - 'bilateral_pop'] + 'otsu' + 'percentile'] diff --git a/skimage/filter/rank/bilateral.py b/skimage/filter/rank/bilateral.py index 560bc68c..f0bc2b38 100644 --- a/skimage/filter/rank/bilateral.py +++ b/skimage/filter/rank/bilateral.py @@ -27,7 +27,7 @@ from . import bilateral_cy from .generic import _handle_input -__all__ = ['bilateral_mean', 'bilateral_pop'] +__all__ = ['mean_bilateral', 'pop_bilateral'] def _apply(func, image, selem, out, mask, shift_x, shift_y, s0, s1): @@ -40,7 +40,7 @@ def _apply(func, image, selem, out, mask, shift_x, shift_y, s0, s1): return out -def bilateral_mean(image, selem, out=None, mask=None, shift_x=False, +def mean_bilateral(image, selem, out=None, mask=None, shift_x=False, shift_y=False, s0=10, s1=10): """Apply a flat kernel bilateral filter. @@ -99,7 +99,7 @@ def bilateral_mean(image, selem, out=None, mask=None, shift_x=False, mask=mask, shift_x=shift_x, shift_y=shift_y, s0=s0, s1=s1) -def bilateral_pop(image, selem, out=None, mask=None, shift_x=False, +def pop_bilateral(image, selem, out=None, mask=None, shift_x=False, shift_y=False, s0=10, s1=10): """Return the number (population) of pixels actually inside the bilateral neighborhood, i.e. being inside the structuring element AND having a gray diff --git a/skimage/filter/rank/percentile.py b/skimage/filter/rank/percentile.py index b01d314d..e91e0d82 100644 --- a/skimage/filter/rank/percentile.py +++ b/skimage/filter/rank/percentile.py @@ -1,6 +1,6 @@ """Inferior and superior ranks, provided by the user, are passed to the kernel function to provide a softer version of the rank filters. E.g. -percentile_autolevel will stretch image levels between percentile [p0, p1] +``autolevel_percentile`` will stretch image levels between percentile [p0, p1] instead of using [min, max]. It means that isolated bright or dark pixels will not produce halos. @@ -27,10 +27,10 @@ from . import percentile_cy from .generic import _handle_input -__all__ = ['percentile_autolevel', 'percentile_gradient', - 'percentile_mean', 'percentile_subtract_mean', - 'percentile_enhance_contrast', 'percentile', 'percentile_pop', - 'percentile_threshold'] +__all__ = ['autolevel_percentile', 'gradient_percentile', + 'mean_percentile', 'subtract_mean_percentile', + 'enhance_contrast_percentile', 'percentile', 'pop_percentile', + 'threshold_percentile'] def _apply(func, image, selem, out, mask, shift_x, shift_y, p0, p1): @@ -43,7 +43,7 @@ def _apply(func, image, selem, out, mask, shift_x, shift_y, p0, p1): return out -def percentile_autolevel(image, selem, out=None, mask=None, shift_x=False, +def autolevel_percentile(image, selem, out=None, mask=None, shift_x=False, shift_y=False, p0=0, p1=1): """Return greyscale local autolevel of an image. @@ -81,11 +81,11 @@ def percentile_autolevel(image, selem, out=None, mask=None, shift_x=False, shift_y=shift_y, p0=p0, p1=p1) -def percentile_gradient(image, selem, out=None, mask=None, shift_x=False, +def gradient_percentile(image, selem, out=None, mask=None, shift_x=False, shift_y=False, p0=0, p1=1): - """Return greyscale local percentile_gradient of an image. + """Return greyscale local gradient of an image. - percentile_gradient is computed on the given structuring element. Only + gradient is computed on the given structuring element. Only levels between percentiles [p0, p1] are used. Parameters @@ -119,7 +119,7 @@ def percentile_gradient(image, selem, out=None, mask=None, shift_x=False, shift_y=shift_y, p0=p0, p1=p1) -def percentile_mean(image, selem, out=None, mask=None, shift_x=False, +def mean_percentile(image, selem, out=None, mask=None, shift_x=False, shift_y=False, p0=0, p1=1): """Return greyscale local mean of an image. @@ -157,8 +157,8 @@ def percentile_mean(image, selem, out=None, mask=None, shift_x=False, shift_y=shift_y, p0=p0, p1=p1) -def percentile_subtract_mean(image, selem, out=None, mask=None, - shift_x=False, shift_y=False, p0=0, p1=1): +def subtract_mean_percentile(image, selem, out=None, mask=None, + shift_x=False, shift_y=False, p0=0, p1=1): """Return greyscale local subtract_mean of an image. subtract_mean is computed on the given structuring element. Only levels @@ -195,8 +195,8 @@ def percentile_subtract_mean(image, selem, out=None, mask=None, shift_y=shift_y, p0=p0, p1=p1) -def percentile_enhance_contrast(image, selem, out=None, mask=None, - shift_x=False, shift_y=False, p0=0, p1=1): +def enhance_contrast_percentile(image, selem, out=None, mask=None, + shift_x=False, shift_y=False, p0=0, p1=1): """Return greyscale local enhance_contrast of an image. enhance_contrast is computed on the given structuring element. Only levels @@ -270,7 +270,7 @@ def percentile(image, selem, out=None, mask=None, shift_x=False, shift_y=False, shift_y=shift_y, p0=p0, p1=0.) -def percentile_pop(image, selem, out=None, mask=None, shift_x=False, +def pop_percentile(image, selem, out=None, mask=None, shift_x=False, shift_y=False, p0=0, p1=1): """Return greyscale local pop of an image. @@ -308,7 +308,7 @@ def percentile_pop(image, selem, out=None, mask=None, shift_x=False, shift_y=shift_y, p0=p0, p1=p1) -def percentile_threshold(image, selem, out=None, mask=None, shift_x=False, +def threshold_percentile(image, selem, out=None, mask=None, shift_x=False, shift_y=False, p0=0): """Return greyscale local threshold of an image. diff --git a/skimage/filter/rank/tests/test_rank.py b/skimage/filter/rank/tests/test_rank.py index 166fe67d..d2906f98 100644 --- a/skimage/filter/rank/tests/test_rank.py +++ b/skimage/filter/rank/tests/test_rank.py @@ -33,10 +33,10 @@ def test_random_sizes(): shift_x=+1, shift_y=+1) assert_array_equal(image16.shape, out16.shape) - rank.percentile_mean(image=image16, mask=mask, out=out16, + rank.mean_percentile(image=image16, mask=mask, out=out16, selem=elem, shift_x=0, shift_y=0, p0=.1, p1=.9) assert_array_equal(image16.shape, out16.shape) - rank.percentile_mean(image=image16, mask=mask, out=out16, + rank.mean_percentile(image=image16, mask=mask, out=out16, selem=elem, shift_x=+1, shift_y=+1, p0=.1, p1=.9) assert_array_equal(image16.shape, out16.shape) @@ -78,7 +78,7 @@ def test_bitdepth(): for i in range(5): image = np.ones((100, 100), dtype=np.uint16) * 255 * 2 ** i - r = rank.percentile_mean(image=image, selem=elem, mask=mask, + r = rank.mean_percentile(image=image, selem=elem, mask=mask, out=out, shift_x=0, shift_y=0, p0=.1, p1=.9) @@ -156,7 +156,7 @@ def test_compare_autolevels(): selem = disk(20) loc_autolevel = rank.autolevel(image, selem=selem) - loc_perc_autolevel = rank.percentile_autolevel(image, selem=selem, + loc_perc_autolevel = rank.autolevel_percentile(image, selem=selem, p0=.0, p1=1.) assert_array_equal(loc_autolevel, loc_perc_autolevel) @@ -170,7 +170,7 @@ def test_compare_autolevels_16bit(): selem = disk(20) loc_autolevel = rank.autolevel(image, selem=selem) - loc_perc_autolevel = rank.percentile_autolevel(image, selem=selem, + loc_perc_autolevel = rank.autolevel_percentile(image, selem=selem, p0=.0, p1=1.) assert_array_equal(loc_autolevel, loc_perc_autolevel) @@ -418,7 +418,7 @@ def test_selem_dtypes(): rank.mean(image=image, selem=elem, out=out, mask=mask, shift_x=0, shift_y=0) assert_array_equal(image, out) - rank.percentile_mean(image=image, selem=elem, out=out, mask=mask, + rank.mean_percentile(image=image, selem=elem, out=out, mask=mask, shift_x=0, shift_y=0) assert_array_equal(image, out) @@ -443,10 +443,10 @@ def test_bilateral(): image[10, 11] = 1010 image[10, 9] = 900 - assert rank.bilateral_mean(image, selem, s0=1, s1=1)[10, 10] == 1000 - assert rank.bilateral_pop(image, selem, s0=1, s1=1)[10, 10] == 1 - assert rank.bilateral_mean(image, selem, s0=11, s1=11)[10, 10] == 1005 - assert rank.bilateral_pop(image, selem, s0=11, s1=11)[10, 10] == 2 + assert rank.mean_bilateral(image, selem, s0=1, s1=1)[10, 10] == 1000 + assert rank.pop_bilateral(image, selem, s0=1, s1=1)[10, 10] == 1 + assert rank.mean_bilateral(image, selem, s0=11, s1=11)[10, 10] == 1005 + assert rank.pop_bilateral(image, selem, s0=11, s1=11)[10, 10] == 2 if __name__ == "__main__": From c2939d53080959d1544d9c8b1e224e0c20036877 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Mon, 8 Jul 2013 20:11:36 +0200 Subject: [PATCH 30/43] Add TODO.txt --- TODO.txt | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 TODO.txt diff --git a/TODO.txt b/TODO.txt new file mode 100644 index 00000000..2067d036 --- /dev/null +++ b/TODO.txt @@ -0,0 +1,14 @@ +Version 0.10 +------------ +* Remove deprecated functions: + - ``skimage.filter.rank.*`` +* Remove deprecated parameter ``epsilon`` of ``skimage.viewer.LineProfile`` + +Version 0.9 +----------- +* Remove deprecated functions + - ``skimage.filter.denoise_tv_chambolle`` + - ``skimage.morphology.is_local_maximum`` + - ``skimage.transform.hough`` + - ``skimage.transform.probabilistic_hough`` + - ``skimage.transform.hough_peaks`` From af752b97d3a91c0d3152a7539bf8aa2eda73e443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Mon, 8 Jul 2013 20:13:20 +0200 Subject: [PATCH 31/43] Add note about TODO.txt to release instructions --- RELEASE.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASE.txt b/RELEASE.txt index 80bf4cab..d29143aa 100644 --- a/RELEASE.txt +++ b/RELEASE.txt @@ -1,6 +1,8 @@ How to make a new release of ``skimage`` ======================================== +- Check ``TODO.txt`` for any outstanding tasks. + - Update release notes. - To show a list contributors, run ``doc/release/contributors.sh ``, From e041c27f884895dfd230b9a55aa93f9df68ccf07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Mon, 8 Jul 2013 20:25:25 +0200 Subject: [PATCH 32/43] Deprecate old rank filter functions --- skimage/filter/rank/__init__.py | 35 ++++++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/skimage/filter/rank/__init__.py b/skimage/filter/rank/__init__.py index b25abb8c..cfd034f1 100644 --- a/skimage/filter/rank/__init__.py +++ b/skimage/filter/rank/__init__.py @@ -7,6 +7,29 @@ from .percentile import (autolevel_percentile, gradient_percentile, pop_percentile, threshold_percentile) from .bilateral import mean_bilateral, pop_bilateral +from skimage._shared.utils import deprecated + + +percentile_autolevel = deprecated('autolevel_percentile')(autolevel_percentile) + +percentile_gradient = deprecated('gradient_percentile')(gradient_percentile) + +percentile_mean = deprecated('mean_percentile')(mean_percentile) +bilateral_mean = deprecated('mean_bilateral')(mean_bilateral) + +meansubtraction = deprecated('subtract_mean')(subtract_mean) +percentile_mean_subtraction = deprecated('subtract_mean_percentile')\ + (subtract_mean_percentile) + +morph_contr_enh = deprecated('enhance_contrast')(enhance_contrast) +percentile_morph_contr_enh = deprecated('enhance_contrast_percentile')\ + (enhance_contrast_percentile) + +percentile_pop = deprecated('pop_percentile')(pop_percentile) +bilateral_pop = deprecated('pop_bilateral')(pop_bilateral) + +percentile_threshold = deprecated('threshold_percentile')(threshold_percentile) + __all__ = ['autolevel', 'autolevel_percentile', @@ -34,4 +57,14 @@ __all__ = ['autolevel', 'noise_filter', 'entropy', 'otsu' - 'percentile'] + 'percentile', + # Deprecated + 'percentile_autolevel', + 'percentile_gradient', + 'percentile_mean', + 'percentile_mean_subtraction', + 'percentile_morph_contr_enh', + 'percentile_pop', + 'percentile_threshold', + 'bilateral_mean', + 'bilateral_pop'] From b9b5efbdf8d769e83fefc0553f0b226aced2644f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Mon, 8 Jul 2013 20:34:40 +0200 Subject: [PATCH 33/43] Replace deprecated function calls in examples --- doc/examples/applications/plot_rank_filters.py | 18 +++++++++--------- doc/examples/plot_rank_mean.py | 4 ++-- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/examples/applications/plot_rank_filters.py b/doc/examples/applications/plot_rank_filters.py index ded335bd..fb69cd40 100644 --- a/doc/examples/applications/plot_rank_filters.py +++ b/doc/examples/applications/plot_rank_filters.py @@ -283,16 +283,16 @@ result. """ -from skimage.filter.rank import percentile_autolevel +from skimage.filter.rank import autolevel_percentile image = data.camera() selem = disk(20) loc_autolevel = autolevel(image, selem=selem) -loc_perc_autolevel0 = percentile_autolevel(image, selem=selem, p0=.00, p1=1.0) -loc_perc_autolevel1 = percentile_autolevel(image, selem=selem, p0=.01, p1=.99) -loc_perc_autolevel2 = percentile_autolevel(image, selem=selem, p0=.05, p1=.95) -loc_perc_autolevel3 = percentile_autolevel(image, selem=selem, p0=.1, p1=.9) +loc_perc_autolevel0 = autolevel_percentile(image, selem=selem, p0=.00, p1=1.0) +loc_perc_autolevel1 = autolevel_percentile(image, selem=selem, p0=.01, p1=.99) +loc_perc_autolevel2 = autolevel_percentile(image, selem=selem, p0=.05, p1=.95) +loc_perc_autolevel3 = autolevel_percentile(image, selem=selem, p0=.1, p1=.9) fig, axes = plt.subplots(nrows=3, figsize=(7, 8)) ax0, ax1, ax2 = axes @@ -321,11 +321,11 @@ otherwise by the minimum local. """ -from skimage.filter.rank import morph_contr_enh +from skimage.filter.rank import enhance_contrast noisy_image = data.camera() -enh = morph_contr_enh(noisy_image, disk(5)) +enh = enhance_contrast(noisy_image, disk(5)) fig = plt.figure(figsize=[10, 7]) plt.subplot(2, 2, 1) @@ -355,11 +355,11 @@ percentile *p0* and *p1* instead of the local minimum and maximum. """ -from skimage.filter.rank import percentile_morph_contr_enh +from skimage.filter.rank import enhance_contrast_percentile noisy_image = data.camera() -penh = percentile_morph_contr_enh(noisy_image, disk(5), p0=.1, p1=.9) +penh = enhance_contrast_percentile(noisy_image, disk(5), p0=.1, p1=.9) fig = plt.figure(figsize=[10, 7]) plt.subplot(2, 2, 1) diff --git a/doc/examples/plot_rank_mean.py b/doc/examples/plot_rank_mean.py index 013535cb..6f16c440 100644 --- a/doc/examples/plot_rank_mean.py +++ b/doc/examples/plot_rank_mean.py @@ -29,8 +29,8 @@ from skimage.filter import rank image = (data.coins()).astype(np.uint16) * 16 selem = disk(20) -percentile_result = rank.percentile_mean(image, selem=selem, p0=.1, p1=.9) -bilateral_result = rank.bilateral_mean(image, selem=selem, s0=500, s1=500) +percentile_result = rank.mean_percentile(image, selem=selem, p0=.1, p1=.9) +bilateral_result = rank.mean_bilateral(image, selem=selem, s0=500, s1=500) normal_result = rank.mean(image, selem=selem) From 33a09c3b1a1727e8f63cc2fce926a460bd50c5c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 12 Jul 2013 22:58:15 +0200 Subject: [PATCH 34/43] Add option to return double output image for rank filters --- skimage/filter/rank/bilateral.py | 9 +- skimage/filter/rank/bilateral_cy.pyx | 58 ++-- skimage/filter/rank/core_cy.pxd | 15 +- skimage/filter/rank/core_cy.pyx | 28 +- skimage/filter/rank/generic.py | 21 +- skimage/filter/rank/generic_cy.pyx | 427 +++++++++++--------------- skimage/filter/rank/percentile.py | 9 +- skimage/filter/rank/percentile_cy.pyx | 250 +++++++-------- 8 files changed, 362 insertions(+), 455 deletions(-) diff --git a/skimage/filter/rank/bilateral.py b/skimage/filter/rank/bilateral.py index f0bc2b38..f1b10fec 100644 --- a/skimage/filter/rank/bilateral.py +++ b/skimage/filter/rank/bilateral.py @@ -11,6 +11,9 @@ The pixel neighborhood is defined by: The kernel is flat (i.e. each pixel belonging to the neighborhood contributes equally). +Result image is 8-/16-bit or double with respect to the input image and the +rank filter operation. + References ---------- @@ -30,9 +33,11 @@ from .generic import _handle_input __all__ = ['mean_bilateral', 'pop_bilateral'] -def _apply(func, image, selem, out, mask, shift_x, shift_y, s0, s1): +def _apply(func, image, selem, out, mask, shift_x, shift_y, s0, s1, + out_dtype=None): - image, selem, out, mask, max_bin = _handle_input(image, selem, out, mask) + image, selem, out, mask, max_bin = _handle_input(image, selem, out, mask, + out_dtype) func(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, out=out, max_bin=max_bin, s0=s0, s1=s1) diff --git a/skimage/filter/rank/bilateral_cy.pyx b/skimage/filter/rank/bilateral_cy.pyx index d93fdb3c..b8e0d1e7 100644 --- a/skimage/filter/rank/bilateral_cy.pyx +++ b/skimage/filter/rank/bilateral_cy.pyx @@ -6,14 +6,13 @@ cimport numpy as cnp from libc.math cimport log -from .core_cy cimport uint8_t, uint16_t, dtype_t, _core +from .core_cy cimport dtype_t, dtype_t_out, _core -cdef inline dtype_t _kernel_mean(Py_ssize_t* histo, float pop, - dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t bilat_pop = 0 @@ -25,18 +24,17 @@ cdef inline dtype_t _kernel_mean(Py_ssize_t* histo, float pop, bilat_pop += histo[i] mean += histo[i] * i if bilat_pop: - return (mean / bilat_pop) + return mean / bilat_pop else: - return (0) + return 0 else: - return (0) + return 0 -cdef inline dtype_t _kernel_pop(Py_ssize_t* histo, float pop, - dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t bilat_pop = 0 @@ -45,36 +43,28 @@ cdef inline dtype_t _kernel_pop(Py_ssize_t* histo, float pop, for i in range(max_bin): if (g > (i - s0)) and (g < (i + s1)): bilat_pop += histo[i] - return (bilat_pop) + return bilat_pop else: - return (0) + return 0 def _mean(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t s0, Py_ssize_t s1, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_mean[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, s0, s1, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_mean[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, s0, s1, max_bin) + _core(_kernel_mean[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, s0, s1, max_bin) def _pop(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask, - dtype_t[:, ::1] out, - char shift_x, char shift_y, Py_ssize_t s0, Py_ssize_t s1, - Py_ssize_t max_bin): + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t_out[:, ::1] out, + char shift_x, char shift_y, Py_ssize_t s0, Py_ssize_t s1, + Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_pop[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, s0, s1, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_pop[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, s0, s1, max_bin) + _core(_kernel_pop[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, s0, s1, max_bin) diff --git a/skimage/filter/rank/core_cy.pxd b/skimage/filter/rank/core_cy.pxd index 544368a0..a1e44f98 100644 --- a/skimage/filter/rank/core_cy.pxd +++ b/skimage/filter/rank/core_cy.pxd @@ -1,22 +1,27 @@ -from numpy cimport uint8_t, uint16_t +from numpy cimport uint8_t, uint16_t, double_t ctypedef fused dtype_t: uint8_t uint16_t +ctypedef fused dtype_t_out: + uint8_t + uint16_t + double_t + cdef dtype_t _max(dtype_t a, dtype_t b) cdef dtype_t _min(dtype_t a, dtype_t b) -cdef void _core(dtype_t kernel(Py_ssize_t*, float, dtype_t, - Py_ssize_t, Py_ssize_t, float, - float, Py_ssize_t, Py_ssize_t), +cdef void _core(float kernel(Py_ssize_t*, float, dtype_t, + Py_ssize_t, Py_ssize_t, float, + float, Py_ssize_t, Py_ssize_t), dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1, diff --git a/skimage/filter/rank/core_cy.pyx b/skimage/filter/rank/core_cy.pyx index 898e1775..854a3ce7 100644 --- a/skimage/filter/rank/core_cy.pyx +++ b/skimage/filter/rank/core_cy.pyx @@ -42,13 +42,13 @@ cdef inline char is_in_mask(Py_ssize_t rows, Py_ssize_t cols, return 0 -cdef void _core(dtype_t kernel(Py_ssize_t*, float, dtype_t, - Py_ssize_t, Py_ssize_t, float, - float, Py_ssize_t, Py_ssize_t), +cdef void _core(float kernel(Py_ssize_t*, float, dtype_t, + Py_ssize_t, Py_ssize_t, float, + float, Py_ssize_t, Py_ssize_t), dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1, @@ -151,8 +151,8 @@ cdef void _core(dtype_t kernel(Py_ssize_t*, float, dtype_t, r = 0 c = 0 - out[r, c] = kernel(histo, pop, image[r, c], max_bin, mid_bin, - p0, p1, s0, s1) + out[r, c] = kernel(histo, pop, image[r, c], max_bin, mid_bin, + p0, p1, s0, s1) # main loop r = 0 @@ -172,8 +172,8 @@ cdef void _core(dtype_t kernel(Py_ssize_t*, float, dtype_t, if is_in_mask(rows, cols, rr, cc, mask_data): histogram_decrement(histo, &pop, image[rr, cc]) - out[r, c] = kernel(histo, pop, image[r, c], max_bin, - mid_bin, p0, p1, s0, s1) + out[r, c] = kernel(histo, pop, image[r, c], + max_bin, mid_bin, p0, p1, s0, s1) r += 1 # pass to the next row if r >= rows: @@ -192,8 +192,8 @@ cdef void _core(dtype_t kernel(Py_ssize_t*, float, dtype_t, if is_in_mask(rows, cols, rr, cc, mask_data): histogram_decrement(histo, &pop, image[rr, cc]) - out[r, c] = kernel(histo, pop, image[r, c], - max_bin, mid_bin, p0, p1, s0, s1) + out[r, c] = kernel(histo, pop, image[r, c], + max_bin, mid_bin, p0, p1, s0, s1) # ---> east to west for c in range(cols - 2, -1, -1): @@ -209,8 +209,8 @@ cdef void _core(dtype_t kernel(Py_ssize_t*, float, dtype_t, if is_in_mask(rows, cols, rr, cc, mask_data): histogram_decrement(histo, &pop, image[rr, cc]) - out[r, c] = kernel(histo, pop, image[r, c], max_bin, - mid_bin, p0, p1, s0, s1) + out[r, c] = kernel(histo, pop, image[r, c], + max_bin, mid_bin, p0, p1, s0, s1) r += 1 # pass to the next row if r >= rows: @@ -229,8 +229,8 @@ cdef void _core(dtype_t kernel(Py_ssize_t*, float, dtype_t, if is_in_mask(rows, cols, rr, cc, mask_data): histogram_decrement(histo, &pop, image[rr, cc]) - out[r, c] = kernel(histo, pop, image[r, c], max_bin, mid_bin, - p0, p1, s0, s1) + out[r, c] = kernel(histo, pop, image[r, c], + max_bin, mid_bin, p0, p1, s0, s1) # release memory allocated by malloc free(se_e_r) diff --git a/skimage/filter/rank/generic.py b/skimage/filter/rank/generic.py index 595a55ee..0bc8ca50 100644 --- a/skimage/filter/rank/generic.py +++ b/skimage/filter/rank/generic.py @@ -4,7 +4,8 @@ described in [1]_. Input image can be 8-bit or 16-bit, for 16-bit input images, the number of histogram bins is determined from the maximum value present in the image. -Result image is 8- or 16-bit with respect to the input image. +Result image is 8-/16-bit or double with respect to the input image and the +rank filter operation. References ---------- @@ -17,7 +18,7 @@ References import warnings import numpy as np -from skimage import img_as_ubyte, img_as_uint +from skimage import img_as_ubyte from . import generic_cy @@ -27,7 +28,7 @@ __all__ = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'maximum', 'mean', 'pop', 'threshold', 'tophat', 'noise_filter', 'entropy', 'otsu'] -def _handle_input(image, selem, out, mask): +def _handle_input(image, selem, out, mask, out_dtype=None): if image.dtype not in (np.uint8, np.uint16): image = img_as_ubyte(image) @@ -42,7 +43,9 @@ def _handle_input(image, selem, out, mask): mask = np.ascontiguousarray(mask) if out is None: - out = np.empty_like(image, dtype=image.dtype) + if out_dtype is None: + out_dtype = image.dtype + out = np.empty_like(image, dtype=out_dtype) if image is out: raise NotImplementedError("Cannot perform rank operation in place.") @@ -62,9 +65,10 @@ def _handle_input(image, selem, out, mask): return image, selem, out, mask, max_bin -def _apply(func, image, selem, out, mask, shift_x, shift_y): +def _apply(func, image, selem, out, mask, shift_x, shift_y, out_dtype=None): - image, selem, out, mask, max_bin = _handle_input(image, selem, out, mask) + image, selem, out, mask, max_bin = _handle_input(image, selem, out, mask, + out_dtype) func(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, out=out, max_bin=max_bin) @@ -668,7 +672,7 @@ def entropy(image, selem, out=None, mask=None, shift_x=False, shift_y=False): Returns ------- - out : ndarray (same dtype as input image) + out : ndarray (double) Output image. References @@ -687,7 +691,8 @@ def entropy(image, selem, out=None, mask=None, shift_x=False, shift_y=False): """ return _apply(generic_cy._entropy, image, selem, - out=out, mask=mask, shift_x=shift_x, shift_y=shift_y) + out=out, mask=mask, shift_x=shift_x, shift_y=shift_y, + out_dtype=np.double) def otsu(image, selem, out=None, mask=None, shift_x=False, shift_y=False): diff --git a/skimage/filter/rank/generic_cy.pyx b/skimage/filter/rank/generic_cy.pyx index ffb52cc8..47cb99da 100644 --- a/skimage/filter/rank/generic_cy.pyx +++ b/skimage/filter/rank/generic_cy.pyx @@ -6,13 +6,13 @@ cimport numpy as cnp from libc.math cimport log -from .core_cy cimport uint8_t, uint16_t, dtype_t, _core +from .core_cy cimport dtype_t, dtype_t_out, _core -cdef inline dtype_t _kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i, imin, imax, delta @@ -27,17 +27,17 @@ cdef inline dtype_t _kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, break delta = imax - imin if delta > 0: - return ((max_bin - 1) * (g - imin) / delta) + return (max_bin - 1) * (g - imin) / delta else: - return (imax - imin) + return imax - imin else: - return (0) + return 0 -cdef inline dtype_t _kernel_bottomhat(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_bottomhat(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i @@ -45,16 +45,15 @@ cdef inline dtype_t _kernel_bottomhat(Py_ssize_t* histo, float pop, dtype_t g, for i in range(max_bin): if histo[i]: break - - return (g - i) + return g - i else: - return (0) + return 0 -cdef inline dtype_t _kernel_equalize(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_equalize(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t sum = 0 @@ -64,16 +63,15 @@ cdef inline dtype_t _kernel_equalize(Py_ssize_t* histo, float pop, dtype_t g, sum += histo[i] if i >= g: break - - return (((max_bin - 1) * sum) / pop) + return ((max_bin - 1) * sum) / pop else: - return (0) + return 0 -cdef inline dtype_t _kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i, imin, imax @@ -86,64 +84,65 @@ cdef inline dtype_t _kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, if histo[i]: imin = i break - return (imax - imin) + return imax - imin else: - return (0) + return 0 -cdef inline dtype_t _kernel_maximum(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_maximum(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i if pop: for i in range(max_bin - 1, -1, -1): if histo[i]: - return (i) + return i else: - return (0) + return 0 -cdef inline dtype_t _kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, +cdef inline float _kernel_mean(Py_ssize_t* histo, float pop,dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): + + cdef Py_ssize_t i + cdef Py_ssize_t mean = 0 + + if pop: + for i in range(max_bin): + mean += histo[i] * i + return mean / pop + else: + return 0 + + +cdef inline float _kernel_subtract_mean(Py_ssize_t* histo, float pop, + dtype_t g, + Py_ssize_t max_bin, + Py_ssize_t mid_bin, float p0, + float p1, Py_ssize_t s0, + Py_ssize_t s1): + + cdef Py_ssize_t i + cdef Py_ssize_t mean = 0 + + if pop: + for i in range(max_bin): + mean += histo[i] * i + return (g - mean / pop) / 2. + 127 + else: + return 0 + + +cdef inline float _kernel_median(Py_ssize_t* histo, float pop, dtype_t g, Py_ssize_t max_bin, Py_ssize_t mid_bin, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i - cdef Py_ssize_t mean = 0 - - if pop: - for i in range(max_bin): - mean += histo[i] * i - return (mean / pop) - else: - return (0) - - -cdef inline dtype_t _kernel_subtract_mean(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t max_bin, - Py_ssize_t mid_bin, float p0, - float p1, Py_ssize_t s0, - Py_ssize_t s1): - - cdef Py_ssize_t i - cdef Py_ssize_t mean = 0 - - if pop: - for i in range(max_bin): - mean += histo[i] * i - return ((g - mean / pop) / 2. + 127) - else: - return (0) - - -cdef inline dtype_t _kernel_median(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): - cdef Py_ssize_t i cdef float sum = pop / 2.0 @@ -152,30 +151,30 @@ cdef inline dtype_t _kernel_median(Py_ssize_t* histo, float pop, dtype_t g, if histo[i]: sum -= histo[i] if sum < 0: - return (i) + return i else: - return (0) + return 0 -cdef inline dtype_t _kernel_minimum(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_minimum(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i if pop: for i in range(max_bin): if histo[i]: - return (i) + return i else: - return (0) + return 0 -cdef inline dtype_t _kernel_modal(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_modal(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t hmax = 0, imax = 0 @@ -184,16 +183,17 @@ cdef inline dtype_t _kernel_modal(Py_ssize_t* histo, float pop, dtype_t g, if histo[i] > hmax: hmax = histo[i] imax = i - return (imax) + return imax else: - return (0) + return 0 -cdef inline dtype_t _kernel_enhance_contrast(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t max_bin, - Py_ssize_t mid_bin, float p0, - float p1, Py_ssize_t s0, - Py_ssize_t s1): +cdef inline float _kernel_enhance_contrast(Py_ssize_t* histo, float pop, + dtype_t g, + Py_ssize_t max_bin, + Py_ssize_t mid_bin, float p0, + float p1, Py_ssize_t s0, + Py_ssize_t s1): cdef Py_ssize_t i, imin, imax @@ -207,25 +207,25 @@ cdef inline dtype_t _kernel_enhance_contrast(Py_ssize_t* histo, float pop, imin = i break if imax - g < g - imin: - return (imax) + return imax else: - return (imin) + return imin else: - return (0) + return 0 -cdef inline dtype_t _kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): - return (pop) + return pop -cdef inline dtype_t _kernel_threshold(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_threshold(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t mean = 0 @@ -233,15 +233,15 @@ cdef inline dtype_t _kernel_threshold(Py_ssize_t* histo, float pop, dtype_t g, if pop: for i in range(max_bin): mean += histo[i] * i - return (g > (mean / pop)) + return g > (mean / pop) else: - return (0) + return 0 -cdef inline dtype_t _kernel_tophat(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_tophat(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i @@ -249,23 +249,22 @@ cdef inline dtype_t _kernel_tophat(Py_ssize_t* histo, float pop, dtype_t g, for i in range(max_bin - 1, -1, -1): if histo[i]: break - - return (i - g) + return i - g else: - return (0) + return 0 -cdef inline dtype_t _kernel_noise_filter(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t max_bin, - Py_ssize_t mid_bin, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_noise_filter(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, + Py_ssize_t mid_bin, float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t min_i # early stop if at least one pixel of the neighborhood has the same g if histo[g] > 0: - return 0 + return 0 for i in range(g, -1, -1): if histo[i]: @@ -275,35 +274,33 @@ cdef inline dtype_t _kernel_noise_filter(Py_ssize_t* histo, float pop, if histo[i]: break if i - g < min_i: - return (i - g) + return i - g else: - return min_i + return min_i -cdef inline dtype_t _kernel_entropy(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_entropy(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i cdef float e, p if pop: e = 0. - for i in range(max_bin): p = histo[i] / pop if p > 0: e -= p * log(p) / 0.6931471805599453 - - return e + return e else: - return (0) + return 0 -cdef inline dtype_t _kernel_otsu(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_otsu(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t max_i cdef float P, mu1, mu2, q1, new_q1, sigma_b, max_sigma_b @@ -313,9 +310,9 @@ cdef inline dtype_t _kernel_otsu(Py_ssize_t* histo, float pop, dtype_t g, if pop: for i in range(max_bin): mu += histo[i] * i - mu = (mu / pop) + mu = mu / pop else: - return (0) + return 0 # maximizing the between class variance max_i = 0 @@ -335,242 +332,174 @@ cdef inline dtype_t _kernel_otsu(Py_ssize_t* histo, float pop, dtype_t g, max_i = i q1 = new_q1 - return max_i + return max_i def _autolevel(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_autolevel[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_autolevel[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_autolevel[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) def _bottomhat(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_bottomhat[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_bottomhat[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_bottomhat[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) def _equalize(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_equalize[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_equalize[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_equalize[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) def _gradient(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_gradient[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_gradient[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_gradient[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) def _maximum(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_maximum[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_maximum[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_maximum[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) def _mean(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_mean[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_mean[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_mean[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) def _subtract_mean(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_subtract_mean[uint8_t], image, selem, mask, - out, shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_subtract_mean[uint16_t], image, selem, mask, - out, shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_subtract_mean[dtype_t], image, selem, mask, + out, shift_x, shift_y, 0, 0, 0, 0, max_bin) def _median(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_median[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_median[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_median[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) def _minimum(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_minimum[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_minimum[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_minimum[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) def _enhance_contrast(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_enhance_contrast[uint8_t], image, selem, mask, - out, shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_enhance_contrast[uint16_t], image, selem, mask, - out, shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_enhance_contrast[dtype_t], image, selem, mask, + out, shift_x, shift_y, 0, 0, 0, 0, max_bin) def _modal(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_modal[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_modal[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_modal[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) def _pop(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_pop[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_pop[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_pop[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) def _threshold(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_threshold[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_threshold[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_threshold[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) def _tophat(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_tophat[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_tophat[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_tophat[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) def _noise_filter(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_noise_filter[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_noise_filter[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_noise_filter[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) def _entropy(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_entropy[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_entropy[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_entropy[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) def _otsu(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_otsu[uint8_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_otsu[uint16_t], image, selem, mask, out, - shift_x, shift_y, 0, 0, 0, 0, max_bin) + _core(_kernel_otsu[dtype_t], image, selem, mask, out, + shift_x, shift_y, 0, 0, 0, 0, max_bin) diff --git a/skimage/filter/rank/percentile.py b/skimage/filter/rank/percentile.py index e91e0d82..ff3b1559 100644 --- a/skimage/filter/rank/percentile.py +++ b/skimage/filter/rank/percentile.py @@ -10,7 +10,8 @@ described in [1]_. Input image can be 8-bit or 16-bit, for 16-bit input images, the number of histogram bins is determined from the maximum value present in the image. -Result image is 8 or 16-bit with respect to the input image. +Result image is 8-/16-bit or double with respect to the input image and the +rank filter operation. References ---------- @@ -33,9 +34,11 @@ __all__ = ['autolevel_percentile', 'gradient_percentile', 'threshold_percentile'] -def _apply(func, image, selem, out, mask, shift_x, shift_y, p0, p1): +def _apply(func, image, selem, out, mask, shift_x, shift_y, p0, p1, + out_dtype=None): - image, selem, out, mask, max_bin = _handle_input(image, selem, out, mask) + image, selem, out, mask, max_bin = _handle_input(image, selem, out, mask, + out_dtype) func(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, out=out, max_bin=max_bin, p0=p0, p1=p1) diff --git a/skimage/filter/rank/percentile_cy.pyx b/skimage/filter/rank/percentile_cy.pyx index bb4419de..664985f9 100644 --- a/skimage/filter/rank/percentile_cy.pyx +++ b/skimage/filter/rank/percentile_cy.pyx @@ -4,13 +4,13 @@ #cython: wraparound=False cimport numpy as cnp -from .core_cy cimport uint8_t, uint16_t, dtype_t, _core, _min, _max +from .core_cy cimport dtype_t, dtype_t_out, _core, _min, _max -cdef inline dtype_t _kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i, imin, imax, sum, delta @@ -31,18 +31,18 @@ cdef inline dtype_t _kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, delta = imax - imin if delta > 0: - return ((max_bin - 1) * (_min(_max(imin, g), imax) - - imin) / delta) + return (max_bin - 1) * (_min(_max(imin, g), imax) + - imin) / delta else: - return (imax - imin) + return imax - imin else: - return (0) + return 0 -cdef inline dtype_t _kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i, imin, imax, sum, delta @@ -61,15 +61,15 @@ cdef inline dtype_t _kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, imax = i break - return (imax - imin) + return imax - imin else: - return (0) + return 0 -cdef inline dtype_t _kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i, sum, mean, n @@ -84,18 +84,19 @@ cdef inline dtype_t _kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, mean += histo[i] * i if n > 0: - return (mean / n) + return mean / n else: - return (0) + return 0 else: - return (0) + return 0 -cdef inline dtype_t _kernel_subtract_mean(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t max_bin, - Py_ssize_t mid_bin, float p0, - float p1, Py_ssize_t s0, - Py_ssize_t s1): +cdef inline float _kernel_subtract_mean(Py_ssize_t* histo, float pop, + dtype_t g, + Py_ssize_t max_bin, + Py_ssize_t mid_bin, float p0, + float p1, Py_ssize_t s0, + Py_ssize_t s1): cdef Py_ssize_t i, sum, mean, n @@ -109,18 +110,19 @@ cdef inline dtype_t _kernel_subtract_mean(Py_ssize_t* histo, float pop, n += histo[i] mean += histo[i] * i if n > 0: - return ((g - (mean / n)) * .5 + mid_bin) + return (g - (mean / n)) * .5 + mid_bin else: - return (0) + return 0 else: - return (0) + return 0 -cdef inline dtype_t _kernel_enhance_contrast(Py_ssize_t* histo, float pop, - dtype_t g, Py_ssize_t max_bin, - Py_ssize_t mid_bin, float p0, - float p1, Py_ssize_t s0, - Py_ssize_t s1): +cdef inline float _kernel_enhance_contrast(Py_ssize_t* histo, float pop, + dtype_t g, + Py_ssize_t max_bin, + Py_ssize_t mid_bin, float p0, + float p1, Py_ssize_t s0, + Py_ssize_t s1): cdef Py_ssize_t i, imin, imax, sum, delta @@ -139,21 +141,21 @@ cdef inline dtype_t _kernel_enhance_contrast(Py_ssize_t* histo, float pop, imax = i break if g > imax: - return imax + return imax if g < imin: - return imin + return imin if imax - g < g - imin: - return imax + return imax else: - return imin + return imin else: - return (0) + return 0 -cdef inline dtype_t _kernel_percentile(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_percentile(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t sum = 0 @@ -164,15 +166,15 @@ cdef inline dtype_t _kernel_percentile(Py_ssize_t* histo, float pop, dtype_t g, if sum >= p0 * pop: break - return (i) + return i else: - return (0) + return 0 -cdef inline dtype_t _kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i, sum, n @@ -183,15 +185,15 @@ cdef inline dtype_t _kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, sum += histo[i] if (sum >= p0 * pop) and (sum <= p1 * pop): n += histo[i] - return (n) + return n else: - return (0) + return 0 -cdef inline dtype_t _kernel_threshold(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline float _kernel_threshold(Py_ssize_t* histo, float pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + float p0, float p1, + Py_ssize_t s0, Py_ssize_t s1): cdef int i cdef Py_ssize_t sum = 0 @@ -202,124 +204,92 @@ cdef inline dtype_t _kernel_threshold(Py_ssize_t* histo, float pop, dtype_t g, if sum >= p0 * pop: break - return ((max_bin - 1) * (g >= i)) + return (max_bin - 1) * (g >= i) else: - return (0) + return 0 def _autolevel(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask, - dtype_t[:, ::1] out, - char shift_x, char shift_y, float p0, float p1, - Py_ssize_t max_bin): + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t_out[:, ::1] out, + char shift_x, char shift_y, float p0, float p1, + Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_autolevel[uint8_t], image, selem, mask, out, - shift_x, shift_y, p0, p1, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_autolevel[uint16_t], image, selem, mask, out, - shift_x, shift_y, p0, p1, 0, 0, max_bin) + _core(_kernel_autolevel[dtype_t], image, selem, mask, out, + shift_x, shift_y, p0, p1, 0, 0, max_bin) def _gradient(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask, - dtype_t[:, ::1] out, - char shift_x, char shift_y, float p0, float p1, - Py_ssize_t max_bin): + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t_out[:, ::1] out, + char shift_x, char shift_y, float p0, float p1, + Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_gradient[uint8_t], image, selem, mask, out, - shift_x, shift_y, p0, p1, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_gradient[uint16_t], image, selem, mask, out, - shift_x, shift_y, p0, p1, 0, 0, max_bin) + _core(_kernel_gradient[dtype_t], image, selem, mask, out, + shift_x, shift_y, p0, p1, 0, 0, max_bin) def _mean(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask, - dtype_t[:, ::1] out, - char shift_x, char shift_y, float p0, float p1, - Py_ssize_t max_bin): + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t_out[:, ::1] out, + char shift_x, char shift_y, float p0, float p1, + Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_mean[uint8_t], image, selem, mask, out, - shift_x, shift_y, p0, p1, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_mean[uint16_t], image, selem, mask, out, - shift_x, shift_y, p0, p1, 0, 0, max_bin) + _core(_kernel_mean[dtype_t], image, selem, mask, out, + shift_x, shift_y, p0, p1, 0, 0, max_bin) def _subtract_mean(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, - dtype_t[:, ::1] out, + dtype_t_out[:, ::1] out, char shift_x, char shift_y, float p0, float p1, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_subtract_mean[uint8_t], image, selem, mask, - out, shift_x, shift_y, p0, p1, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_subtract_mean[uint16_t], image, selem, mask, - out, shift_x, shift_y, p0, p1, 0, 0, max_bin) + _core(_kernel_subtract_mean[dtype_t], image, selem, mask, + out, shift_x, shift_y, p0, p1, 0, 0, max_bin) def _enhance_contrast(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask, - dtype_t[:, ::1] out, - char shift_x, char shift_y, float p0, float p1, - Py_ssize_t max_bin): + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t_out[:, ::1] out, + char shift_x, char shift_y, float p0, float p1, + Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_enhance_contrast[uint8_t], image, selem, mask, - out, shift_x, shift_y, p0, p1, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_enhance_contrast[uint16_t], image, selem, mask, - out, shift_x, shift_y, p0, p1, 0, 0, max_bin) + _core(_kernel_enhance_contrast[dtype_t], image, selem, mask, + out, shift_x, shift_y, p0, p1, 0, 0, max_bin) def _percentile(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask, - dtype_t[:, ::1] out, - char shift_x, char shift_y, float p0, Py_ssize_t max_bin): + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t_out[:, ::1] out, + char shift_x, char shift_y, float p0, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_percentile[uint8_t], image, selem, mask, out, - shift_x, shift_y, p0, 1, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_percentile[uint16_t], image, selem, mask, out, - shift_x, shift_y, p0, 1, 0, 0, max_bin) + _core(_kernel_percentile[dtype_t], image, selem, mask, out, + shift_x, shift_y, p0, 1, 0, 0, max_bin) def _pop(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask, - dtype_t[:, ::1] out, - char shift_x, char shift_y, float p0, float p1, - Py_ssize_t max_bin): + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t_out[:, ::1] out, + char shift_x, char shift_y, float p0, float p1, + Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_pop[uint8_t], image, selem, mask, out, - shift_x, shift_y, p0, p1, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_pop[uint16_t], image, selem, mask, out, - shift_x, shift_y, p0, p1, 0, 0, max_bin) + _core(_kernel_pop[dtype_t], image, selem, mask, out, + shift_x, shift_y, p0, p1, 0, 0, max_bin) def _threshold(dtype_t[:, ::1] image, - char[:, ::1] selem, - char[:, ::1] mask, - dtype_t[:, ::1] out, - char shift_x, char shift_y, float p0, Py_ssize_t max_bin): + char[:, ::1] selem, + char[:, ::1] mask, + dtype_t_out[:, ::1] out, + char shift_x, char shift_y, float p0, Py_ssize_t max_bin): - if dtype_t is uint8_t: - _core[uint8_t](_kernel_threshold[uint8_t], image, selem, mask, out, - shift_x, shift_y, p0, 1, 0, 0, max_bin) - elif dtype_t is uint16_t: - _core[uint16_t](_kernel_threshold[uint16_t], image, selem, mask, out, - shift_x, shift_y, p0, 1, 0, 0, max_bin) + _core(_kernel_threshold[dtype_t], image, selem, mask, out, + shift_x, shift_y, p0, 1, 0, 0, max_bin) From 8ea6d1deb0b64a47ab38bb8a6aeedacaab71107a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 12 Jul 2013 23:06:44 +0200 Subject: [PATCH 35/43] Replace all float dtypes with double --- skimage/filter/rank/bilateral_cy.pyx | 16 +-- skimage/filter/rank/core_cy.pxd | 8 +- skimage/filter/rank/core_cy.pyx | 16 +-- skimage/filter/rank/generic_cy.pyx | 155 +++++++++++++------------- skimage/filter/rank/percentile_cy.pyx | 90 +++++++-------- 5 files changed, 143 insertions(+), 142 deletions(-) diff --git a/skimage/filter/rank/bilateral_cy.pyx b/skimage/filter/rank/bilateral_cy.pyx index b8e0d1e7..de2b3e53 100644 --- a/skimage/filter/rank/bilateral_cy.pyx +++ b/skimage/filter/rank/bilateral_cy.pyx @@ -9,10 +9,10 @@ from libc.math cimport log from .core_cy cimport dtype_t, dtype_t_out, _core -cdef inline float _kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_mean(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t bilat_pop = 0 @@ -31,10 +31,10 @@ cdef inline float _kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_pop(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t bilat_pop = 0 diff --git a/skimage/filter/rank/core_cy.pxd b/skimage/filter/rank/core_cy.pxd index a1e44f98..2e97e50a 100644 --- a/skimage/filter/rank/core_cy.pxd +++ b/skimage/filter/rank/core_cy.pxd @@ -15,14 +15,14 @@ cdef dtype_t _max(dtype_t a, dtype_t b) cdef dtype_t _min(dtype_t a, dtype_t b) -cdef void _core(float kernel(Py_ssize_t*, float, dtype_t, - Py_ssize_t, Py_ssize_t, float, - float, Py_ssize_t, Py_ssize_t), +cdef void _core(double kernel(Py_ssize_t*, double, dtype_t, + Py_ssize_t, Py_ssize_t, double, + double, Py_ssize_t, Py_ssize_t), dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, dtype_t_out[:, ::1] out, char shift_x, char shift_y, - float p0, float p1, + double p0, double p1, Py_ssize_t s0, Py_ssize_t s1, Py_ssize_t max_bin) except * diff --git a/skimage/filter/rank/core_cy.pyx b/skimage/filter/rank/core_cy.pyx index 854a3ce7..02c2c8d0 100644 --- a/skimage/filter/rank/core_cy.pyx +++ b/skimage/filter/rank/core_cy.pyx @@ -17,13 +17,13 @@ cdef inline dtype_t _min(dtype_t a, dtype_t b): return a if a <= b else b -cdef inline void histogram_increment(Py_ssize_t* histo, float* pop, +cdef inline void histogram_increment(Py_ssize_t* histo, double* pop, dtype_t value): histo[value] += 1 pop[0] += 1 -cdef inline void histogram_decrement(Py_ssize_t* histo, float* pop, +cdef inline void histogram_decrement(Py_ssize_t* histo, double* pop, dtype_t value): histo[value] -= 1 pop[0] -= 1 @@ -42,15 +42,15 @@ cdef inline char is_in_mask(Py_ssize_t rows, Py_ssize_t cols, return 0 -cdef void _core(float kernel(Py_ssize_t*, float, dtype_t, - Py_ssize_t, Py_ssize_t, float, - float, Py_ssize_t, Py_ssize_t), +cdef void _core(double kernel(Py_ssize_t*, double, dtype_t, + Py_ssize_t, Py_ssize_t, double, + double, Py_ssize_t, Py_ssize_t), dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, dtype_t_out[:, ::1] out, char shift_x, char shift_y, - float p0, float p1, + double p0, double p1, Py_ssize_t s0, Py_ssize_t s1, Py_ssize_t max_bin) except *: """Compute histogram for each pixel neighborhood, apply kernel function and @@ -82,8 +82,8 @@ cdef void _core(float kernel(Py_ssize_t*, float, dtype_t, # define local variable types cdef Py_ssize_t r, c, rr, cc, s, value, local_max, i, even_row - # number of pixels actually inside the neighborhood (float) - cdef float pop = 0 + # number of pixels actually inside the neighborhood (double) + cdef double pop = 0 # the current local histogram distribution cdef Py_ssize_t* histo = malloc(max_bin * sizeof(Py_ssize_t)) diff --git a/skimage/filter/rank/generic_cy.pyx b/skimage/filter/rank/generic_cy.pyx index 47cb99da..a773f62c 100644 --- a/skimage/filter/rank/generic_cy.pyx +++ b/skimage/filter/rank/generic_cy.pyx @@ -9,10 +9,10 @@ from libc.math cimport log from .core_cy cimport dtype_t, dtype_t_out, _core -cdef inline float _kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_autolevel(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i, imin, imax, delta @@ -27,17 +27,17 @@ cdef inline float _kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, break delta = imax - imin if delta > 0: - return (max_bin - 1) * (g - imin) / delta + return (max_bin - 1) * (g - imin) / delta else: return imax - imin else: return 0 -cdef inline float _kernel_bottomhat(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_bottomhat(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i @@ -50,10 +50,10 @@ cdef inline float _kernel_bottomhat(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_equalize(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_equalize(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t sum = 0 @@ -68,10 +68,10 @@ cdef inline float _kernel_equalize(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_gradient(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i, imin, imax @@ -89,10 +89,10 @@ cdef inline float _kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_maximum(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_maximum(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i @@ -104,10 +104,10 @@ cdef inline float _kernel_maximum(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_mean(Py_ssize_t* histo, float pop,dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_mean(Py_ssize_t* histo, double pop,dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t mean = 0 @@ -120,12 +120,12 @@ cdef inline float _kernel_mean(Py_ssize_t* histo, float pop,dtype_t g, return 0 -cdef inline float _kernel_subtract_mean(Py_ssize_t* histo, float pop, - dtype_t g, - Py_ssize_t max_bin, - Py_ssize_t mid_bin, float p0, - float p1, Py_ssize_t s0, - Py_ssize_t s1): +cdef inline double _kernel_subtract_mean(Py_ssize_t* histo, double pop, + dtype_t g, + Py_ssize_t max_bin, + Py_ssize_t mid_bin, double p0, + double p1, Py_ssize_t s0, + Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t mean = 0 @@ -138,13 +138,13 @@ cdef inline float _kernel_subtract_mean(Py_ssize_t* histo, float pop, return 0 -cdef inline float _kernel_median(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_median(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i - cdef float sum = pop / 2.0 + cdef double sum = pop / 2.0 if pop: for i in range(max_bin): @@ -156,10 +156,10 @@ cdef inline float _kernel_median(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_minimum(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_minimum(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i @@ -171,10 +171,10 @@ cdef inline float _kernel_minimum(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_modal(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_modal(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t hmax = 0, imax = 0 @@ -188,12 +188,12 @@ cdef inline float _kernel_modal(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_enhance_contrast(Py_ssize_t* histo, float pop, - dtype_t g, - Py_ssize_t max_bin, - Py_ssize_t mid_bin, float p0, - float p1, Py_ssize_t s0, - Py_ssize_t s1): +cdef inline double _kernel_enhance_contrast(Py_ssize_t* histo, double pop, + dtype_t g, + Py_ssize_t max_bin, + Py_ssize_t mid_bin, double p0, + double p1, Py_ssize_t s0, + Py_ssize_t s1): cdef Py_ssize_t i, imin, imax @@ -214,18 +214,18 @@ cdef inline float _kernel_enhance_contrast(Py_ssize_t* histo, float pop, return 0 -cdef inline float _kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_pop(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): return pop -cdef inline float _kernel_threshold(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_threshold(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t mean = 0 @@ -238,10 +238,10 @@ cdef inline float _kernel_threshold(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_tophat(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_tophat(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i @@ -254,10 +254,11 @@ cdef inline float _kernel_tophat(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_noise_filter(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, - Py_ssize_t mid_bin, float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_noise_filter(Py_ssize_t* histo, double pop, + dtype_t g, Py_ssize_t max_bin, + Py_ssize_t mid_bin, double p0, + double p1, Py_ssize_t s0, + Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t min_i @@ -279,12 +280,12 @@ cdef inline float _kernel_noise_filter(Py_ssize_t* histo, float pop, dtype_t g, return min_i -cdef inline float _kernel_entropy(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_entropy(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i - cdef float e, p + cdef double e, p if pop: e = 0. @@ -297,14 +298,14 @@ cdef inline float _kernel_entropy(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_otsu(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_otsu(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t max_i - cdef float P, mu1, mu2, q1, new_q1, sigma_b, max_sigma_b - cdef float mu = 0. + cdef double P, mu1, mu2, q1, new_q1, sigma_b, max_sigma_b + cdef double mu = 0. # compute local mean if pop: diff --git a/skimage/filter/rank/percentile_cy.pyx b/skimage/filter/rank/percentile_cy.pyx index 664985f9..31afd53a 100644 --- a/skimage/filter/rank/percentile_cy.pyx +++ b/skimage/filter/rank/percentile_cy.pyx @@ -7,10 +7,10 @@ cimport numpy as cnp from .core_cy cimport dtype_t, dtype_t_out, _core, _min, _max -cdef inline float _kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_autolevel(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i, imin, imax, sum, delta @@ -31,7 +31,7 @@ cdef inline float _kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, delta = imax - imin if delta > 0: - return (max_bin - 1) * (_min(_max(imin, g), imax) + return (max_bin - 1) * (_min(_max(imin, g), imax) - imin) / delta else: return imax - imin @@ -39,10 +39,10 @@ cdef inline float _kernel_autolevel(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_gradient(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i, imin, imax, sum, delta @@ -66,10 +66,10 @@ cdef inline float _kernel_gradient(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_mean(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i, sum, mean, n @@ -91,12 +91,12 @@ cdef inline float _kernel_mean(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_subtract_mean(Py_ssize_t* histo, float pop, - dtype_t g, - Py_ssize_t max_bin, - Py_ssize_t mid_bin, float p0, - float p1, Py_ssize_t s0, - Py_ssize_t s1): +cdef inline double _kernel_subtract_mean(Py_ssize_t* histo, double pop, + dtype_t g, + Py_ssize_t max_bin, + Py_ssize_t mid_bin, double p0, + double p1, Py_ssize_t s0, + Py_ssize_t s1): cdef Py_ssize_t i, sum, mean, n @@ -117,12 +117,12 @@ cdef inline float _kernel_subtract_mean(Py_ssize_t* histo, float pop, return 0 -cdef inline float _kernel_enhance_contrast(Py_ssize_t* histo, float pop, - dtype_t g, - Py_ssize_t max_bin, - Py_ssize_t mid_bin, float p0, - float p1, Py_ssize_t s0, - Py_ssize_t s1): +cdef inline double _kernel_enhance_contrast(Py_ssize_t* histo, double pop, + dtype_t g, + Py_ssize_t max_bin, + Py_ssize_t mid_bin, double p0, + double p1, Py_ssize_t s0, + Py_ssize_t s1): cdef Py_ssize_t i, imin, imax, sum, delta @@ -152,10 +152,10 @@ cdef inline float _kernel_enhance_contrast(Py_ssize_t* histo, float pop, return 0 -cdef inline float _kernel_percentile(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_percentile(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i cdef Py_ssize_t sum = 0 @@ -171,10 +171,10 @@ cdef inline float _kernel_percentile(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_pop(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef Py_ssize_t i, sum, n @@ -190,10 +190,10 @@ cdef inline float _kernel_pop(Py_ssize_t* histo, float pop, dtype_t g, return 0 -cdef inline float _kernel_threshold(Py_ssize_t* histo, float pop, dtype_t g, - Py_ssize_t max_bin, Py_ssize_t mid_bin, - float p0, float p1, - Py_ssize_t s0, Py_ssize_t s1): +cdef inline double _kernel_threshold(Py_ssize_t* histo, double pop, dtype_t g, + Py_ssize_t max_bin, Py_ssize_t mid_bin, + double p0, double p1, + Py_ssize_t s0, Py_ssize_t s1): cdef int i cdef Py_ssize_t sum = 0 @@ -213,7 +213,7 @@ def _autolevel(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, dtype_t_out[:, ::1] out, - char shift_x, char shift_y, float p0, float p1, + char shift_x, char shift_y, double p0, double p1, Py_ssize_t max_bin): _core(_kernel_autolevel[dtype_t], image, selem, mask, out, @@ -224,7 +224,7 @@ def _gradient(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, dtype_t_out[:, ::1] out, - char shift_x, char shift_y, float p0, float p1, + char shift_x, char shift_y, double p0, double p1, Py_ssize_t max_bin): _core(_kernel_gradient[dtype_t], image, selem, mask, out, @@ -235,7 +235,7 @@ def _mean(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, dtype_t_out[:, ::1] out, - char shift_x, char shift_y, float p0, float p1, + char shift_x, char shift_y, double p0, double p1, Py_ssize_t max_bin): _core(_kernel_mean[dtype_t], image, selem, mask, out, @@ -246,7 +246,7 @@ def _subtract_mean(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, dtype_t_out[:, ::1] out, - char shift_x, char shift_y, float p0, float p1, + char shift_x, char shift_y, double p0, double p1, Py_ssize_t max_bin): _core(_kernel_subtract_mean[dtype_t], image, selem, mask, @@ -257,7 +257,7 @@ def _enhance_contrast(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, dtype_t_out[:, ::1] out, - char shift_x, char shift_y, float p0, float p1, + char shift_x, char shift_y, double p0, double p1, Py_ssize_t max_bin): _core(_kernel_enhance_contrast[dtype_t], image, selem, mask, @@ -268,7 +268,7 @@ def _percentile(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, dtype_t_out[:, ::1] out, - char shift_x, char shift_y, float p0, Py_ssize_t max_bin): + char shift_x, char shift_y, double p0, Py_ssize_t max_bin): _core(_kernel_percentile[dtype_t], image, selem, mask, out, shift_x, shift_y, p0, 1, 0, 0, max_bin) @@ -278,7 +278,7 @@ def _pop(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, dtype_t_out[:, ::1] out, - char shift_x, char shift_y, float p0, float p1, + char shift_x, char shift_y, double p0, double p1, Py_ssize_t max_bin): _core(_kernel_pop[dtype_t], image, selem, mask, out, @@ -289,7 +289,7 @@ def _threshold(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, dtype_t_out[:, ::1] out, - char shift_x, char shift_y, float p0, Py_ssize_t max_bin): + char shift_x, char shift_y, double p0, Py_ssize_t max_bin): _core(_kernel_threshold[dtype_t], image, selem, mask, out, shift_x, shift_y, p0, 1, 0, 0, max_bin) From bb4a8aff26abd6b080e372c5058e978886b9bad7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Fri, 12 Jul 2013 23:20:32 +0200 Subject: [PATCH 36/43] Add test for output dtype of entropy --- skimage/filter/rank/tests/test_rank.py | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/skimage/filter/rank/tests/test_rank.py b/skimage/filter/rank/tests/test_rank.py index d2906f98..c190fb57 100644 --- a/skimage/filter/rank/tests/test_rank.py +++ b/skimage/filter/rank/tests/test_rank.py @@ -163,8 +163,8 @@ def test_compare_autolevels(): def test_compare_autolevels_16bit(): - # compare autolevel(16-bit) and percentile autolevel(16-bit) with p0=0.0 and - # p1=1.0 should returns the same arrays + # compare autolevel(16-bit) and percentile autolevel(16-bit) with p0=0.0 + # and p1=1.0 should returns the same arrays image = data.camera().astype(np.uint16) * 4 @@ -193,8 +193,8 @@ def test_compare_ubyte_vs_float(): 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 + # 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()) @@ -216,8 +216,8 @@ def test_compare_8bit_unsigned_vs_signed(): 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 + # filters applied on 8-bit image ore 16-bit image (having only real 8-bit + # of dynamic) should be identical image8 = util.img_as_ubyte(data.camera()) image16 = image8.astype(np.uint16) @@ -327,7 +327,8 @@ def test_smallest_selem16(): def test_empty_selem(): - # check that min, max and mean returns zeros if structuring element is empty + # check that min, max and mean returns zeros if structuring element is + # empty image = np.zeros((5, 5), dtype=np.uint16) out = np.zeros_like(image) @@ -402,6 +403,10 @@ def test_entropy(): np.reshape(np.arange(4096), (64, 64)), (2, 2)).astype(np.uint16) assert(np.max(rank.entropy(data, selem)) == 12) + # make sure output is of dtype double + out = rank.entropy(data, np.ones((16, 16), dtype=np.uint8)) + assert out.dtype == np.double + def test_selem_dtypes(): From 5c5c67027effce176c2ad4ceb8ee75be461964bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Wed, 31 Jul 2013 19:12:44 +0200 Subject: [PATCH 37/43] Add missing p1 parameter to percentile and threshold functions --- skimage/filter/rank/percentile_cy.pyx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/skimage/filter/rank/percentile_cy.pyx b/skimage/filter/rank/percentile_cy.pyx index 31afd53a..ffa5e1b0 100644 --- a/skimage/filter/rank/percentile_cy.pyx +++ b/skimage/filter/rank/percentile_cy.pyx @@ -268,7 +268,8 @@ def _percentile(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, dtype_t_out[:, ::1] out, - char shift_x, char shift_y, double p0, Py_ssize_t max_bin): + char shift_x, char shift_y, double p0, double p1, + Py_ssize_t max_bin): _core(_kernel_percentile[dtype_t], image, selem, mask, out, shift_x, shift_y, p0, 1, 0, 0, max_bin) @@ -289,7 +290,8 @@ def _threshold(dtype_t[:, ::1] image, char[:, ::1] selem, char[:, ::1] mask, dtype_t_out[:, ::1] out, - char shift_x, char shift_y, double p0, Py_ssize_t max_bin): + char shift_x, char shift_y, double p0, double p1, + Py_ssize_t max_bin): _core(_kernel_threshold[dtype_t], image, selem, mask, out, shift_x, shift_y, p0, 1, 0, 0, max_bin) From 391e9761571ebd486e2ff7784b0a64a964580ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Wed, 31 Jul 2013 19:24:18 +0200 Subject: [PATCH 38/43] Add specific branch for the percentile p0 = 0 case --- skimage/filter/rank/percentile_cy.pyx | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/skimage/filter/rank/percentile_cy.pyx b/skimage/filter/rank/percentile_cy.pyx index ffa5e1b0..8fad59c5 100644 --- a/skimage/filter/rank/percentile_cy.pyx +++ b/skimage/filter/rank/percentile_cy.pyx @@ -161,11 +161,15 @@ cdef inline double _kernel_percentile(Py_ssize_t* histo, double pop, dtype_t g, cdef Py_ssize_t sum = 0 if pop: - for i in range(max_bin): - sum += histo[i] - if sum >= p0 * pop: - break - + if p0 == 0: # make sure p0 == 0 returns the minimum filter + for i in range(max_bin): + if histo[i]: + break + else: + for i in range(max_bin): + sum += histo[i] + if sum >= p0 * pop: + break return i else: return 0 From 9f68e7141262dc1fcd54911642d08705773c9b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Wed, 31 Jul 2013 19:27:52 +0200 Subject: [PATCH 39/43] Fix accidential variable naming confusion --- skimage/filter/rank/generic_cy.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/filter/rank/generic_cy.pyx b/skimage/filter/rank/generic_cy.pyx index a773f62c..44c51d55 100644 --- a/skimage/filter/rank/generic_cy.pyx +++ b/skimage/filter/rank/generic_cy.pyx @@ -318,7 +318,7 @@ cdef inline double _kernel_otsu(Py_ssize_t* histo, double pop, dtype_t g, # maximizing the between class variance max_i = 0 q1 = histo[0] / pop - m1 = 0. + mu1 = 0. max_sigma_b = 0. for i in range(1, max_bin): From 7be96b4a013c3a8920c5a44e4be5e505aa4869f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Wed, 31 Jul 2013 19:45:55 +0200 Subject: [PATCH 40/43] Integrate new test cases from @odebeir and fix old function names of dilate and erode --- skimage/filter/rank/tests/test_rank.py | 49 ++++++++++++++++++++++++-- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/skimage/filter/rank/tests/test_rank.py b/skimage/filter/rank/tests/test_rank.py index c190fb57..1d573b81 100644 --- a/skimage/filter/rank/tests/test_rank.py +++ b/skimage/filter/rank/tests/test_rank.py @@ -51,7 +51,7 @@ def test_compare_with_cmorph_dilate(): for r in range(1, 20, 1): elem = np.ones((r, r), dtype=np.uint8) rank.maximum(image=image, selem=elem, out=out, mask=mask) - cm = cmorph.dilate(image=image, selem=elem) + cm = cmorph._dilate(image=image, selem=elem) assert_array_equal(out, cm) @@ -65,7 +65,7 @@ def test_compare_with_cmorph_erode(): for r in range(1, 20, 1): elem = np.ones((r, r), dtype=np.uint8) rank.minimum(image=image, selem=elem, out=out, mask=mask) - cm = cmorph.erode(image=image, selem=elem) + cm = cmorph._erode(image=image, selem=elem) assert_array_equal(out, cm) @@ -454,5 +454,50 @@ def test_bilateral(): assert rank.pop_bilateral(image, selem, s0=11, s1=11)[10, 10] == 2 +def test_percentile_min(): + # check that percentile p0 = 0 is identical to local min + img = data.camera() + img16 = img.astype(np.uint16) + selem = disk(15) + # check for 8bit + img_p0 = rank.percentile(img, selem=selem, p0=0) + img_min = rank.minimum(img, selem=selem) + assert_array_equal(img_p0, img_min) + # check for 16bit + img_p0 = rank.percentile(img16, selem=selem, p0=0) + img_min = rank.minimum(img16, selem=selem) + assert_array_equal(img_p0, img_min) + + +def test_percentile_max(): + # check that percentile p0 = 1 is identical to local max + img = data.camera() + img16 = img.astype(np.uint16) + selem = disk(15) + # check for 8bit + img_p0 = rank.percentile(img, selem=selem, p0=1.) + img_max = rank.maximum(img, selem=selem) + assert_array_equal(img_p0, img_max) + # check for 16bit + img_p0 = rank.percentile(img16, selem=selem, p0=1.) + img_max = rank.maximum(img16, selem=selem) + assert_array_equal(img_p0, img_max) + + +def test_percentile_median(): + # check that percentile p0 = 0.5 is identical to local median + img = data.camera() + img16 = img.astype(np.uint16) + selem = disk(15) + # check for 8bit + img_p0 = rank.percentile(img, selem=selem, p0=.5) + img_max = rank.median(img, selem=selem) + assert_array_equal(img_p0, img_max) + # check for 16bit + img_p0 = rank.percentile(img16, selem=selem, p0=.5) + img_max = rank.median(img16, selem=selem) + assert_array_equal(img_p0, img_max) + + if __name__ == "__main__": run_module_suite() From f9f405a8ba9e82f23f620843115035e0214ea1a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Wed, 31 Jul 2013 19:50:05 +0200 Subject: [PATCH 41/43] Fix invalid previous fix for percentile edge case --- skimage/filter/rank/percentile_cy.pyx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/skimage/filter/rank/percentile_cy.pyx b/skimage/filter/rank/percentile_cy.pyx index 8fad59c5..5989cdca 100644 --- a/skimage/filter/rank/percentile_cy.pyx +++ b/skimage/filter/rank/percentile_cy.pyx @@ -161,14 +161,14 @@ cdef inline double _kernel_percentile(Py_ssize_t* histo, double pop, dtype_t g, cdef Py_ssize_t sum = 0 if pop: - if p0 == 0: # make sure p0 == 0 returns the minimum filter - for i in range(max_bin): + if p0 == 1: # make sure p0 = 1 returns the maximum filter + for i in range(max_bin - 1, -1, -1): if histo[i]: break else: for i in range(max_bin): sum += histo[i] - if sum >= p0 * pop: + if sum > p0 * pop: break return i else: From d9196be3c3ba3158e1960541cd059c9861e294fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Thu, 1 Aug 2013 08:45:11 +0200 Subject: [PATCH 42/43] Fix loop ranges of rank filter kernel functions --- skimage/filter/rank/generic_cy.pyx | 4 ++-- skimage/filter/rank/percentile_cy.pyx | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/skimage/filter/rank/generic_cy.pyx b/skimage/filter/rank/generic_cy.pyx index 44c51d55..9815d6ea 100644 --- a/skimage/filter/rank/generic_cy.pyx +++ b/skimage/filter/rank/generic_cy.pyx @@ -29,7 +29,7 @@ cdef inline double _kernel_autolevel(Py_ssize_t* histo, double pop, dtype_t g, if delta > 0: return (max_bin - 1) * (g - imin) / delta else: - return imax - imin + return 0 else: return 0 @@ -321,7 +321,7 @@ cdef inline double _kernel_otsu(Py_ssize_t* histo, double pop, dtype_t g, mu1 = 0. max_sigma_b = 0. - for i in range(1, max_bin): + for i in range(max_bin): P = histo[i] / pop new_q1 = q1 + P if new_q1 > 0: diff --git a/skimage/filter/rank/percentile_cy.pyx b/skimage/filter/rank/percentile_cy.pyx index 5989cdca..e951a76e 100644 --- a/skimage/filter/rank/percentile_cy.pyx +++ b/skimage/filter/rank/percentile_cy.pyx @@ -17,7 +17,7 @@ cdef inline double _kernel_autolevel(Py_ssize_t* histo, double pop, dtype_t g, if pop: sum = 0 p1 = 1.0 - p1 - for i in range(max_bin - 1): + for i in range(max_bin): sum += histo[i] if sum > p0 * pop: imin = i @@ -55,7 +55,7 @@ cdef inline double _kernel_gradient(Py_ssize_t* histo, double pop, dtype_t g, imin = i break sum = 0 - for i in range((max_bin - 1), -1, -1): + for i in range(max_bin - 1, -1, -1): sum += histo[i] if sum >= p1 * pop: imax = i @@ -135,7 +135,7 @@ cdef inline double _kernel_enhance_contrast(Py_ssize_t* histo, double pop, imin = i break sum = 0 - for i in range((max_bin - 1), -1, -1): + for i in range(max_bin - 1, -1, -1): sum += histo[i] if sum > p1 * pop: imax = i From d883b456667b5c6893c28149f33cce7851ab8d07 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johannes=20Sch=C3=B6nberger?= Date: Thu, 1 Aug 2013 11:12:55 +0200 Subject: [PATCH 43/43] Fix Otsu rank filter kernel loop range --- skimage/filter/rank/generic_cy.pyx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/skimage/filter/rank/generic_cy.pyx b/skimage/filter/rank/generic_cy.pyx index 9815d6ea..dcf6e361 100644 --- a/skimage/filter/rank/generic_cy.pyx +++ b/skimage/filter/rank/generic_cy.pyx @@ -321,7 +321,7 @@ cdef inline double _kernel_otsu(Py_ssize_t* histo, double pop, dtype_t g, mu1 = 0. max_sigma_b = 0. - for i in range(max_bin): + for i in range(1, max_bin): P = histo[i] / pop new_q1 = q1 + P if new_q1 > 0: