Add local geometric mean filter

Add the filter in cython with a specific kernnel.
The implementatio is based on the log-average method.
The test were added the npz.
This commit is contained in:
Guillaume Lemaitre
2015-12-04 19:26:37 +01:00
parent bc7e9588e9
commit 4bc1c587ed
5 changed files with 107 additions and 8 deletions
Binary file not shown.
+4 -3
View File
@@ -1,7 +1,7 @@
from .generic import (autolevel, bottomhat, equalize, gradient, maximum, mean,
subtract_mean, median, minimum, modal, enhance_contrast,
pop, threshold, tophat, noise_filter, entropy, otsu,
sum, windowed_histogram)
geometric_mean, subtract_mean, median, minimum, modal,
enhance_contrast, pop, threshold, tophat, noise_filter,
entropy, otsu, sum, windowed_histogram)
from ._percentile import (autolevel_percentile, gradient_percentile,
mean_percentile, subtract_mean_percentile,
enhance_contrast_percentile, percentile,
@@ -17,6 +17,7 @@ __all__ = ['autolevel',
'gradient_percentile',
'maximum',
'mean',
'geometric_mean',
'mean_percentile',
'mean_bilateral',
'subtract_mean',
+40 -2
View File
@@ -25,8 +25,9 @@ from . import generic_cy
__all__ = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'maximum', 'mean',
'subtract_mean', 'median', 'minimum', 'modal', 'enhance_contrast',
'pop', 'threshold', 'tophat', 'noise_filter', 'entropy', 'otsu']
'geometric_mean', 'subtract_mean', 'median', 'minimum', 'modal',
'enhance_contrast', 'pop', 'threshold', 'tophat', 'noise_filter',
'entropy', 'otsu']
def _handle_input(image, selem, out, mask, out_dtype=None, pixel_size=1):
@@ -342,6 +343,43 @@ def mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
return _apply_scalar_per_pixel(generic_cy._mean, image, selem, out=out,
mask=mask, shift_x=shift_x, shift_y=shift_y)
def geometric_mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
"""Return local geometric mean of an image.
Parameters
----------
image : 2-D array (uint8, uint16)
Input image.
selem : 2-D array
The neighborhood expressed as a 2-D array of 1's and 0's.
out : 2-D array (same dtype as input)
If None, a new array is allocated.
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
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 : 2-D array (same dtype as input image)
Output image.
Examples
--------
>>> from skimage import data
>>> from skimage.morphology import disk
>>> from skimage.filters.rank import mean
>>> img = data.camera()
>>> avg = geomtric_mean(img, disk(5))
"""
return _apply_scalar_per_pixel(generic_cy._geometric_mean, image, selem, out=out,
mask=mask, shift_x=shift_x, shift_y=shift_y)
def subtract_mean(image, selem, out=None, mask=None, shift_x=False,
shift_y=False):
+30 -1
View File
@@ -4,7 +4,7 @@
#cython: wraparound=False
cimport numpy as cnp
from libc.math cimport log
from libc.math cimport log, exp, round
from .core_cy cimport dtype_t, dtype_t_out, _core
@@ -133,6 +133,25 @@ cdef inline void _kernel_mean(dtype_t_out* out, Py_ssize_t odepth,
out[0] = <dtype_t_out>0
cdef inline void _kernel_geometric_mean(dtype_t_out* out, Py_ssize_t odepth,
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) nogil:
cdef Py_ssize_t i
cdef double mean = 0.
if pop:
for i in range(max_bin):
if histo[i]:
mean += (histo[i] * log(i+1))
out[0] = <dtype_t_out>round(exp(mean / pop)-1)
else:
out[0] = <dtype_t_out>0
cdef inline void _kernel_subtract_mean(dtype_t_out* out, Py_ssize_t odepth,
Py_ssize_t* histo,
double pop, dtype_t g,
@@ -467,6 +486,16 @@ def _mean(dtype_t[:, ::1] image,
shift_x, shift_y, 0, 0, 0, 0, max_bin)
def _geometric_mean(dtype_t[:, ::1] image,
char[:, ::1] selem,
char[:, ::1] mask,
dtype_t_out[:, :, ::1] out,
signed char shift_x, signed char shift_y, Py_ssize_t max_bin):
_core(_kernel_geometric_mean[dtype_t_out, 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,
+33 -2
View File
@@ -39,6 +39,8 @@ def check_all():
rank.maximum(image, selem))
assert_equal(refs["mean"],
rank.mean(image, selem))
assert_equal(refs["geometric_mean"],
rank.geometric_mean(image, selem)),
assert_equal(refs["mean_percentile"],
rank.mean_percentile(image, selem))
assert_equal(refs["mean_bilateral"],
@@ -102,6 +104,13 @@ def test_random_sizes():
rank.mean(image=image8, selem=elem, mask=mask, out=out8,
shift_x=+1, shift_y=+1)
assert_equal(image8.shape, out8.shape)
rank.geometric_mean(image=image8, selem=elem, mask=mask, out=out8,
shift_x=0, shift_y=0)
assert_equal(image8.shape, out8.shape)
rank.geometric_mean(image=image8, selem=elem, mask=mask, out=out8,
shift_x=+1, shift_y=+1)
assert_equal(image8.shape, out8.shape)
image16 = np.ones((m, n), dtype=np.uint16)
out16 = np.empty_like(image8, dtype=np.uint16)
@@ -112,6 +121,13 @@ def test_random_sizes():
shift_x=+1, shift_y=+1)
assert_equal(image16.shape, out16.shape)
rank.geometric_mean(image=image16, selem=elem, mask=mask, out=out16,
shift_x=0, shift_y=0)
assert_equal(image16.shape, out16.shape)
rank.geometric_mean(image=image16, selem=elem, mask=mask, out=out16,
shift_x=+1, shift_y=+1)
assert_equal(image16.shape, out16.shape)
rank.mean_percentile(image=image16, mask=mask, out=out16,
selem=elem, shift_x=0, shift_y=0, p0=.1, p1=.9)
assert_equal(image16.shape, out16.shape)
@@ -292,8 +308,8 @@ def test_compare_8bit_unsigned_vs_signed():
assert_equal(image_u, img_as_ubyte(image_s))
methods = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'maximum',
'mean', 'subtract_mean', 'median', 'minimum', 'modal',
'enhance_contrast', 'pop', 'threshold', 'tophat']
'mean', 'geometric_mean', 'subtract_mean', 'median', 'minimum',
'modal', 'enhance_contrast', 'pop', 'threshold', 'tophat']
for method in methods:
func = getattr(rank, method)
@@ -338,6 +354,9 @@ def test_trivial_selem8():
rank.mean(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_equal(image, out)
rank.geometric_mean(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_equal(image, out)
rank.minimum(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_equal(image, out)
@@ -361,6 +380,9 @@ def test_trivial_selem16():
rank.mean(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_equal(image, out)
rank.geometric_mean(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_equal(image, out)
rank.minimum(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_equal(image, out)
@@ -407,6 +429,9 @@ def test_smallest_selem16():
rank.mean(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_equal(image, out)
rank.geometric_mean(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_equal(image, out)
rank.minimum(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_equal(image, out)
@@ -432,6 +457,9 @@ def test_empty_selem():
rank.mean(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_equal(res, out)
rank.geometric_mean(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_equal(res, out)
rank.minimum(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_equal(res, out)
@@ -514,6 +542,9 @@ def test_selem_dtypes():
rank.mean(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_equal(image, out)
rank.geometric_mean(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_equal(image, out)
rank.mean_percentile(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_equal(image, out)