mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-21 12:50:27 +08:00
added generic method to adaptive thresholding
This commit is contained in:
@@ -52,17 +52,20 @@ plt.axis('off')
|
||||
|
||||
#: Adaptive thresholding
|
||||
plt.subplot(2, 3, 4)
|
||||
plt.imshow(threshold_adaptive(image, 11, 5, 'gaussian'), cmap=plt.cm.gray)
|
||||
plt.imshow(threshold_adaptive(image, 11, method='gaussian', offset=5),
|
||||
cmap=plt.cm.gray)
|
||||
plt.title('Adaptive edge thresholding')
|
||||
plt.axis('off')
|
||||
|
||||
plt.subplot(2, 3, 5)
|
||||
plt.imshow(threshold_adaptive(image, 125, 7.5, 'gaussian'), cmap=plt.cm.gray)
|
||||
plt.imshow(threshold_adaptive(image, 125, method='gaussian', offset=7.5),
|
||||
cmap=plt.cm.gray)
|
||||
plt.title('Adaptive Gaussian')
|
||||
plt.axis('off')
|
||||
|
||||
plt.subplot(2, 3, 6)
|
||||
plt.imshow(threshold_adaptive(image, 125, 7.5, 'mean'), cmap=plt.cm.gray)
|
||||
plt.imshow(threshold_adaptive(image, 125, method='mean', offset=7.5),
|
||||
cmap=plt.cm.gray)
|
||||
plt.title('Adaptive Mean')
|
||||
plt.axis('off')
|
||||
|
||||
|
||||
@@ -6,22 +6,27 @@ cimport cython
|
||||
|
||||
@cython.boundscheck(False)
|
||||
@cython.wraparound(False)
|
||||
def _threshold_adaptive(np.ndarray[np.double_t, ndim=2] image,
|
||||
int block_size, double offset, method):
|
||||
def _threshold_adaptive(np.ndarray[np.double_t, ndim=2] image, int block_size,
|
||||
method, double offset, mode, param):
|
||||
cdef int r, c
|
||||
cdef np.ndarray[np.float64_t, ndim=2] mean_image
|
||||
if method == 'gaussian':
|
||||
# covers > 99% of distribution
|
||||
sigma = (block_size - 1) / 6.0
|
||||
mean_image = scipy.ndimage.gaussian_filter(image, sigma)
|
||||
cdef np.ndarray[np.float64_t, ndim=2] thres_image
|
||||
|
||||
if method == 'generic':
|
||||
thres_image = scipy.ndimage.generic_filter(image, param, block_size,
|
||||
mode=mode)
|
||||
elif method == 'gaussian':
|
||||
if param is None:
|
||||
# automatically determine sigme which covers > 99% of distribution
|
||||
sigma = (block_size - 1) / 6.0
|
||||
thres_image = scipy.ndimage.gaussian_filter(image, sigma, mode=mode)
|
||||
elif method == 'mean':
|
||||
mask = 1. / block_size**2 * np.ones((block_size, block_size))
|
||||
mean_image = scipy.ndimage.convolve(image, mask)
|
||||
thres_image = scipy.ndimage.convolve(image, mask, mode=mode)
|
||||
elif method == 'median':
|
||||
mean_image = scipy.ndimage.median_filter(image, block_size)
|
||||
thres_image = scipy.ndimage.median_filter(image, block_size, mode=mode)
|
||||
|
||||
for r in range(image.shape[0]):
|
||||
for c in range(image.shape[1]):
|
||||
mean_image[r,c] = image[r,c] > (mean_image[r,c] - offset)
|
||||
thres_image[r,c] = image[r,c] > (thres_image[r,c] - offset)
|
||||
|
||||
return mean_image.astype('bool')
|
||||
return thres_image.astype('bool')
|
||||
|
||||
@@ -25,6 +25,19 @@ class TestSimpleImage():
|
||||
image = np.float64(self.image)
|
||||
assert 2 <= threshold_otsu(image) < 3
|
||||
|
||||
def test_threshold_adaptive_generic(self):
|
||||
def func(arr):
|
||||
return arr.sum() / arr.shape[0]
|
||||
ref = np.array(
|
||||
[[False, False, False, False, True],
|
||||
[False, False, True, False, True],
|
||||
[False, False, True, True, False],
|
||||
[False, True, True, False, False],
|
||||
[ True, True, False, False, False]]
|
||||
)
|
||||
out = threshold_adaptive(self.image, 3, method='generic', param=func)
|
||||
assert_array_equal(ref, out)
|
||||
|
||||
def test_threshold_adaptive_gaussian(self):
|
||||
ref = np.array(
|
||||
[[False, False, False, False, True],
|
||||
@@ -33,7 +46,7 @@ class TestSimpleImage():
|
||||
[False, True, True, False, False],
|
||||
[ True, True, False, False, False]]
|
||||
)
|
||||
out = threshold_adaptive(self.image, 3, 0, 'gaussian')
|
||||
out = threshold_adaptive(self.image, 3, method='gaussian')
|
||||
assert_array_equal(ref, out)
|
||||
|
||||
def test_threshold_adaptive_mean(self):
|
||||
@@ -44,7 +57,7 @@ class TestSimpleImage():
|
||||
[False, True, True, False, False],
|
||||
[ True, True, False, False, False]]
|
||||
)
|
||||
out = threshold_adaptive(self.image, 3, 0, 'mean')
|
||||
out = threshold_adaptive(self.image, 3, method='mean')
|
||||
assert_array_equal(ref, out)
|
||||
|
||||
def test_threshold_adaptive_median(self):
|
||||
@@ -55,7 +68,7 @@ class TestSimpleImage():
|
||||
[False, False, True, True, False],
|
||||
[False, True, False, False, False]]
|
||||
)
|
||||
out = threshold_adaptive(self.image, 3, 0, 'median')
|
||||
out = threshold_adaptive(self.image, 3, method='median')
|
||||
assert_array_equal(ref, out)
|
||||
|
||||
|
||||
|
||||
@@ -7,12 +7,14 @@ from ._thresholding import _threshold_adaptive
|
||||
__all__ = ['threshold_otsu', 'threshold_adaptive']
|
||||
|
||||
|
||||
def threshold_adaptive(image, block_size, offset, method='gaussian'):
|
||||
def threshold_adaptive(image, block_size, method='gaussian', offset=0,
|
||||
mode='reflect', param=None):
|
||||
"""Applies an adaptive threshold to an array.
|
||||
|
||||
Also known as local or dynamic thresholding where the threshold value is the
|
||||
weighted mean for the local neighborhood of a pixel subtracted by a
|
||||
constant.
|
||||
constant. Alternatively the threshold can be determined dynamically by a
|
||||
a given function using the 'generic' method.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
@@ -21,12 +23,18 @@ def threshold_adaptive(image, block_size, offset, method='gaussian'):
|
||||
block_size : int
|
||||
uneven size of pixel neighborhood which is used to calculate the
|
||||
threshold value (e.g. 3, 5, 7, ..., 21, ...)
|
||||
offset : float
|
||||
method : {'generic', 'gaussian', 'mean', 'median'}, optional
|
||||
method used to determine adaptive threshold. By default the 'gaussian'
|
||||
method is used.
|
||||
offset : float, optional
|
||||
constant subtracted from weighted mean of neighborhood to calculate
|
||||
the local threshold value
|
||||
method : string, optional
|
||||
thresholding type which must be one of 'gaussian', 'mean' or 'median'.
|
||||
By default the 'gaussian' method is used.
|
||||
the local threshold value. Default offset is 0.
|
||||
mode : {‘reflect’,’constant’,’nearest’,’mirror’, ‘wrap’}, optional
|
||||
The mode parameter determines how the array borders are handled, where
|
||||
cval is the value when mode is equal to ‘constant’. Default is ‘reflect’
|
||||
param : {int, function}, optional
|
||||
either specify sigma for 'gaussian' method or function object for
|
||||
'generic' method.
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -40,7 +48,7 @@ def threshold_adaptive(image, block_size, offset, method='gaussian'):
|
||||
"""
|
||||
# not using img_as_float because offset parameter wouldn't work
|
||||
image = image.astype('double')
|
||||
return _threshold_adaptive(image, block_size, offset, method)
|
||||
return _threshold_adaptive(image, block_size, method, offset, mode, param)
|
||||
|
||||
def threshold_otsu(image, nbins=256):
|
||||
"""Return threshold value based on Otsu's method.
|
||||
|
||||
Reference in New Issue
Block a user