Merge pull request #1 from ahojnnes/rank-filters

Rank filters
This commit is contained in:
Olivier Debeir
2012-11-10 08:50:32 -08:00
17 changed files with 1523 additions and 1285 deletions
-5
View File
@@ -29,8 +29,3 @@ this path to your PYTHONPATH variable and compiling the extensions:
License
-------
Please read LICENSE.txt in this directory.
Contact
-------
Stefan van der Walt <stefan at sun.ac.za>
+19 -22
View File
@@ -1,35 +1,32 @@
To use this to build your Cython file use the commandline options:
.. sourcecode:: text
$ python setup.py build_ext --inplace
**To do**
To do
-----
* add simple examples, adapt documentation on existing examples
* add/check existing doc
* adapting tests for each type of filter
**General remarks**
General remarks
---------------
Basically these filters compute local histogram for each pixel. Histogram is build using a moving window in
order to limit redundant computation. The path followed by the moving window is given hereunder
Basically these filters compute local histogram for each pixel. Histogram is
build using a moving window in order to limit redundant computation. The path
followed by the moving window is given hereunder
...-----------------------\
/--------------------------/
\-------------------------- ...
A comparison is proposed with cmorph.dilate algorithm to show how computation costs evolve with respect to image size or
structuring element size. This implementation gives better results for large structuring elements.
A comparison is proposed with cmorph.dilate algorithm to show how computation
costs evolve with respect to image size or structuring element size. This
implementation gives better results for large structuring elements.
A local histogram is update at each pixel by introducing pixel entering the structuring element border and
by removing those leaving it. The histogram size is 8bit (256 bins) for 8 bit images and 2 to 12 bit (up to 4096 bins)
for 16bit image depending on the image maximum value. Image with pixels higher than 4095 raise a ValueError.
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 value are the part of the image participating the the
histogram computation. By default all the image is filtered.
A local histogram is update at each pixel by introducing pixel entering the
structuring element border and by removing those leaving it. The histogram size
is 8bit (256 bins) for 8 bit images and 2 to 12 bit (up to 4096 bins) for 16bit
image depending on the image maximum value. Image with pixels higher than 4095
raise a ValueError.
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 value are the part of the image participating the the histogram
computation. By default all the image is filtered.
+11 -12
View File
@@ -1,18 +1,17 @@
cimport numpy as np
#---------------------------------------------------------------------------
# 16 bit core kernel receives extra information about data bitdepth
#---------------------------------------------------------------------------
# generic cdef functions
cdef int int_max(int a, int b)
cdef int int_min(int a, int b)
cdef _core16(
np.uint16_t kernel(Py_ssize_t * , float, np.uint16_t, Py_ssize_t, Py_ssize_t, Py_ssize_t, float, float, Py_ssize_t, Py_ssize_t),
np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask,
np.ndarray[np.uint16_t, ndim=2] out,
char shift_x, char shift_y, Py_ssize_t bitdepth,
float p0, float p1, Py_ssize_t s0, Py_ssize_t s1)
# 16 bit core kernel receives extra information about data bitdepth
cdef void _core16(np.uint16_t kernel(Py_ssize_t *, float, np.uint16_t,
Py_ssize_t, Py_ssize_t, Py_ssize_t, float,
float, Py_ssize_t, Py_ssize_t),
np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask,
np.ndarray[np.uint16_t, ndim=2] out,
char shift_x, char shift_y, Py_ssize_t bitdepth,
float p0, float p1, Py_ssize_t s0, Py_ssize_t s1) except *
+51 -80
View File
@@ -6,50 +6,40 @@
import numpy as np
cimport numpy as np
from libc.stdlib cimport malloc, free
from _core8 cimport is_in_mask
#---------------------------------------------------------------------------
# 16 bit core kernel receives extra information about data bitdepth
#---------------------------------------------------------------------------
# generic cdef functions
cdef inline int int_max(int a, int b):
return a if a >= b else b
cdef inline int int_min(int a, int b):
return a if a <= b else b
cdef inline void histogram_increment(Py_ssize_t * histo, float * pop, np.uint16_t value):
cdef inline void histogram_increment(Py_ssize_t * histo, float * pop,
np.uint16_t value):
histo[value] += 1
pop[0] += 1.
pop[0] += 1
cdef inline void histogram_decrement(Py_ssize_t * histo, float * pop, np.uint16_t value):
cdef inline void histogram_decrement(Py_ssize_t * histo, float * pop,
np.uint16_t value):
histo[value] -= 1
pop[0] -= 1.
cdef inline np.uint8_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols, Py_ssize_t r, Py_ssize_t c, np.uint8_t * mask):
""" returns 1 if given(r,c) coordinate are within the image frame ([0-rows],[0-cols]) and
inside the given mask
returns 0 otherwise
"""
if r < 0 or r > rows - 1 or c < 0 or c > cols - 1:
return 0
else:
if mask[r * cols + c]:
return 1
else:
return 0
pop[0] -= 1
cdef inline _core16(
np.uint16_t kernel(Py_ssize_t *, float, np.uint16_t, Py_ssize_t, Py_ssize_t, Py_ssize_t, float, float, Py_ssize_t, Py_ssize_t),
np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask,
np.ndarray[np.uint16_t, ndim=2] out,
char shift_x, char shift_y, Py_ssize_t bitdepth,
float p0, float p1, Py_ssize_t s0, Py_ssize_t s1):
""" Main loop, this function computes the histogram for each image point
- data is uint8
- result is uint8 casted
cdef void _core16(np.uint16_t kernel(Py_ssize_t *, float, np.uint16_t,
Py_ssize_t, Py_ssize_t, Py_ssize_t, float,
float, Py_ssize_t, Py_ssize_t),
np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask,
np.ndarray[np.uint16_t, ndim=2] 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]
@@ -70,36 +60,21 @@ cdef inline _core16(
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]
#set maxbin and midbin
cdef Py_ssize_t maxbin = maxbin_list[bitdepth], midbin = midbin_list[bitdepth]
# set maxbin and midbin
cdef Py_ssize_t maxbin = maxbin_list[bitdepth]
cdef Py_ssize_t midbin = midbin_list[bitdepth]
assert (image < maxbin).all()
image = np.ascontiguousarray(image)
if mask is None:
mask = np.ones((rows, cols), dtype=np.uint8)
else:
mask = np.ascontiguousarray(mask)
if image is out:
raise NotImplementedError("Cannot perform rank operation in place.")
if out is None:
out = np.zeros((rows, cols), dtype=np.uint16)
else:
out = np.ascontiguousarray(out)
mask = np.ascontiguousarray(mask)
# define pointers to the data
cdef np.uint16_t * out_data = <np.uint16_t * >out.data
cdef np.uint16_t * image_data = <np.uint16_t * >image.data
cdef np.uint8_t * mask_data = <np.uint8_t * >mask.data
cdef np.uint16_t * out_data = <np.uint16_t*>out.data
cdef np.uint16_t * image_data = <np.uint16_t*>image.data
cdef np.uint8_t * mask_data = <np.uint8_t*>mask.data
# define local variable types
cdef Py_ssize_t r, c, rr, cc, s, value, local_max, i, even_row
cdef float pop # number of pixels actually inside the neighborhood (float)
# number of pixels actually inside the neighborhood (float)
cdef float pop
# allocate memory with malloc
cdef Py_ssize_t max_se = srows * scols
@@ -108,24 +83,22 @@ cdef inline _core16(
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 = <Py_ssize_t * >malloc(maxbin * sizeof(Py_ssize_t))
cdef Py_ssize_t * histo = <Py_ssize_t*>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 = <Py_ssize_t * >malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_e_c = <Py_ssize_t * >malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_w_r = <Py_ssize_t * >malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_w_c = <Py_ssize_t * >malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_n_r = <Py_ssize_t * >malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_n_c = <Py_ssize_t * >malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_s_r = <Py_ssize_t * >malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_s_c = <Py_ssize_t * >malloc(max_se * 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 = <Py_ssize_t*>malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_e_c = <Py_ssize_t*>malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_w_r = <Py_ssize_t*>malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_w_c = <Py_ssize_t*>malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_n_r = <Py_ssize_t*>malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_n_c = <Py_ssize_t*>malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_s_r = <Py_ssize_t*>malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_s_c = <Py_ssize_t*>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))))
t_e = np.diff(t, axis=1) == -1
@@ -171,7 +144,7 @@ cdef inline _core16(
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_data[rr * cols + cc])
r = 0
c = 0
@@ -189,13 +162,13 @@ cdef inline _core16(
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_data[rr * cols + 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_data[rr * cols + cc])
# kernel -------------------------------------------
out_data[r * cols + c] = kernel(
@@ -212,13 +185,13 @@ cdef inline _core16(
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_data[rr * cols + 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_data[rr * cols + cc])
# kernel -------------------------------------------
out_data[r * cols + c] = kernel(histo, pop, image_data[r * cols + c],
@@ -231,13 +204,13 @@ cdef inline _core16(
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_data[rr * cols + 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_data[rr * cols + cc])
# kernel -------------------------------------------
out_data[r * cols + c] = kernel(
@@ -254,13 +227,13 @@ cdef inline _core16(
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_data[rr * cols + 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_data[rr * cols + cc])
# kernel -------------------------------------------
out_data[r * cols + c] = kernel(histo, pop, image_data[r * cols + c],
@@ -279,5 +252,3 @@ cdef inline _core16(
free(se_s_c)
free(histo)
return out
+16 -11
View File
@@ -1,17 +1,22 @@
cimport numpy as np
# generic cdef functions
cdef np.uint8_t uint8_max(np.uint8_t a, np.uint8_t b)
cdef np.uint8_t uint8_min(np.uint8_t a, np.uint8_t b)
#---------------------------------------------------------------------------
# 8 bit core kernel receives extra information about data inferior and superior percentiles
#---------------------------------------------------------------------------
cdef _core8(
np.uint8_t kernel(Py_ssize_t *, float, np.uint8_t, float, float, Py_ssize_t, Py_ssize_t),
np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask,
np.ndarray[np.uint8_t, ndim=2] out,
char shift_x, char shift_y, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1)
cdef np.uint8_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols,
Py_ssize_t r, Py_ssize_t c,
np.uint8_t * mask)
# 8 bit core kernel receives extra information about data inferior and superior
# percentiles
cdef void _core8(np.uint8_t kernel(Py_ssize_t *, float, np.uint8_t, float,
float, Py_ssize_t, Py_ssize_t),
np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask,
np.ndarray[np.uint8_t, ndim=2] out,
char shift_x, char shift_y, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1) except *
+70 -88
View File
@@ -7,30 +7,31 @@ import numpy as np
cimport numpy as np
from libc.stdlib cimport malloc, free
# generic cdef functions
cdef inline np.uint8_t uint8_max(np.uint8_t a, np.uint8_t b):
return a if a >= b else b
cdef inline np.uint8_t uint8_min(np.uint8_t a, np.uint8_t b):
return a if a <= b else b
#---------------------------------------------------------------------------
# 8 bit core kernel
#---------------------------------------------------------------------------
cdef inline void histogram_increment(Py_ssize_t * histo, float * pop, np.uint8_t value):
cdef inline void histogram_increment(Py_ssize_t * histo, float * pop,
np.uint8_t value):
histo[value] += 1
pop[0] += 1.
pop[0] += 1
cdef inline void histogram_decrement(Py_ssize_t * histo, float * pop, np.uint8_t value):
cdef inline void histogram_decrement(Py_ssize_t * histo, float * pop,
np.uint8_t value):
histo[value] -= 1
pop[0] -= 1.
pop[0] -= 1
cdef inline np.uint8_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols, Py_ssize_t r, Py_ssize_t c, np.uint8_t * mask):
""" returns 1 if given(r,c) coordinate are within the image frame ([0-rows],[0-cols]) and
inside the given mask
returns 0 otherwise
"""
cdef inline np.uint8_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols,
Py_ssize_t r, Py_ssize_t c,
np.uint8_t * 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
else:
@@ -39,16 +40,17 @@ cdef inline np.uint8_t is_in_mask(Py_ssize_t rows, Py_ssize_t cols, Py_ssize_t r
else:
return 0
cdef inline _core8(
np.uint8_t kernel(Py_ssize_t * , float, np.uint8_t, float, float, Py_ssize_t, Py_ssize_t),
np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask,
np.ndarray[np.uint8_t, ndim=2] out,
char shift_x, char shift_y, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1):
""" Main loop, this function computes the histogram for each image point
- data is uint8
- result is uint8 casted
cdef void _core8(np.uint8_t kernel(Py_ssize_t *, float, np.uint8_t, float,
float, Py_ssize_t, Py_ssize_t),
np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask,
np.ndarray[np.uint8_t, ndim=2] 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
use kernel function return value for output image.
"""
cdef Py_ssize_t rows = image.shape[0]
@@ -65,28 +67,11 @@ cdef inline _core8(
assert centre_r < srows
assert centre_c < scols
image = np.ascontiguousarray(image)
if mask is None:
mask = np.ones((rows, cols), dtype=np.uint8)
else:
mask = np.ascontiguousarray(mask)
if image is out:
raise NotImplementedError("Cannot perform rank operation in place.")
if out is None:
out = np.zeros((rows, cols), dtype=np.uint8)
else:
out = np.ascontiguousarray(out)
mask = np.ascontiguousarray(mask)
# define pointers to the data
cdef np.uint8_t * out_data = <np.uint8_t * >out.data
cdef np.uint8_t * image_data = <np.uint8_t * >image.data
cdef np.uint8_t * mask_data = <np.uint8_t * >mask.data
cdef np.uint8_t * out_data = <np.uint8_t*>out.data
cdef np.uint8_t * image_data = <np.uint8_t*>image.data
cdef np.uint8_t * mask_data = <np.uint8_t*>mask.data
# define local variable types
cdef Py_ssize_t r, c, rr, cc, s, value, local_max, i, even_row
@@ -101,24 +86,22 @@ cdef inline _core8(
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 = <Py_ssize_t * >malloc(256 * sizeof(Py_ssize_t))
cdef Py_ssize_t * histo = <Py_ssize_t*>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 = <Py_ssize_t * >malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_e_c = <Py_ssize_t * >malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_w_r = <Py_ssize_t * >malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_w_c = <Py_ssize_t * >malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_n_r = <Py_ssize_t * >malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_n_c = <Py_ssize_t * >malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_s_r = <Py_ssize_t * >malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_s_c = <Py_ssize_t * >malloc(max_se * 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 = <Py_ssize_t*>malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_e_c = <Py_ssize_t*>malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_w_r = <Py_ssize_t*>malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_w_c = <Py_ssize_t*>malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_n_r = <Py_ssize_t*>malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_n_c = <Py_ssize_t*>malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_s_r = <Py_ssize_t*>malloc(max_se * sizeof(Py_ssize_t))
cdef Py_ssize_t * se_s_c = <Py_ssize_t*>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))))
t_e = np.diff(t, axis=1) == -1
@@ -152,7 +135,8 @@ cdef inline _core8(
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)
# initial population and histogram (kernel is centered on the first row and
# column)
for i in range(256):
histo[i] = 0
@@ -164,14 +148,14 @@ cdef inline _core8(
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_data[rr * cols + cc])
r = 0
c = 0
# kernel --------------------------------------------------------------------
out_data[r * cols + c] = kernel(histo, pop, image_data[r * cols +
c], p0, p1, s0, s1)
# kernel --------------------------------------------------------------------
# kernel -------------------------------------------------------------------
out_data[r * cols + c] = kernel(histo, pop, image_data[r * cols + c],
p0, p1, s0, s1)
# kernel -------------------------------------------------------------------
# main loop
r = 0
@@ -182,18 +166,18 @@ cdef inline _core8(
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_data[rr * cols + 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_data[rr * cols + cc])
# kernel --------------------------------------------------------------------
out_data[r * cols + c] = kernel(
histo, pop, image_data[r * cols + c], p0, p1, s0, s1)
# kernel --------------------------------------------------------------------
# kernel -----------------------------------------------------------
out_data[r * cols + c] = \
kernel(histo, pop, image_data[r * cols + c], p0, p1, s0, s1)
# kernel -----------------------------------------------------------
r += 1 # pass to the next row
if r >= rows:
@@ -204,18 +188,18 @@ cdef inline _core8(
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_data[rr * cols + 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_data[rr * cols + cc])
# kernel --------------------------------------------------------------------
out_data[r * cols + c] = kernel(histo, pop, image_data[r *
cols + c], p0, p1, s0, s1)
# kernel --------------------------------------------------------------------
# kernel ---------------------------------------------------------------
out_data[r * cols + c] = kernel(histo, pop, image_data[r * cols + c],
p0, p1, s0, s1)
# kernel ---------------------------------------------------------------
# ---> east to west
for c in range(cols - 2, -1, -1):
@@ -223,18 +207,18 @@ cdef inline _core8(
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_data[rr * cols + 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_data[rr * cols + cc])
# kernel --------------------------------------------------------------------
# kernel -----------------------------------------------------------
out_data[r * cols + c] = kernel(
histo, pop, image_data[r * cols + c], p0, p1, s0, s1)
# kernel --------------------------------------------------------------------
# kernel -----------------------------------------------------------
r += 1 # pass to the next row
if r >= rows:
@@ -245,18 +229,18 @@ cdef inline _core8(
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_data[rr * cols + 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_data[rr * cols + cc])
# kernel --------------------------------------------------------------------
out_data[r * cols + c] = kernel(histo, pop, image_data[r *
cols + c], p0, p1, s0, s1)
# kernel --------------------------------------------------------------------
# kernel ---------------------------------------------------------------
out_data[r * cols + c] = kernel(histo, pop, image_data[r * cols + c],
p0, p1, s0, s1)
# kernel ---------------------------------------------------------------
# release memory allocated by malloc
@@ -270,5 +254,3 @@ cdef inline _core8(
free(se_s_c)
free(histo)
return out
+153 -104
View File
@@ -6,18 +6,19 @@
import numpy as np
cimport numpy as np
from libc.math cimport log2
# import main loop
from skimage.filter.rank._core16 cimport _core16
# -----------------------------------------------------------------
# kernels uint16 take extra parameter for defining the bitdepth
# -----------------------------------------------------------------
cdef inline np.uint16_t kernel_autolevel(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_autolevel(Py_ssize_t * histo, float pop,
np.uint16_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:
@@ -31,27 +32,30 @@ cdef inline np.uint16_t kernel_autolevel(
break
delta = imax - imin
if delta > 0:
return < np.uint16_t > (1. * (maxbin - 1) * (g - imin) / delta)
return <np.uint16_t>(1. * (maxbin - 1) * (g - imin) / delta)
else:
return < np.uint16_t > (imax - imin)
return <np.uint16_t>(imax - imin)
cdef inline np.uint16_t kernel_bottomhat(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_bottomhat(Py_ssize_t * histo, float pop,
np.uint16_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
for i in range(maxbin):
if histo[i]:
break
return < np.uint16_t > (g - i)
return <np.uint16_t>(g - i)
cdef inline np.uint16_t kernel_equalize(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_equalize(Py_ssize_t * histo, float pop,
np.uint16_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.
@@ -61,14 +65,16 @@ cdef inline np.uint16_t kernel_equalize(
if i >= g:
break
return < np.uint16_t > (((maxbin - 1) * sum) / pop)
return <np.uint16_t>(((maxbin - 1) * sum) / pop)
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_gradient(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_gradient(Py_ssize_t * histo, float pop,
np.uint16_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:
@@ -80,55 +86,66 @@ cdef inline np.uint16_t kernel_gradient(
if histo[i]:
imin = i
break
return < np.uint16_t > (imax - imin)
return <np.uint16_t>(imax - imin)
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_maximum(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_maximum(Py_ssize_t * histo, float pop,
np.uint16_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 < np.uint16_t > (i)
return <np.uint16_t>(i)
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_mean(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_mean(Py_ssize_t * histo, float pop,
np.uint16_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 < np.uint16_t > (mean / pop)
return <np.uint16_t>(mean / pop)
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_meansubstraction(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_meansubstraction(Py_ssize_t * histo,
float pop,
np.uint16_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 < np.uint16_t > ((g - mean / pop) / 2. + (midbin - 1))
return <np.uint16_t>((g - mean / pop) / 2. + (midbin - 1))
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_median(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_median(Py_ssize_t * histo, float pop,
np.uint16_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
@@ -137,27 +154,31 @@ cdef inline np.uint16_t kernel_median(
if histo[i]:
sum -= histo[i]
if sum < 0:
return < np.uint16_t > (i)
return <np.uint16_t>(i)
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_minimum(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_minimum(Py_ssize_t * histo, float pop,
np.uint16_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 < np.uint16_t > (i)
return <np.uint16_t>(i)
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_modal(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_modal(Py_ssize_t * histo, float pop,
np.uint16_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:
@@ -165,14 +186,19 @@ cdef inline np.uint16_t kernel_modal(
if histo[i] > hmax:
hmax = histo[i]
imax = i
return < np.uint16_t > (imax)
return <np.uint16_t>(imax)
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_morph_contr_enh(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_morph_contr_enh(Py_ssize_t * histo,
float pop,
np.uint16_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:
@@ -185,49 +211,56 @@ cdef inline np.uint16_t kernel_morph_contr_enh(
imin = i
break
if imax - g < g - imin:
return < np.uint16_t > (imax)
return <np.uint16_t>(imax)
else:
return < np.uint16_t > (imin)
return <np.uint16_t>(imin)
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_pop(
Py_ssize_t * histo, float pop, np.uint16_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 < np.uint16_t > (pop)
cdef inline np.uint16_t kernel_threshold(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_pop(Py_ssize_t * histo, float pop,
np.uint16_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 <np.uint16_t>(pop)
cdef inline np.uint16_t kernel_threshold(Py_ssize_t * histo, float pop,
np.uint16_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 < np.uint16_t > (g > (mean / pop))
return <np.uint16_t>(g > (mean / pop))
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_tophat(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_tophat(Py_ssize_t * histo, float pop,
np.uint16_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
for i in range(maxbin - 1, -1, -1):
if histo[i]:
break
return < np.uint16_t > (i - g)
return <np.uint16_t>(i - g)
cdef inline np.uint16_t kernel_entropy(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_entropy(Py_ssize_t * histo, float pop,
np.uint16_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
@@ -238,7 +271,8 @@ cdef inline np.uint16_t kernel_entropy(
if p>0:
e -= p*log2(p)
return < np.uint16_t > e*1000
return <np.uint16_t>e*1000
# -----------------------------------------------------------------
# python wrappers
@@ -250,7 +284,8 @@ def autolevel(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
return _core16(kernel_autolevel, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_autolevel, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def bottomhat(np.ndarray[np.uint16_t, ndim=2] image,
@@ -258,7 +293,8 @@ def bottomhat(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
return _core16(kernel_bottomhat, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_bottomhat, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def equalize(np.ndarray[np.uint16_t, ndim=2] image,
@@ -266,7 +302,8 @@ def equalize(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
return _core16(kernel_equalize, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_equalize, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def gradient(np.ndarray[np.uint16_t, ndim=2] image,
@@ -274,7 +311,8 @@ def gradient(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
return _core16(kernel_gradient, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_gradient, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def maximum(np.ndarray[np.uint16_t, ndim=2] image,
@@ -282,7 +320,8 @@ def maximum(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
return _core16(kernel_maximum, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_maximum, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def mean(np.ndarray[np.uint16_t, ndim=2] image,
@@ -290,7 +329,8 @@ def mean(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
return _core16(kernel_mean, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_mean, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def meansubstraction(np.ndarray[np.uint16_t, ndim=2] image,
@@ -298,7 +338,8 @@ def meansubstraction(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
return _core16(kernel_meansubstraction, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_meansubstraction, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def median(np.ndarray[np.uint16_t, ndim=2] image,
@@ -306,7 +347,8 @@ def median(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
return _core16(kernel_median, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_median, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def minimum(np.ndarray[np.uint16_t, ndim=2] image,
@@ -314,7 +356,8 @@ def minimum(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
return _core16(kernel_minimum, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_minimum, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def morph_contr_enh(np.ndarray[np.uint16_t, ndim=2] image,
@@ -322,7 +365,8 @@ def morph_contr_enh(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
return _core16(kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def modal(np.ndarray[np.uint16_t, ndim=2] image,
@@ -330,7 +374,8 @@ def modal(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
return _core16(kernel_modal, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_modal, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def pop(np.ndarray[np.uint16_t, ndim=2] image,
@@ -338,7 +383,8 @@ def pop(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
return _core16(kernel_pop, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_pop, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def threshold(np.ndarray[np.uint16_t, ndim=2] image,
@@ -346,7 +392,8 @@ def threshold(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
return _core16(kernel_threshold, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_threshold, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def tophat(np.ndarray[np.uint16_t, ndim=2] image,
@@ -354,11 +401,13 @@ def tophat(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
return _core16(kernel_tophat, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_tophat, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def entropy(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, Py_ssize_t bitdepth=8):
return _core16(kernel_entropy, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_entropy, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
+24 -16
View File
@@ -5,18 +5,19 @@
import numpy as np
cimport numpy as np
# import main loop
from skimage.filter.rank._core16 cimport _core16
# -----------------------------------------------------------------
# kernels uint16 take extra parameter for defining the bitdepth
# -----------------------------------------------------------------
cdef inline np.uint16_t kernel_mean(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_mean(Py_ssize_t * histo, float pop,
np.uint16_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.
@@ -27,16 +28,18 @@ cdef inline np.uint16_t kernel_mean(
bilat_pop += histo[i]
mean += histo[i] * i
if bilat_pop:
return < np.uint16_t > (mean / bilat_pop)
return <np.uint16_t>(mean / bilat_pop)
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_pop(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_pop(Py_ssize_t * histo, float pop,
np.uint16_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
@@ -44,14 +47,16 @@ cdef inline np.uint16_t kernel_pop(
for i in range(maxbin):
if (g > (i - s0)) and (g < (i + s1)):
bilat_pop += histo[i]
return < np.uint16_t > (bilat_pop)
return <np.uint16_t>(bilat_pop)
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
# -----------------------------------------------------------------
# python wrappers
# -----------------------------------------------------------------
def mean(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
@@ -59,7 +64,8 @@ def mean(np.ndarray[np.uint16_t, ndim=2] image,
char shift_x=0, char shift_y=0, int bitdepth=8, int s0=1, int s1=1):
"""average gray level (clipped on uint8)
"""
return _core16(kernel_mean, image, selem, mask, out, shift_x, shift_y, bitdepth, 0., 0., s0, s1)
_core16(kernel_mean, image, selem, mask, out, shift_x, shift_y,
bitdepth, 0., 0., s0, s1)
def pop(np.ndarray[np.uint16_t, ndim=2] image,
@@ -67,6 +73,8 @@ def pop(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] 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
"""returns the number of actual pixels of the structuring element inside
the mask
"""
return _core16(kernel_pop, image, selem, mask, out, shift_x, shift_y, bitdepth, .0, .0, s0, s1)
_core16(kernel_pop, image, selem, mask, out, shift_x, shift_y,
bitdepth, .0, .0, s0, s1)
+109 -80
View File
@@ -5,17 +5,19 @@
import numpy as np
cimport numpy as np
# import main loop
from skimage.filter.rank._core16 cimport _core16, int_min, int_max
# -----------------------------------------------------------------
# kernels uint16 (SOFT version using percentiles)
# -----------------------------------------------------------------
cdef inline np.uint16_t kernel_autolevel(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_autolevel(Py_ssize_t * histo, float pop,
np.uint16_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
@@ -36,16 +38,19 @@ cdef inline np.uint16_t kernel_autolevel(
delta = imax - imin
if delta > 0:
return < np.uint16_t > (1.0 * (maxbin - 1) * (int_min(int_max(imin, g), imax) - imin) / delta)
return <np.uint16_t>(1.0 * (maxbin - 1) \
* (int_min(int_max(imin, g), imax) - imin) / delta)
else:
return < np.uint16_t > (imax - imin)
return <np.uint16_t>(imax - imin)
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_gradient(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_gradient(Py_ssize_t * histo, float pop,
np.uint16_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
@@ -64,14 +69,16 @@ cdef inline np.uint16_t kernel_gradient(
imax = i
break
return < np.uint16_t > (imax - imin)
return <np.uint16_t>(imax - imin)
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_mean(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_mean(Py_ssize_t * histo, float pop,
np.uint16_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
@@ -86,15 +93,21 @@ cdef inline np.uint16_t kernel_mean(
mean += histo[i] * i
if n > 0:
return < np.uint16_t > (1.0 * mean / n)
return <np.uint16_t>(1.0 * mean / n)
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_mean_substraction(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_mean_substraction(Py_ssize_t * histo,
float pop,
np.uint16_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
@@ -108,15 +121,21 @@ cdef inline np.uint16_t kernel_mean_substraction(
n += histo[i]
mean += histo[i] * i
if n > 0:
return < np.uint16_t > ((g - (mean / n)) * .5 + midbin)
return <np.uint16_t>((g - (mean / n)) * .5 + midbin)
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_morph_contr_enh(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_morph_contr_enh(Py_ssize_t * histo,
float pop,
np.uint16_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
@@ -135,19 +154,22 @@ cdef inline np.uint16_t kernel_morph_contr_enh(
imax = i
break
if g > imax:
return < np.uint16_t > imax
return <np.uint16_t>imax
if g < imin:
return < np.uint16_t > imin
return <np.uint16_t>imin
if imax - g < g - imin:
return < np.uint16_t > imax
return <np.uint16_t>imax
else:
return < np.uint16_t > imin
return <np.uint16_t>imin
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_percentile(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_percentile(Py_ssize_t * histo, float pop,
np.uint16_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.
@@ -158,13 +180,16 @@ cdef inline np.uint16_t kernel_percentile(
if sum >= p0 * pop:
break
return < np.uint16_t > (i)
return <np.uint16_t>(i)
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_pop(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_pop(Py_ssize_t * histo, float pop,
np.uint16_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
@@ -175,13 +200,16 @@ cdef inline np.uint16_t kernel_pop(
sum += histo[i]
if (sum >= p0 * pop) and (sum <= p1 * pop):
n += histo[i]
return < np.uint16_t > (n)
return <np.uint16_t>(n)
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
cdef inline np.uint16_t kernel_threshold(
Py_ssize_t * histo, float pop, np.uint16_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 inline np.uint16_t kernel_threshold(Py_ssize_t * histo, float pop,
np.uint16_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.
@@ -192,9 +220,10 @@ cdef inline np.uint16_t kernel_threshold(
if sum >= p0 * pop:
break
return < np.uint16_t > ((maxbin - 1) * (g >= i))
return <np.uint16_t>((maxbin - 1) * (g >= i))
else:
return < np.uint16_t > (0)
return <np.uint16_t>(0)
# -----------------------------------------------------------------
# python wrappers
@@ -205,93 +234,93 @@ def autolevel(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0., float p1=0.):
char shift_x=0, char shift_y=0, int bitdepth=8,
float p0=0., float p1=0.):
"""bottom hat
"""
return _core16(
kernel_autolevel, image, selem, mask, out, shift_x, shift_y, bitdepth, p0, p1,
< Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_autolevel, image, selem, mask, out, shift_x, shift_y,
bitdepth, p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def gradient(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0., float p1=0.):
char shift_x=0, char shift_y=0, int bitdepth=8,
float p0=0., float p1=0.):
"""return p0,p1 percentile gradient
"""
return _core16(
kernel_gradient, image, selem, mask, out, shift_x, shift_y, bitdepth, p0, p1, < Py_ssize_t > 0,
< Py_ssize_t > 0)
_core16(kernel_gradient, image, selem, mask, out, shift_x, shift_y,
bitdepth, p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def mean(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0., float p1=0.):
char shift_x=0, char shift_y=0, int bitdepth=8,
float p0=0., float p1=0.):
"""return mean between [p0 and p1] percentiles
"""
return _core16(
kernel_mean, image, selem, mask, out, shift_x, shift_y, bitdepth, p0, p1, < Py_ssize_t > 0,
< Py_ssize_t > 0)
_core16(kernel_mean, image, selem, mask, out, shift_x, shift_y,
bitdepth, p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def mean_substraction(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0., float p1=0.):
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
"""
return _core16(
kernel_mean_substraction, image, selem, mask, out, shift_x, shift_y, bitdepth, p0, p1,
< Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_mean_substraction, image, selem, mask, out, shift_x, shift_y,
bitdepth, p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def morph_contr_enh(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0., float p1=0.):
char shift_x=0, char shift_y=0, int bitdepth=8,
float p0=0., float p1=0.):
"""reforce contrast using percentiles
"""
return _core16(
kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y, bitdepth, p0, p1,
< Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y,
bitdepth, p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def percentile(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0., float p1=0.):
char shift_x=0, char shift_y=0, int bitdepth=8,
float p0=0., float p1=0.):
"""return p0 percentile
"""
return _core16(
kernel_percentile, image, selem, mask, out, shift_x, shift_y, bitdepth, p0, p1,
< Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_percentile, image, selem, mask, out, shift_x, shift_y,
bitdepth, p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def pop(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0., float p1=0.):
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]
"""
return _core16(
kernel_pop, image, selem, mask, out, shift_x, shift_y, bitdepth, p0, p1,
< Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_pop, image, selem, mask, out, shift_x, shift_y,
bitdepth, p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def threshold(np.ndarray[np.uint16_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint16_t, ndim=2] out=None,
char shift_x=0, char shift_y=0, int bitdepth=8, float p0=0., float p1=0.):
char shift_x=0, char shift_y=0, int bitdepth=8,
float p0=0., float p1=0.):
"""return (maxbin-1) if g > percentile p0
"""
return _core16(
kernel_threshold, image, selem, mask, out, shift_x, shift_y, bitdepth, p0, p1,
< Py_ssize_t > 0, < Py_ssize_t > 0)
_core16(kernel_threshold, image, selem, mask, out, shift_x, shift_y,
bitdepth, p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
+150 -132
View File
@@ -5,19 +5,18 @@
import numpy as np
cimport numpy as np
from libc.math cimport log2
# import main loop
from skimage.filter.rank._core8 cimport _core8
# -----------------------------------------------------------------
# kernels uint8
# -----------------------------------------------------------------
cdef inline np.uint8_t kernel_autolevel(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline np.uint8_t kernel_autolevel(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i, imin, imax, delta
@@ -32,15 +31,16 @@ cdef inline np.uint8_t kernel_autolevel(
break
delta = imax - imin
if delta > 0:
return < np.uint8_t > (255. * (g - imin) / delta)
return <np.uint8_t>(255. * (g - imin) / delta)
else:
return < np.uint8_t > (imax - imin)
return <np.uint8_t>(imax - imin)
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_bottomhat(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline np.uint8_t kernel_bottomhat(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
@@ -48,12 +48,12 @@ cdef inline np.uint8_t kernel_bottomhat(
if histo[i]:
break
return < np.uint8_t > (g - i)
return <np.uint8_t>(g - i)
cdef inline np.uint8_t kernel_equalize(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline np.uint8_t kernel_equalize(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float sum = 0.
@@ -64,13 +64,14 @@ cdef inline np.uint8_t kernel_equalize(
if i >= g:
break
return < np.uint8_t > ((255 * sum) / pop)
return <np.uint8_t>((255 * sum) / pop)
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_gradient(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
cdef inline np.uint8_t kernel_gradient(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i, imin, imax
@@ -83,26 +84,28 @@ cdef inline np.uint8_t kernel_gradient(
if histo[i]:
imin = i
break
return < np.uint8_t > (imax - imin)
return <np.uint8_t>(imax - imin)
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_maximum(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
cdef inline np.uint8_t kernel_maximum(Py_ssize_t * histo, float pop,
np.uint8_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 < np.uint8_t > (i)
return <np.uint8_t>(i)
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_mean(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
cdef inline np.uint8_t kernel_mean(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float mean = 0.
@@ -110,13 +113,14 @@ cdef inline np.uint8_t kernel_mean(
if pop:
for i in range(256):
mean += histo[i] * i
return < np.uint8_t > (mean / pop)
return <np.uint8_t>(mean / pop)
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_meansubstraction(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline np.uint8_t kernel_meansubstraction(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float mean = 0.
@@ -124,13 +128,14 @@ cdef inline np.uint8_t kernel_meansubstraction(
if pop:
for i in range(256):
mean += histo[i] * i
return < np.uint8_t > ((g - mean / pop) / 2. + 127)
return <np.uint8_t>((g - mean / pop) / 2. + 127)
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_median(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
cdef inline np.uint8_t kernel_median(Py_ssize_t * histo, float pop,
np.uint8_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
@@ -140,25 +145,28 @@ cdef inline np.uint8_t kernel_median(
if histo[i]:
sum -= histo[i]
if sum < 0:
return < np.uint8_t > (i)
return <np.uint8_t>(i)
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_minimum(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
cdef inline np.uint8_t kernel_minimum(Py_ssize_t * histo, float pop,
np.uint8_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 < np.uint8_t > (i)
return <np.uint8_t>(i)
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_modal(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0, Py_ssize_t s1):
cdef inline np.uint8_t kernel_modal(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t hmax = 0, imax = 0
@@ -167,13 +175,14 @@ cdef inline np.uint8_t kernel_modal(
if histo[i] > hmax:
hmax = histo[i]
imax = i
return < np.uint8_t > (imax)
return <np.uint8_t>(imax)
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_morph_contr_enh(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline np.uint8_t kernel_morph_contr_enh(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i, imin, imax
@@ -187,21 +196,23 @@ cdef inline np.uint8_t kernel_morph_contr_enh(
imin = i
break
if imax - g < g - imin:
return < np.uint8_t > (imax)
return <np.uint8_t>(imax)
else:
return < np.uint8_t > (imin)
return <np.uint8_t>(imin)
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_pop(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
return < np.uint8_t > (pop)
cdef inline np.uint8_t kernel_pop(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline np.uint8_t kernel_threshold(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
return <np.uint8_t>(pop)
cdef inline np.uint8_t kernel_threshold(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float mean = 0.
@@ -209,13 +220,14 @@ cdef inline np.uint8_t kernel_threshold(
if pop:
for i in range(256):
mean += histo[i] * i
return < np.uint8_t > (g > (mean / pop))
return <np.uint8_t>(g > (mean / pop))
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_tophat(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
cdef inline np.uint8_t kernel_tophat(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
@@ -223,64 +235,64 @@ cdef inline np.uint8_t kernel_tophat(
if histo[i]:
break
return < np.uint8_t > (i - g)
return <np.uint8_t>(i - g)
cdef inline np.uint8_t kernel_noise_filter(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
cdef inline np.uint8_t kernel_noise_filter(Py_ssize_t * histo, float pop,
np.uint8_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 < np.uint8_t > 0
if histo[g] > 0:
return <np.uint8_t>0
for i in range(g, -1, -1):
if histo[i]:
break
min_i = g-i
min_i = g - i
for i in range(g, 256):
if histo[i]:
break
if i-g < min_i:
return < np.uint8_t > (i-g)
if i - g < min_i:
return <np.uint8_t>(i - g)
else:
return < np.uint8_t > min_i
return <np.uint8_t>min_i
cdef inline np.uint8_t kernel_entropy(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
cdef inline np.uint8_t kernel_entropy(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef Py_ssize_t i
cdef float e,p
e = 0.
for i in range(256):
p = histo[i]/pop
if p>0:
e -= p*log2(p)
p = histo[i] / pop
if p > 0:
e -= p * log2(p)
return < np.uint8_t > e*10
return <np.uint8_t>e*10
cdef inline np.uint8_t kernel_otsu(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
cdef inline np.uint8_t kernel_otsu(Py_ssize_t * histo, float pop, np.uint8_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 < np.uint8_t > (0)
return <np.uint8_t>(0)
# maximizing the between class variance
max_i = 0
@@ -289,21 +301,24 @@ cdef inline np.uint8_t kernel_otsu(
max_sigma_b = 0.
for i in range(1,256):
P = histo[i]/pop
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:
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
if g>max_i:
return < np.uint8_t > 255
if g > max_i:
return <np.uint8_t>255
else:
return < np.uint8_t > 0
return <np.uint8_t>0
# -----------------------------------------------------------------
# python wrappers
# used only internally
@@ -315,9 +330,8 @@ def autolevel(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(
kernel_autolevel, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0,
< Py_ssize_t > 0)
_core8(kernel_autolevel, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def bottomhat(np.ndarray[np.uint8_t, ndim=2] image,
@@ -325,9 +339,8 @@ def bottomhat(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(
kernel_bottomhat, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0,
< Py_ssize_t > 0)
_core8(kernel_bottomhat, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def equalize(np.ndarray[np.uint8_t, ndim=2] image,
@@ -335,9 +348,8 @@ def equalize(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(
kernel_equalize, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0,
< Py_ssize_t > 0)
_core8(kernel_equalize, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def gradient(np.ndarray[np.uint8_t, ndim=2] image,
@@ -345,9 +357,8 @@ def gradient(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(
kernel_gradient, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0,
< Py_ssize_t > 0)
_core8(kernel_gradient, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def maximum(np.ndarray[np.uint8_t, ndim=2] image,
@@ -355,7 +366,8 @@ def maximum(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(kernel_maximum, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core8(kernel_maximum, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def mean(np.ndarray[np.uint8_t, ndim=2] image,
@@ -363,7 +375,8 @@ def mean(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(kernel_mean, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core8(kernel_mean, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def meansubstraction(np.ndarray[np.uint8_t, ndim=2] image,
@@ -371,9 +384,8 @@ def meansubstraction(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(
kernel_meansubstraction, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0,
< Py_ssize_t > 0)
_core8(kernel_meansubstraction, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def median(np.ndarray[np.uint8_t, ndim=2] image,
@@ -381,7 +393,8 @@ def median(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(kernel_median, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core8(kernel_median, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def minimum(np.ndarray[np.uint8_t, ndim=2] image,
@@ -389,7 +402,8 @@ def minimum(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(kernel_minimum, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core8(kernel_minimum, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def morph_contr_enh(np.ndarray[np.uint8_t, ndim=2] image,
@@ -397,9 +411,8 @@ def morph_contr_enh(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(
kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0,
< Py_ssize_t > 0)
_core8(kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def modal(np.ndarray[np.uint8_t, ndim=2] image,
@@ -407,7 +420,8 @@ def modal(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(kernel_modal, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core8(kernel_modal, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def pop(np.ndarray[np.uint8_t, ndim=2] image,
@@ -415,7 +429,8 @@ def pop(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(kernel_pop, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core8(kernel_pop, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def threshold(np.ndarray[np.uint8_t, ndim=2] image,
@@ -423,9 +438,8 @@ def threshold(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(
kernel_threshold, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0,
< Py_ssize_t > 0)
_core8(kernel_threshold, image, selem, mask, out, shift_x, shift_y, 0, 0,
<Py_ssize_t>0, <Py_ssize_t>0)
def tophat(np.ndarray[np.uint8_t, ndim=2] image,
@@ -433,7 +447,8 @@ def tophat(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(kernel_tophat, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core8(kernel_tophat, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def noise_filter(np.ndarray[np.uint8_t, ndim=2] image,
@@ -441,18 +456,21 @@ def noise_filter(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(kernel_noise_filter, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core8(kernel_noise_filter, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def entropy(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(kernel_entropy, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core8(kernel_entropy, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
def otsu(np.ndarray[np.uint8_t, ndim=2] image,
np.ndarray[np.uint8_t, ndim=2] selem,
np.ndarray[np.uint8_t, ndim=2] mask=None,
np.ndarray[np.uint8_t, ndim=2] out=None,
char shift_x=0, char shift_y=0):
return _core8(kernel_otsu, image, selem, mask, out, shift_x, shift_y, .0, .0, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core8(kernel_otsu, image, selem, mask, out, shift_x, shift_y,
0, 0, <Py_ssize_t>0, <Py_ssize_t>0)
+74 -68
View File
@@ -5,17 +5,17 @@
import numpy as np
cimport numpy as np
# import main loop
from skimage.filter.rank._core8 cimport _core8, uint8_max, uint8_min
# -----------------------------------------------------------------
# kernels uint8 (SOFT version using percentiles)
# -----------------------------------------------------------------
cdef inline np.uint8_t kernel_autolevel(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
cdef inline np.uint8_t kernel_autolevel(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, imin, imax, sum, delta
if pop:
@@ -37,16 +37,17 @@ cdef inline np.uint8_t kernel_autolevel(
break
delta = imax - imin
if delta > 0:
return < np.uint8_t > (255 * (uint8_min(uint8_max(imin, g), imax) - imin) / delta)
return <np.uint8_t>(255 \
* (uint8_min(uint8_max(imin, g), imax) - imin) / delta)
else:
return < np.uint8_t > (imax - imin)
return <np.uint8_t>(imax - imin)
else:
return < np.uint8_t > (128)
return <np.uint8_t>(128)
cdef inline np.uint8_t kernel_gradient(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
cdef inline np.uint8_t kernel_gradient(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, imin, imax, sum, delta
if pop:
@@ -64,14 +65,14 @@ cdef inline np.uint8_t kernel_gradient(
imax = i
break
return < np.uint8_t > (imax - imin)
return <np.uint8_t>(imax - imin)
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_mean(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
cdef inline np.uint8_t kernel_mean(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, sum, mean, n
if pop:
@@ -84,15 +85,18 @@ cdef inline np.uint8_t kernel_mean(
n += histo[i]
mean += histo[i] * i
if n > 0:
return < np.uint8_t > (1.0 * mean / n)
return <np.uint8_t>(1.0 * mean / n)
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_mean_substraction(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline np.uint8_t kernel_mean_substraction(Py_ssize_t * histo,
float pop,
np.uint8_t g,
float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, sum, mean, n
if pop:
@@ -105,15 +109,17 @@ cdef inline np.uint8_t kernel_mean_substraction(
n += histo[i]
mean += histo[i] * i
if n > 0:
return < np.uint8_t > ((g - (mean / n)) * .5 + 127)
return <np.uint8_t>((g - (mean / n)) * .5 + 127)
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_morph_contr_enh(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline np.uint8_t kernel_morph_contr_enh(Py_ssize_t * histo,
float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, imin, imax, sum, delta
if pop:
@@ -131,19 +137,20 @@ cdef inline np.uint8_t kernel_morph_contr_enh(
imax = i
break
if g > imax:
return < np.uint8_t > imax
return <np.uint8_t>imax
if g < imin:
return < np.uint8_t > imin
return <np.uint8_t>imin
if imax - g < g - imin:
return < np.uint8_t > imax
return <np.uint8_t>imax
else:
return < np.uint8_t > imin
return <np.uint8_t>imin
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_percentile(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline np.uint8_t kernel_percentile(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i
cdef float sum = 0.
@@ -153,13 +160,14 @@ cdef inline np.uint8_t kernel_percentile(
if sum >= p0 * pop:
break
return < np.uint8_t > (i)
return <np.uint8_t>(i)
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_pop(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef inline np.uint8_t kernel_pop(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i, sum, n
if pop:
@@ -169,13 +177,14 @@ cdef inline np.uint8_t kernel_pop(
sum += histo[i]
if (sum >= p0 * pop) and (sum <= p1 * pop):
n += histo[i]
return < np.uint8_t > (n)
return <np.uint8_t>(n)
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
cdef inline np.uint8_t kernel_threshold(
Py_ssize_t * histo, float pop, np.uint8_t g, float p0, float p1, Py_ssize_t s0,
Py_ssize_t s1):
cdef inline np.uint8_t kernel_threshold(Py_ssize_t * histo, float pop,
np.uint8_t g, float p0, float p1,
Py_ssize_t s0, Py_ssize_t s1):
cdef int i
cdef float sum = 0.
@@ -185,9 +194,10 @@ cdef inline np.uint8_t kernel_threshold(
if sum >= p0 * pop:
break
return < np.uint8_t > (255 * (g >= i))
return <np.uint8_t>(255 * (g >= i))
else:
return < np.uint8_t > (0)
return <np.uint8_t>(0)
# -----------------------------------------------------------------
# python wrappers
@@ -201,9 +211,8 @@ def autolevel(np.ndarray[np.uint8_t, ndim=2] image,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""autolevel
"""
return _core8(
kernel_autolevel, image, selem, mask, out, shift_x, shift_y, p0, p1, < Py_ssize_t > 0,
< Py_ssize_t > 0)
_core8(kernel_autolevel, image, selem, mask, out, shift_x, shift_y, p0, p1,
<Py_ssize_t>0, <Py_ssize_t>0)
def gradient(np.ndarray[np.uint8_t, ndim=2] image,
@@ -213,9 +222,8 @@ def gradient(np.ndarray[np.uint8_t, ndim=2] image,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""return p0,p1 percentile gradient
"""
return _core8(
kernel_gradient, image, selem, mask, out, shift_x, shift_y, p0, p1, < Py_ssize_t > 0,
< Py_ssize_t > 0)
_core8(kernel_gradient, image, selem, mask, out, shift_x, shift_y, p0, p1,
<Py_ssize_t>0, <Py_ssize_t>0)
def mean(np.ndarray[np.uint8_t, ndim=2] image,
@@ -225,7 +233,8 @@ def mean(np.ndarray[np.uint8_t, ndim=2] image,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""return mean between [p0 and p1] percentiles
"""
return _core8(kernel_mean, image, selem, mask, out, shift_x, shift_y, p0, p1, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core8(kernel_mean, image, selem, mask, out, shift_x, shift_y, p0, p1,
<Py_ssize_t>0, <Py_ssize_t>0)
def mean_substraction(np.ndarray[np.uint8_t, ndim=2] image,
@@ -235,9 +244,8 @@ def mean_substraction(np.ndarray[np.uint8_t, ndim=2] image,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""return original - mean between [p0 and p1] percentiles *.5 +127
"""
return _core8(
kernel_mean_substraction, image, selem, mask, out, shift_x, shift_y, p0, p1, < Py_ssize_t > 0,
< Py_ssize_t > 0)
_core8(kernel_mean_substraction, image, selem, mask, out, shift_x, shift_y,
p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def morph_contr_enh(np.ndarray[np.uint8_t, ndim=2] image,
@@ -247,9 +255,8 @@ def morph_contr_enh(np.ndarray[np.uint8_t, ndim=2] image,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""reforce contrast using percentiles
"""
return _core8(
kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y, p0, p1, < Py_ssize_t > 0,
< Py_ssize_t > 0)
_core8(kernel_morph_contr_enh, image, selem, mask, out, shift_x, shift_y,
p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def percentile(np.ndarray[np.uint8_t, ndim=2] image,
@@ -259,9 +266,8 @@ def percentile(np.ndarray[np.uint8_t, ndim=2] image,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""return p0 percentile
"""
return _core8(
kernel_percentile, image, selem, mask, out, shift_x, shift_y, p0, p1, < Py_ssize_t > 0,
< Py_ssize_t > 0)
_core8(kernel_percentile, image, selem, mask, out, shift_x, shift_y,
p0, p1, <Py_ssize_t>0, <Py_ssize_t>0)
def pop(np.ndarray[np.uint8_t, ndim=2] image,
@@ -271,7 +277,8 @@ def pop(np.ndarray[np.uint8_t, ndim=2] image,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""return nb of pixels between [p0 and p1]
"""
return _core8(kernel_pop, image, selem, mask, out, shift_x, shift_y, p0, p1, < Py_ssize_t > 0, < Py_ssize_t > 0)
_core8(kernel_pop, image, selem, mask, out, shift_x, shift_y, p0, p1,
<Py_ssize_t>0, <Py_ssize_t>0)
def threshold(np.ndarray[np.uint8_t, ndim=2] image,
@@ -281,6 +288,5 @@ def threshold(np.ndarray[np.uint8_t, ndim=2] image,
char shift_x=0, char shift_y=0, float p0=0., float p1=0.):
"""return 255 if g > percentile p0
"""
return _core8(
kernel_threshold, image, selem, mask, out, shift_x, shift_y, p0, p1, < Py_ssize_t > 0,
< Py_ssize_t > 0)
_core8(kernel_threshold, image, selem, mask, out, shift_x, shift_y, p0, p1,
<Py_ssize_t>0, <Py_ssize_t>0)
+79 -56
View File
@@ -1,31 +1,31 @@
"""bilateral_rank.py - approximate bilateral rankfilter for local (custom kernel) mean
"""Approximate bilateral rankfilter for local (custom kernel) mean.
The local histogram is computed using a sliding window similar to the method described in
The local histogram is computed using a sliding window similar to the method
described in:
Reference: 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.
Reference: 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.
input image can be 8 bit or 16 bit with a value < 4096 (i.e. 12 bit),
8 bit images are casted in 16 bit
the number of histogram bins is determined from the maximum value present in the image
Input image can be 8 bit or 16 bit with a value < 4096 (i.e. 12 bit), 8 bit
images are casted in 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
* an interval [g-s0,g+s1] in gray level around g the processed pixel gray level
The kernel is flat (i.e. each pixel belonging to the neighborhood contributes equally)
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
Result image is 16 bit with respect to the input image.
"""
from skimage import img_as_ubyte
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
@@ -34,52 +34,74 @@ __all__ = ['bilateral_mean', 'bilateral_pop']
def _apply(func8, func16, image, selem, out, mask, shift_x, shift_y, s0, s1):
selem = img_as_ubyte(selem)
if mask is not None:
mask = img_as_ubyte(mask)
if image.dtype == np.uint8:
image = image.astype(np.uint16)
elif image.dtype == np.uint16:
pass
image = np.ascontiguousarray(image)
if mask is None:
mask = np.ones(image.shape, dtype=np.uint8)
else:
raise TypeError("only uint8 and uint16 image supported!")
bitdepth = find_bitdepth(image)
if bitdepth > 11:
raise ValueError("only uint16 <4096 image (12bit) supported!")
return func16(
image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, bitdepth=bitdepth + 1, out=out,
s0=s0, s1=s1)
mask = np.ascontiguousarray(mask)
mask = img_as_ubyte(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 > 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:
raise TypeError("Only uint8 and uint16 image supported.")
return out
def bilateral_mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False, s0=10, s1=10):
def bilateral_mean(image, selem, out=None, mask=None, shift_x=False,
shift_y=False, s0=10, s1=10):
"""Apply a flat kernel bilateral filter.
This is an edge-preserving and noise reducing denoising filter. It averages
pixels based on their spatial closeness and radiometric similarity.
Spatial closeness is measured by considering only the local pixel neighborhood given by a
structuring element (selem).
Spatial closeness is measured by considering only the local pixel
neighborhood given by a structuring element (selem).
Radiometric similarity is defined by the gray level interval [g-s0,g+s1] where g is the current pixel gray level.
Only pixels belonging to the structuring element AND having a gray level inside this interval are averaged.
Return greyscale local bilateral_mean of an image.
Radiometric similarity is defined by the gray level interval [g-s0,g+s1]
where g is the current pixel gray level. Only pixels belonging to the
structuring element AND having a gray level inside this interval are
averaged. Return greyscale local bilateral_mean of an image.
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). If image is uint16, as the
algorithm uses max. 12bit histogram, an exception will be raised if
image has a value > 4095
selem : ndarray
The neighborhood expressed as a 2-D array of 1's and 0's.
out : ndarray
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).
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).
Offset added to the structuring element center point. Shift is bounded
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
-------
@@ -108,32 +130,35 @@ def bilateral_mean(image, selem, out=None, mask=None, shift_x=False, shift_y=Fal
>>> bilat_ima = bilateral_mean(ima, disk(20), s0=10,s1=10)
"""
return _apply(
None, _crank16_bilateral.mean, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y,
s0=s0, s1=s1)
return _apply(None, _crank16_bilateral.mean, image, selem, out=out,
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, 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 level inside the interval [g-s0,g+s1].
def bilateral_pop(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
level inside the interval [g-s0, g+s1].
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). If image is uint16, as the
algorithm uses max. 12bit histogram, an exception will be raised if
image has a value > 4095
selem : ndarray
The neighborhood expressed as a 2-D array of 1's and 0's.
out : ndarray
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).
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).
Offset added to the structuring element center point. Shift is bounded
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
-------
@@ -159,7 +184,5 @@ def bilateral_pop(image, selem, out=None, mask=None, shift_x=False, shift_y=Fals
"""
return _apply(
None, _crank16_bilateral.pop, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y,
s0=s0, s1=s1)
return _apply(None, _crank16_bilateral.pop, image, selem, out=out,
mask=mask, shift_x=shift_x, shift_y=shift_y, s0=s0, s1=s1)
+207 -154
View File
@@ -1,337 +1,390 @@
"""percentile_rank.py - 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] instead of using [min,max]. It means that isolate bright or dark pixels will not produce halos.
"""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]
instead of using [min,max]. It means that isolate bright or dark pixels will not
produce halos.
The local histogram is computed using a sliding window similar to the method described in
The local histogram is computed using a sliding window similar to the method
described in:
Reference: 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.
Reference: 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.
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 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
Result image is 8 or 16 bit with respect to the input image.
"""
from skimage import img_as_ubyte
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
__all__ = ['percentile_autolevel', 'percentile_gradient',
'percentile_mean', 'percentile_mean_substraction',
'percentile_morph_contr_enh', 'percentile', 'percentile_pop', 'percentile_threshold']
'percentile_morph_contr_enh', 'percentile', 'percentile_pop',
'percentile_threshold']
def _apply(func8, func16, image, selem, out, mask, shift_x, shift_y, p0, p1):
selem = img_as_ubyte(selem)
if mask is not None:
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.")
if image.dtype == np.uint8:
return func8(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, out=out, p0=p0, p1=p1)
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 > 11:
raise ValueError("only uint16 <4096 image (12bit) supported!")
return func16(
image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, bitdepth=bitdepth + 1, out=out,
p0=p0, p1=p1)
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:
raise TypeError("only uint8 and uint16 image supported!")
raise TypeError("Only uint8 and uint16 image supported.")
return out
def percentile_autolevel(image, selem, out=None, mask=None, shift_x=False, shift_y=False, p0=.0, p1=1.):
def percentile_autolevel(image, selem, out=None, mask=None, shift_x=False,
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 percentiles [p0,p1] ,are used.
Autolevel is computed on the given structuring element. Only levels between
percentiles [p0, p1] are used.
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). If image is uint16, as the
algorithm uses max. 12bit histogram, an exception will be raised if
image has a value > 4095.
selem : ndarray
The neighborhood expressed as a 2-D array of 1's and 0's.
out : ndarray
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).
p0, p1 : float in [0.,...,1.]
define the [p0,p1] percentile interval to be considered for computing the value.
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).
p0, p1 : float in [0, ..., 1]
Define the [p0, p1] percentile interval to be considered for computing
the value.
Returns
-------
local autolevel : uint8 array or uint16 array depending on input image
local autolevel : uint8 array or uint16
The result of the local autolevel.
"""
return _apply(
_crank8_percentiles.autolevel, _crank16_percentiles.autolevel, image, selem, out=out, mask=mask,
shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1)
return _apply(_crank8_percentiles.autolevel, _crank16_percentiles.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.):
def percentile_gradient(image, selem, out=None, mask=None, shift_x=False,
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 levels between percentiles [p0,p1] ,are used.
percentile_gradient is computed on the given structuring element. Only
levels between percentiles [p0, p1] are used.
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). If image is uint16, as the
algorithm uses max. 12bit histogram, an exception will be raised if
image has a value > 4095.
selem : ndarray
The neighborhood expressed as a 2-D array of 1's and 0's.
out : ndarray
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).
p0, p1 : float in [0.,...,1.]
define the [p0,p1] percentile interval to be considered for computing the value.
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).
p0, p1 : float in [0, ..., 1]
Define the [p0, p1] percentile interval to be considered for computing
the value.
Returns
-------
local percentile_gradient : uint8 array or uint16 array depending on input image
local percentile_gradient : uint8 array or uint16
The result of the local percentile_gradient.
"""
return _apply(
_crank8_percentiles.gradient, _crank16_percentiles.gradient, image, selem, out=out, mask=mask,
shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1)
return _apply(_crank8_percentiles.gradient, _crank16_percentiles.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.):
def percentile_mean(image, selem, out=None, mask=None, shift_x=False,
shift_y=False, p0=.0, p1=1.):
"""Return greyscale local mean of an image.
Mean is computed on the given structuring element. Only levels between percentiles [p0,p1] ,are used.
Mean is computed on the given structuring element. Only levels between
percentiles [p0, p1] are used.
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). If image is uint16, as the
algorithm uses max. 12bit histogram, an exception will be raised if
image has a value > 4095.
selem : ndarray
The neighborhood expressed as a 2-D array of 1's and 0's.
out : ndarray
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).
p0, p1 : float in [0.,...,1.]
define the [p0,p1] percentile interval to be considered for computing the value.
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).
p0, p1 : float in [0, ..., 1]
Define the [p0, p1] percentile interval to be considered for computing
the value.
Returns
-------
local mean : uint8 array or uint16 array depending on input image
local mean : uint8 array or uint16
The result of the local mean.
"""
return _apply(
_crank8_percentiles.mean, _crank16_percentiles.mean, image, selem, out=out, mask=mask,
shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1)
return _apply(_crank8_percentiles.mean, _crank16_percentiles.mean,
image, selem, out=out, mask=mask, shift_x=shift_x,
shift_y=shift_y, p0=p0, p1=p1)
def percentile_mean_substraction(image, selem, out=None, mask=None, shift_x=False, shift_y=False, p0=.0, p1=1.):
def percentile_mean_substraction(image, selem, out=None, mask=None,
shift_x=False, shift_y=False, p0=.0, p1=1.):
"""Return greyscale local mean_substraction of an image.
mean_substraction is computed on the given structuring element. Only levels between percentiles [p0,p1] ,are used.
mean_substraction is computed on the given structuring element. Only levels
between percentiles [p0, p1] are used.
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). If image is uint16, as the
algorithm uses max. 12bit histogram, an exception will be raised if
image has a value > 4095.
selem : ndarray
The neighborhood expressed as a 2-D array of 1's and 0's.
out : ndarray
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).
p0, p1 : float in [0.,...,1.]
define the [p0,p1] percentile interval to be considered for computing the value.
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).
p0, p1 : float in [0, ..., 1]
Define the [p0, p1] percentile interval to be considered for computing
the value.
Returns
-------
local mean_substraction : uint8 array or uint16 array depending on input image
local mean_substraction : uint8 array or uint16
The result of the local mean_substraction.
"""
return _apply(
_crank8_percentiles.mean_substraction, _crank16_percentiles.mean_substraction, image, selem, out=out,
mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1)
return _apply(_crank8_percentiles.mean_substraction,
_crank16_percentiles.mean_substraction,
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.):
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 between percentiles [p0,p1] ,are used.
morph_contr_enh is computed on the given structuring element. Only levels
between percentiles [p0, p1] are used.
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). If image is uint16, as the
algorithm uses max. 12bit histogram, an exception will be raised if
image has a value > 4095.
selem : ndarray
The neighborhood expressed as a 2-D array of 1's and 0's.
out : ndarray
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).
p0, p1 : float in [0.,...,1.]
define the [p0,p1] percentile interval to be considered for computing the value.
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).
p0, p1 : float in [0, ..., 1]
Define the [p0, p1] percentile interval to be considered for computing
the value.
Returns
-------
local morph_contr_enh : uint8 array or uint16 array depending on input image
local morph_contr_enh : uint8 array or uint16
The result of the local morph_contr_enh.
"""
return _apply(
_crank8_percentiles.morph_contr_enh, _crank16_percentiles.morph_contr_enh, image, selem, out=out,
mask=mask, shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1)
return _apply(_crank8_percentiles.morph_contr_enh,
_crank16_percentiles.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, p1=1.):
def percentile(image, selem, out=None, mask=None, shift_x=False, shift_y=False,
p0=.0, p1=1.):
"""Return greyscale local percentile of an image.
percentile is computed on the given structuring element. Only levels between percentiles [p0,p1] ,are used.
percentile is computed on the given structuring element. Only levels between
percentiles [p0, p1] are used.
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). If image is uint16, as the
algorithm uses max. 12bit histogram, an exception will be raised if
image has a value > 4095.
selem : ndarray
The neighborhood expressed as a 2-D array of 1's and 0's.
out : ndarray
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).
p0, p1 : float in [0.,...,1.]
define the [p0,p1] percentile interval to be considered for computing the value.
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).
p0, p1 : float in [0, ..., 1]
Define the [p0, p1] percentile interval to be considered for computing
the value.
Returns
-------
local percentile : uint8 array or uint16 array depending on input image
local percentile : uint8 array or uint16
The result of the local percentile.
"""
return _apply(
_crank8_percentiles.percentile, _crank16_percentiles.percentile, image, selem, out=out, mask=mask,
shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1)
return _apply(_crank8_percentiles.percentile,
_crank16_percentiles.percentile,
image, selem, out=out, mask=mask, shift_x=shift_x,
shift_y=shift_y, p0=p0, p1=p1)
def percentile_pop(image, selem, out=None, mask=None, shift_x=False, shift_y=False, p0=.0, p1=1.):
def percentile_pop(image, selem, out=None, mask=None, shift_x=False,
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 percentiles [p0,p1] ,are used.
pop is computed on the given structuring element. Only levels between
percentiles [p0, p1] are used.
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). If image is uint16, as the
algorithm uses max. 12bit histogram, an exception will be raised if
image has a value > 4095.
selem : ndarray
The neighborhood expressed as a 2-D array of 1's and 0's.
out : ndarray
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).
p0, p1 : float in [0.,...,1.]
define the [p0,p1] percentile interval to be considered for computing the value.
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).
p0, p1 : float in [0, ..., 1]
Define the [p0, p1] percentile interval to be considered for computing
the value.
Returns
-------
local pop : uint8 array or uint16 array depending on input image
local pop : uint8 array or uint16
The result of the local pop.
"""
return _apply(
_crank8_percentiles.pop, _crank16_percentiles.pop, image, selem, out=out, mask=mask, shift_x=shift_x,
shift_y=shift_y, p0=p0, p1=p1)
return _apply(_crank8_percentiles.pop, _crank16_percentiles.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, p1=1.):
def percentile_threshold(image, selem, out=None, mask=None, shift_x=False,
shift_y=False, p0=.0, p1=1.):
"""Return greyscale local threshold of an image.
threshold is computed on the given structuring element. Only levels between percentiles [p0,p1] ,are used.
threshold is computed on the given structuring element. Only levels between
percentiles [p0, p1] are used.
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). If image is uint16, as the
algorithm uses max. 12bit histogram, an exception will be raised if
image has a value > 4095.
selem : ndarray
The neighborhood expressed as a 2-D array of 1's and 0's.
out : ndarray
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).
p0, p1 : float in [0.,...,1.]
define the [p0,p1] percentile interval to be considered for computing the value.
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).
p0, p1 : float in [0, ..., 1]
Define the [p0, p1] percentile interval to be considered for computing
the value.
Returns
-------
local threshold : uint8 array or uint16 array depending on input image
local threshold : uint8 array or uint16
The result of the local threshold.
"""
return _apply(
_crank8_percentiles.threshold, _crank16_percentiles.threshold, image, selem, out=out, mask=mask,
shift_x=shift_x, shift_y=shift_y, p0=p0, p1=p1)
return _apply(_crank8_percentiles.threshold, _crank16_percentiles.threshold,
image, selem, out=out, mask=mask, shift_x=shift_x,
shift_y=shift_y, p0=p0, p1=p1)
+266 -209
View File
@@ -1,44 +1,63 @@
"""rank.py - rankfilter for local (custom kernel) maximum, minimum, median, mean, auto-level, equalization, etc
"""The local histogram is computed using a sliding window similar to the method
described in:
The local histogram is computed using a sliding window similar to the method described in
Reference: 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.
Reference: 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.
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 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
Result image is 8 or 16 bit with respect to the input image.
"""
from skimage import img_as_ubyte
import numpy as np
from skimage import img_as_ubyte
from skimage.filter.rank import _crank8, _crank16
from skimage.filter.rank.generic import find_bitdepth
__all__ = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'maximum', 'mean', 'meansubstraction', 'median', 'minimum',
'modal', 'morph_contr_enh', 'pop', 'threshold', 'tophat','noise_filter','entropy','otsu']
__all__ = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'maximum', 'mean',
'meansubstraction', '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)
if mask is not None:
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.")
if image.dtype == np.uint8:
if func8 is None:
raise TypeError("not implemented for uint8 image")
return func8(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, out=out)
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)
elif image.dtype == np.uint16:
if func16 is None:
raise TypeError("not implemented for uint16 image")
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 > 11:
raise ValueError("only uint16 <4096 image (12bit) supported!")
return func16(image, selem, shift_x=shift_x, shift_y=shift_y, mask=mask, bitdepth=bitdepth + 1, out=out)
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)
else:
raise TypeError("only uint8 and uint16 image supported!")
raise TypeError("Only uint8 and uint16 image supported.")
return out
def autolevel(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
@@ -47,18 +66,20 @@ 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). 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).
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
-------
@@ -77,9 +98,8 @@ def autolevel(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
"""
return _apply(
_crank8.autolevel, _crank16.autolevel, image, selem, out=out, mask=mask, shift_x=shift_x,
shift_y=shift_y)
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):
@@ -88,30 +108,30 @@ 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). 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).
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)
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):
@@ -120,18 +140,20 @@ 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). 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).
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
-------
@@ -147,32 +169,35 @@ def equalize(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
>>> 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)
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).
"""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
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).
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
-------
@@ -181,9 +206,8 @@ def gradient(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
"""
return _apply(
_crank8.gradient, _crank16.gradient, image, selem, out=out, mask=mask, shift_x=shift_x,
shift_y=shift_y)
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):
@@ -193,18 +217,20 @@ 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). 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).
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
-------
@@ -213,17 +239,18 @@ def maximum(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
See also
--------
skimage.morphology.dilation()
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
* 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)
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):
@@ -232,18 +259,20 @@ 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). 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).
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
-------
@@ -259,63 +288,66 @@ def mean(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
>>> 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)
return _apply(_crank8.mean, _crank16.mean, image, selem, out=out,
mask=mask, shift_x=shift_x, shift_y=shift_y)
def meansubstraction(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
def meansubstraction(image, selem, out=None, mask=None, shift_x=False,
shift_y=False):
"""Return image substracted 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
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).
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 meansubstraction.
"""
return _apply(
_crank8.meansubstraction, _crank16.meansubstraction, image, selem, out=out, mask=mask,
shift_x=shift_x, shift_y=shift_y)
return _apply(_crank8.meansubstraction, _crank16.meansubstraction, 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
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).
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
-------
@@ -331,9 +363,11 @@ def median(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
>>> 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)
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):
@@ -342,18 +376,20 @@ 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). 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).
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
-------
@@ -362,17 +398,18 @@ def minimum(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
See also
--------
skimage.morphology.erosion()
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
* 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)
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):
@@ -381,49 +418,55 @@ 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). 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).
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)
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 graylevel is closest to maximimum
than local minimum OR local minimum otherwise.
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
graylevel 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
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).
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
-------
@@ -439,31 +482,34 @@ def morph_contr_enh(image, selem, out=None, mask=None, shift_x=False, shift_y=Fa
>>> 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)
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.
"""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
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).
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
-------
@@ -487,10 +533,10 @@ def pop(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
[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)
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):
@@ -499,18 +545,20 @@ 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). 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).
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
-------
@@ -534,12 +582,10 @@ def threshold(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
[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)
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):
@@ -548,18 +594,20 @@ 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). 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).
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
-------
@@ -568,32 +616,35 @@ def tophat(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
"""
return _apply(_crank8.tophat, _crank16.tophat, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y)
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):
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
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. Central element is removed during the filtering.
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).
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).
Reference
References
----------
.. [Hashimoto12] N. Hashimoto et al. Referenceless image quality evaluation for whole slide imaging. J Pathol Inform 2012;3:9.
.. [Hashimoto12] N. Hashimoto et al. Referenceless image quality evaluation
for whole slide imaging. J Pathol Inform 2012;3:9.
Returns
-------
@@ -601,6 +652,7 @@ def noise_filter(image, selem, out=None, mask=None, shift_x=False, shift_y=False
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
@@ -608,41 +660,43 @@ def noise_filter(image, selem, out=None, mask=None, shift_x=False, shift_y=False
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)
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 [wiki_entropy]_ 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.
References
----------
.. [wiki_entropy] http://en.wikipedia.org/wiki/Entropy_(information_theory)
"""Returns the entropy [wiki_entropy]_ 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
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).
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
----------
.. [wiki_entropy] http://en.wikipedia.org/wiki/Entropy_(information_theory)
Examples
--------
>>> # Local entropy
>>> from skimage import data
>>> from skimage.filter.rank import entropy
@@ -650,46 +704,48 @@ def entropy(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
>>> # defining a 8- and a 16-bit test images
>>> a8 = data.camera()
>>> a16 = data.camera().astype(np.uint16)*4
>>> ent8 = entropy(a8,disk(5)) # pixel value contain 10x the local entropy
>>> ent16 = entropy(a16,disk(5)) # pixel value contain 1000x the local entropy
>>> # 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)
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 image threshold using a the Otsu [otsu]_ locally .
References
----------
.. [otsu] http://en.wikipedia.org/wiki/Otsu's_method
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). 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).
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)
threshold image
References
----------
.. [otsu] http://en.wikipedia.org/wiki/Otsu's_method
Examples
--------
>>> # Local entropy
>>> from skimage import data
>>> from skimage.filter.rank import otsu
@@ -700,4 +756,5 @@ def otsu(image, selem, out=None, mask=None, shift_x=False, shift_y=False):
"""
return _apply(_crank8.otsu, None, image, selem, out=out, mask=mask, shift_x=shift_x, shift_y=shift_y)
return _apply(_crank8.otsu, None, image, selem, out=out,
mask=mask, shift_x=shift_x, shift_y=shift_y)
-57
View File
@@ -1,57 +0,0 @@
import sys
print sys.path
import skimage
print skimage
import unittest
import numpy as np
from skimage.filter import rank
from skimage import data
from skimage.morphology import cmorph,disk
from skimage.filter.rank import _crank8, _crank16
from skimage.filter.rank import _crank16_percentiles
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
pass
def test_trivial_selem(self):
# check that min, max and mean returns identity if structuring element contains only central pixel
a = np.zeros((5,5),dtype='uint8')
a[2,2] = 255
a[2,3] = 128
a[1,2] = 16
elem = np.asarray([[0,0,0],[0,1,0],[0,0,0]],dtype='uint8')
f = _crank8.mean(image=a,selem = elem,shift_x=0,shift_y=0)
np.testing.assert_array_equal(a,f)
f = _crank8.minimum(image=a,selem = elem,shift_x=0,shift_y=0)
np.testing.assert_array_equal(a,f)
f = _crank8.maximum(image=a,selem = elem,shift_x=0,shift_y=0)
np.testing.assert_array_equal(a,f)
def test_smallest_selem(self):
# check that min, max and mean returns identity if structuring element contains only central pixel
a = np.zeros((5,5),dtype='uint8')
a[2,2] = 255
a[2,3] = 128
a[1,2] = 16
elem = np.asarray([[1]],dtype='uint8')
f = _crank8.mean(image=a,selem = elem,shift_x=0,shift_y=0)
np.testing.assert_array_equal(a,f)
f = _crank8.minimum(image=a,selem = elem,shift_x=0,shift_y=0)
np.testing.assert_array_equal(a,f)
f = _crank8.maximum(image=a,selem = elem,shift_x=0,shift_y=0)
np.testing.assert_array_equal(a,f)
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)
unittest.TextTestRunner(verbosity=2).run(suite)
+294
View File
@@ -0,0 +1,294 @@
import numpy as np
from numpy.testing import run_module_suite, assert_array_equal, assert_raises
import unittest
from skimage import data
from skimage.morphology import cmorph, disk
from skimage.filter import rank
from skimage.filter.rank import _crank8, _crank16, _crank16_percentiles
def test_random_sizes():
# make sure the size is not a problem
niter = 10
elem = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]], dtype=np.uint8)
for m, n in np.random.random_integers(1, 100, size=(10, 2)):
mask = np.ones((m, n), dtype=np.uint8)
image8 = np.ones((m, n), dtype=np.uint8)
out8 = np.empty_like(image8)
_crank8.mean(image=image8, selem=elem, mask=mask, out=out8,
shift_x=0, shift_y=0)
assert_array_equal(image8.shape, out8.shape)
_crank8.mean(image=image8, selem=elem, mask=mask, out=out8,
shift_x=+1, shift_y=+1)
assert_array_equal(image8.shape, out8.shape)
image16 = np.ones((m, n), dtype=np.uint16)
out16 = np.empty_like(image8, dtype=np.uint16)
_crank16.mean(image=image16, selem=elem, mask=mask, out=out16,
shift_x=0, shift_y=0)
assert_array_equal(image16.shape, out16.shape)
_crank16.mean(image=image16, selem=elem, mask=mask, out=out16,
shift_x=+1, shift_y=+1)
assert_array_equal(image16.shape, out16.shape)
_crank16_percentiles.mean(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)
_crank16_percentiles.mean(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)
def test_compare_with_cmorph_dilate():
# compare the result of maximum filter with dilate
image = (np.random.random((100, 100)) * 256).astype(np.uint8)
out = np.empty_like(image)
mask = np.ones(image.shape, dtype=np.uint8)
for r in range(1, 20, 1):
elem = np.ones((r, r), dtype=np.uint8)
_crank8.maximum(image=image, selem=elem, out=out, mask=mask)
cm = cmorph.dilate(image=image, selem=elem)
assert_array_equal(out, cm)
def test_compare_with_cmorph_erode():
# compare the result of maximum filter with erode
image = (np.random.random((100, 100)) * 256).astype(np.uint8)
out = np.empty_like(image)
mask = np.ones(image.shape, dtype=np.uint8)
for r in range(1, 20, 1):
elem = np.ones((r, r), dtype=np.uint8)
_crank8.minimum(image=image, selem=elem, out=out, mask=mask)
cm = cmorph.erode(image=image, selem=elem)
assert_array_equal(out, cm)
def test_bitdepth():
# test the different bit depth for rank16
elem = np.ones((3, 3), dtype=np.uint8)
out = np.empty((100, 100), dtype=np.uint16)
mask = np.ones((100, 100), dtype=np.uint8)
for i in range(5):
image = np.ones((100, 100),dtype=np.uint16) * 255 * 2**i
r = _crank16_percentiles.mean(image=image, selem=elem, mask=mask,
out=out, shift_x=0, shift_y=0, p0=.1, p1=.9, bitdepth=8 + i)
def test_population():
# check the number of valid pixels in the neighborhood
image = np.zeros((5, 5), dtype=np.uint8)
elem = np.ones((3, 3), dtype=np.uint8)
out = np.empty_like(image)
mask = np.ones(image.shape, dtype=np.uint8)
_crank8.pop(image=image, selem=elem, out=out, mask=mask)
r = np.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]])
assert_array_equal(r, out)
def test_structuring_element8():
# check the output for a custom structuring element
r = np.array([[ 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0],
[ 0, 0, 255, 0, 0, 0],
[ 0, 0, 255, 255, 255, 0],
[ 0, 0, 0, 255, 255, 0],
[ 0, 0, 0, 0, 0, 0]])
# 8bit
image = np.zeros((6, 6), dtype=np.uint8)
image[2, 2] = 255
elem = np.asarray([[1, 1, 0], [1, 1, 1], [0, 0, 1]], dtype=np.uint8)
out = np.empty_like(image)
mask = np.ones(image.shape, dtype=np.uint8)
_crank8.maximum(image=image, selem=elem, out=out, mask=mask,
shift_x=1, shift_y=1)
assert_array_equal(r, out)
# 16bit
image = np.zeros((6, 6), dtype=np.uint16)
image[2, 2] = 255
out = np.empty_like(image)
_crank16.maximum(image=image, selem=elem, out=out, mask=mask,
shift_x=1, shift_y=1)
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) * 255
elem = np.ones((3, 3), dtype=np.uint8)
out = np.empty_like(image)
mask = np.ones(image.shape, dtype=np.uint8)
assert_raises(AssertionError, _crank16_percentiles.mean, image=image,
selem=elem, out=out, mask=mask, shift_x=0, shift_y=0, bitdepth=4)
def test_inplace_output():
# rank filters are not supposed to filter inplace
selem = disk(20)
image = (np.random.random((500,500))*256).astype(np.uint8)
out = image
assert_raises(NotImplementedError, rank.mean, image, selem, out=out)
def test_compare_autolevels():
# compare autolevel and percentile autolevel with p0=0.0 and p1=1.0
# should returns the same arrays
image = data.camera()
selem = disk(20)
loc_autolevel = rank.autolevel(image, selem=selem)
loc_perc_autolevel = rank.percentile_autolevel(image, selem=selem,
p0=.0, p1=1.)
assert_array_equal(loc_autolevel, loc_perc_autolevel)
def test_compare_autolevels_16bit():
# compare autolevel(16bit) and percentile autolevel(16bit) with p0=0.0 and
# p1=1.0 should returns the same arrays
image = data.camera().astype(np.uint16) * 4
selem = disk(20)
loc_autolevel = rank.autolevel(image, selem=selem)
loc_perc_autolevel = rank.percentile_autolevel(image, selem=selem,
p0=.0, p1=1.)
assert_array_equal(loc_autolevel, loc_perc_autolevel)
def test_compare_8bit_vs_16bit():
# filters applied on 8bit image ore 16bit image (having only real 8bit of
# dynamic) should be identical
image8 = data.camera()
image16 = image8.astype(np.uint16)
assert_array_equal(image8, image16)
methods = ['autolevel', 'bottomhat', 'equalize', 'gradient', 'maximum',
'mean', 'meansubstraction', 'median', 'minimum', 'modal',
'morph_contr_enh', 'pop', 'threshold', 'tophat']
for method in methods:
func = getattr(rank, method)
f8 = func(image8, disk(3))
f16 = func(image16, disk(3))
assert_array_equal(f8, f16)
def test_trivial_selem8():
# check that min, max and mean returns identity if structuring element
# contains only central pixel
image = np.zeros((5, 5), dtype=np.uint8)
out = np.zeros_like(image)
mask = np.ones_like(image, dtype=np.uint8)
image[2,2] = 255
image[2,3] = 128
image[1,2] = 16
elem = np.array([[0, 0, 0], [0, 1, 0],[0, 0, 0]], dtype=np.uint8)
_crank8.mean(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_array_equal(image, out)
_crank8.minimum(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_array_equal(image, out)
_crank8.maximum(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_array_equal(image, out)
def test_trivial_selem16():
# check that min, max and mean returns identity if structuring element
# contains only central pixel
image = np.zeros((5, 5), dtype=np.uint16)
out = np.zeros_like(image)
mask = np.ones_like(image, dtype=np.uint8)
image[2,2] = 255
image[2,3] = 128
image[1,2] = 16
elem = np.array([[0, 0, 0], [0, 1, 0],[0, 0, 0]], dtype=np.uint8)
_crank16.mean(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_array_equal(image, out)
_crank16.minimum(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_array_equal(image, out)
_crank16.maximum(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_array_equal(image, out)
def test_smallest_selem8():
# check that min, max and mean returns identity if structuring element
# contains only central pixel
image = np.zeros((5, 5), dtype=np.uint8)
out = np.zeros_like(image)
mask = np.ones_like(image, dtype=np.uint8)
image[2,2] = 255
image[2,3] = 128
image[1,2] = 16
elem = np.array([[1]], dtype=np.uint8)
_crank8.mean(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_array_equal(image, out)
_crank8.minimum(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_array_equal(image, out)
_crank8.maximum(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_array_equal(image, out)
def test_smallest_selem16():
# check that min, max and mean returns identity if structuring element
# contains only central pixel
image = np.zeros((5, 5), dtype=np.uint16)
out = np.zeros_like(image)
mask = np.ones_like(image, dtype=np.uint8)
image[2,2] = 255
image[2,3] = 128
image[1,2] = 16
elem = np.array([[1]], dtype=np.uint8)
_crank16.mean(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_array_equal(image, out)
_crank16.minimum(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_array_equal(image, out)
_crank16.maximum(image=image, selem=elem, out=out, mask=mask,
shift_x=0, shift_y=0)
assert_array_equal(image, out)
if __name__ == "__main__":
run_module_suite()
-191
View File
@@ -1,191 +0,0 @@
import sys
print sys.path
import skimage
print skimage
import unittest
import numpy as np
from skimage.filter import rank
from skimage import data
from skimage.morphology import cmorph,disk
from skimage.filter.rank import _crank8, _crank16
from skimage.filter.rank import _crank16_percentiles
class TestSequenceFunctions(unittest.TestCase):
def setUp(self):
pass
def test_random_sizes(self):
# make sure the size is not a problem
niter = 10
elem = np.asarray([[1,1,1],[1,1,1],[1,1,1]],dtype='uint8')
for m,n in np.random.random_integers(1,100,size=(10,2)):
a8 = np.ones((m,n),dtype='uint8')
r = _crank8.mean(image=a8,selem = elem,shift_x=0,shift_y=0)
self.assertTrue(a8.shape == r.shape)
r = _crank8.mean(image=a8,selem = elem,shift_x=+1,shift_y=+1)
self.assertTrue(a8.shape == r.shape)
for m,n in np.random.random_integers(1,100,size=(10,2)):
a16 = np.ones((m,n),dtype='uint16')
r = _crank16.mean(image=a16,selem = elem,shift_x=0,shift_y=0)
self.assertTrue(a16.shape == r.shape)
r = _crank16.mean(image=a16,selem = elem,shift_x=+1,shift_y=+1)
self.assertTrue(a16.shape == r.shape)
for m,n in np.random.random_integers(1,100,size=(10,2)):
a16 = np.ones((m,n),dtype='uint16')
r = _crank16_percentiles.mean(image=a16,selem = elem,shift_x=0,shift_y=0,p0=.1,p1=.9)
self.assertTrue(a16.shape == r.shape)
r = _crank16_percentiles.mean(image=a16,selem = elem,shift_x=+1,shift_y=+1,p0=.1,p1=.9)
self.assertTrue(a16.shape == r.shape)
def test_compare_with_cmorph_dilate(self):
#compare the result of maximum filter with dilate
a = (np.random.random((500,500))*256).astype('uint8')
for r in range(1,20,1):
elem = np.ones((r,r),dtype='uint8')
# elem = (np.random.random((r,r))>.5).astype('uint8')
rc = _crank8.maximum(image=a,selem = elem)
cm = cmorph.dilate(image=a,selem = elem)
self.assertTrue((rc==cm).all())
def test_compare_with_cmorph_erode(self):
#compare the result of maximum filter with erode
a = (np.random.random((500,500))*256).astype('uint8')
for r in range(1,20,1):
elem = np.ones((r,r),dtype='uint8')
# elem = (np.random.random((r,r))>.5).astype('uint8')
rc = _crank8.minimum(image=a,selem = elem)
cm = cmorph.erode(image=a,selem = elem)
self.assertTrue((rc==cm).all())
def test_bitdepth(self):
# test the different bit depth for rank16
elem = np.ones((3,3),dtype='uint8')
a16 = np.ones((100,100),dtype='uint16')*255
r = _crank16_percentiles.mean(image=a16,selem = elem,shift_x=0,shift_y=0,p0=.1,p1=.9,bitdepth=8)
a16 = np.ones((100,100),dtype='uint16')*255*2
r = _crank16_percentiles.mean(image=a16,selem = elem,shift_x=0,shift_y=0,p0=.1,p1=.9,bitdepth=9)
a16 = np.ones((100,100),dtype='uint16')*255*4
r = _crank16_percentiles.mean(image=a16,selem = elem,shift_x=0,shift_y=0,p0=.1,p1=.9,bitdepth=10)
a16 = np.ones((100,100),dtype='uint16')*255*8
r = _crank16_percentiles.mean(image=a16,selem = elem,shift_x=0,shift_y=0,p0=.1,p1=.9,bitdepth=11)
a16 = np.ones((100,100),dtype='uint16')*255*16
r = _crank16_percentiles.mean(image=a16,selem = elem,shift_x=0,shift_y=0,p0=.1,p1=.9,bitdepth=12)
def test_population(self):
# check the number of valid pixels in the neighborhood
a = np.zeros((5,5),dtype='uint8')
elem = np.ones((3,3),dtype='uint8')
p = _crank8.pop(image=a,selem = elem)
r = np.asarray([[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]])
np.testing.assert_array_equal(r,p)
def test_structuring_element(self):
# check the output for a custom structuring element
a = np.zeros((6,6),dtype='uint8')
a[2,2] = 255
elem = np.asarray([[1,1,0],[1,1,1],[0,0,1]],dtype='uint8')
f = _crank8.maximum(image=a,selem = elem,shift_x=1,shift_y=1)
r = np.asarray([[ 0, 0, 0, 0, 0, 0],
[ 0, 0, 0, 0, 0, 0],
[ 0, 0, 255, 0, 0, 0],
[ 0, 0, 255, 255, 255, 0],
[ 0, 0, 0, 255, 255, 0],
[ 0, 0, 0, 0, 0, 0]])
np.testing.assert_array_equal(r,f)
@unittest.expectedFailure
def test_fail_on_bitdepth(self):
# should fail because data bitdepth is too high for the function
a16 = np.ones((100,100),dtype='uint16')*255
elem = np.ones((3,3),dtype='uint8')
f = _crank16_percentiles.mean(image=a16,selem = elem,shift_x=0,shift_y=0,p0=.1,p1=.9,bitdepth=4)
def test_output(self):
#check rank function with external OUT output array
selem = disk(20)
a = (np.random.random((500,500))*256).astype('uint8')
out = np.zeros_like(a)
f1 = rank.mean(a,selem,out=out)
f2 = rank.mean(a,selem)
np.testing.assert_array_equal(f1,f2)
np.testing.assert_array_equal(out,f2)
@unittest.expectedFailure
def test_inplace_output(self):
#rank filters are not supposed to filter inplace
selem = disk(20)
a = (np.random.random((500,500))*256).astype('uint8')
out = a
f = rank.mean(a,selem,out=out)
np.testing.assert_array_equal(f,out)
def test_compare_autolevels(self):
# compare autolevel and percentile autolevel with p0=0.0 and p1=1.0
# should returns the same arrays
image = data.camera()
selem = disk(20)
loc_autolevel = rank.autolevel(image,selem=selem)
loc_perc_autolevel = rank.percentile_autolevel(image,selem=selem,p0=.0,p1=1.)
assert (loc_autolevel==loc_perc_autolevel).all()
def test_compare_autolevels_16bit(self):
# compare autolevel(16bit) and percentile autolevel(16bit) with p0=0.0 and p1=1.0
# should returns the same arrays
image = data.camera().astype(np.uint16)*4
selem = disk(20)
loc_autolevel = rank.autolevel(image,selem=selem)
loc_perc_autolevel = rank.percentile_autolevel(image,selem=selem,p0=.0,p1=1.)
assert (loc_autolevel==loc_perc_autolevel).all()
def test_compare_8bit_vs_16bit(self):
# filters applied on 8bit image ore 16bit image (having only real 8bit of dynamic)
# should be identical
i8 = data.camera()
i16 = i8.astype(np.uint16)
assert (i8==i16).all()
methods = ['autolevel','bottomhat','equalize','gradient','maximum','mean'
,'meansubstraction','median','minimum','modal','morph_contr_enh','pop','threshold', 'tophat']
for method in methods:
func = eval('rank.%s'%method)
f8 = func(i8,disk(3))
f16 = func(i16,disk(3))
assert (f8==f16).all()
if __name__ == '__main__':
suite = unittest.TestLoader().loadTestsFromTestCase(TestSequenceFunctions)
unittest.TextTestRunner(verbosity=2).run(suite)