mirror of
https://github.com/wassname/scikit-image.git
synced 2026-07-01 08:53:57 +08:00
Added SLIC-zero to SLIC and changed SLIC implementation slightly
This commit is contained in:
@@ -3,6 +3,7 @@
|
||||
#cython: nonecheck=False
|
||||
#cython: wraparound=False
|
||||
from libc.float cimport DBL_MAX
|
||||
from cpython cimport bool
|
||||
|
||||
import numpy as np
|
||||
cimport numpy as cnp
|
||||
@@ -11,8 +12,11 @@ from skimage.util import regular_grid
|
||||
|
||||
def _slic_cython(double[:, :, :, ::1] image_zyx,
|
||||
double[:, ::1] segments,
|
||||
float step,
|
||||
Py_ssize_t max_iter,
|
||||
double[::1] spacing):
|
||||
double[::1] spacing,
|
||||
bool slic_zero,
|
||||
):
|
||||
"""Helper function for SLIC segmentation.
|
||||
|
||||
Parameters
|
||||
@@ -21,12 +25,17 @@ def _slic_cython(double[:, :, :, ::1] image_zyx,
|
||||
The input image.
|
||||
segments : 2D array of double, shape (N, 3 + C)
|
||||
The initial centroids obtained by SLIC as [Z, Y, X, C...].
|
||||
step : double
|
||||
The size of the step between two seeds in voxels.
|
||||
max_iter : int
|
||||
The maximum number of k-means iterations.
|
||||
spacing : 1D array of double, shape (3,)
|
||||
The voxel spacing along each image dimension. This parameter
|
||||
controls the weights of the distances along z, y, and x during
|
||||
k-means clustering.
|
||||
k-means clustering.
|
||||
slic_zero : bool
|
||||
True to run SLIC-ZERO, False to run original SLIC.
|
||||
|
||||
|
||||
Returns
|
||||
-------
|
||||
@@ -85,6 +94,14 @@ def _slic_cython(double[:, :, :, ::1] image_zyx,
|
||||
sy = spacing[1]
|
||||
sx = spacing[2]
|
||||
|
||||
# The colors are scaled before being passed to _slic_cython so
|
||||
# max_color_sq can be initialised as all ones
|
||||
cdef double[::1] max_dist_color = np.ones(n_segments, dtype=np.double)
|
||||
cdef double dist_color
|
||||
|
||||
# The reference implementation calls this invxywt
|
||||
cdef double zyx_wt = float(1) / (step ** 2)
|
||||
|
||||
for i in range(max_iter):
|
||||
change = 0
|
||||
distance[:, :, :] = DBL_MAX
|
||||
@@ -105,19 +122,42 @@ def _slic_cython(double[:, :, :, ::1] image_zyx,
|
||||
x_min = <Py_ssize_t>max(cx - 2 * step_x, 0)
|
||||
x_max = <Py_ssize_t>min(cx + 2 * step_x + 1, width)
|
||||
|
||||
for z in range(z_min, z_max):
|
||||
dz = (sz * (cz - z)) ** 2
|
||||
for y in range(y_min, y_max):
|
||||
dy = (sy * (cy - y)) ** 2
|
||||
for x in range(x_min, x_max):
|
||||
dist_center = dz + dy + (sx * (cx - x)) ** 2
|
||||
for c in range(3, n_features):
|
||||
dist_center += (image_zyx[z, y, x, c - 3]
|
||||
- segments[k, c]) ** 2
|
||||
if distance[z, y, x] > dist_center:
|
||||
nearest_segments[z, y, x] = k
|
||||
distance[z, y, x] = dist_center
|
||||
change = 1
|
||||
# The loop is duplicated to avoid looking up slic_zero in every
|
||||
# iteration but perhaps it's better to improve readability at
|
||||
# the cost of performance.
|
||||
if slic_zero:
|
||||
for z in range(z_min, z_max):
|
||||
dz = (sz * (cz - z)) ** 2
|
||||
for y in range(y_min, y_max):
|
||||
dy = (sy * (cy - y)) ** 2
|
||||
for x in range(x_min, x_max):
|
||||
dist_center = (dz + dy + (sx * (cx - x)) ** 2) * zyx_wt
|
||||
dist_color = 0
|
||||
for c in range(3, n_features):
|
||||
dist_color += (image_zyx[z, y, x, c - 3]
|
||||
- segments[k, c]) ** 2
|
||||
|
||||
dist_center += dist_color / max_dist_color[k]
|
||||
|
||||
if distance[z, y, x] > dist_center:
|
||||
nearest_segments[z, y, x] = k
|
||||
distance[z, y, x] = dist_center
|
||||
change = 1
|
||||
else:
|
||||
for z in range(z_min, z_max):
|
||||
dz = (sz * (cz - z)) ** 2
|
||||
for y in range(y_min, y_max):
|
||||
dy = (sy * (cy - y)) ** 2
|
||||
for x in range(x_min, x_max):
|
||||
dist_center = (dz + dy + (sx * (cx - x)) ** 2) * zyx_wt
|
||||
for c in range(3, n_features):
|
||||
dist_center += (image_zyx[z, y, x, c - 3]
|
||||
- segments[k, c]) ** 2
|
||||
|
||||
if distance[z, y, x] > dist_center:
|
||||
nearest_segments[z, y, x] = k
|
||||
distance[z, y, x] = dist_center
|
||||
change = 1
|
||||
|
||||
# stop if no pixel changed its segment
|
||||
if change == 0:
|
||||
@@ -144,6 +184,31 @@ def _slic_cython(double[:, :, :, ::1] image_zyx,
|
||||
for c in range(n_features):
|
||||
segments[k, c] /= n_segment_elems[k]
|
||||
|
||||
# If in SLICO mode, update the color distance maxima
|
||||
if slic_zero:
|
||||
for z in range(depth):
|
||||
for y in range(height):
|
||||
for x in range(width):
|
||||
|
||||
k = nearest_segments[z, y, x]
|
||||
dist_color = 0
|
||||
|
||||
for c in range(3, n_features):
|
||||
dist_color += (image_zyx[z, y, x, c - 3]
|
||||
- segments[k, c]) ** 2
|
||||
|
||||
# The reference implementation seems to only change
|
||||
# the color if it increases from previous iteration
|
||||
if max_dist_color[k] < dist_color:
|
||||
max_dist_color[k] = dist_color
|
||||
|
||||
## DEBUG
|
||||
print('Iter %d' % (i,))
|
||||
print(str(np.asarray(max_dist_color)))
|
||||
|
||||
print('Image: ')
|
||||
print(str(np.asarray(image_zyx)))
|
||||
|
||||
return np.asarray(nearest_segments)
|
||||
|
||||
|
||||
|
||||
@@ -25,7 +25,8 @@ def slic(image, n_segments=100, compactness=10., max_iter=10, sigma=None,
|
||||
compactness : float, optional
|
||||
Balances color-space proximity and image-space proximity. Higher
|
||||
values give more weight to image-space. As `compactness` tends to
|
||||
infinity, superpixel shapes become square/cubic.
|
||||
infinity, superpixel shapes become square/cubic. In SLICO mode, this
|
||||
is the initial compactness.
|
||||
max_iter : int, optional
|
||||
Maximum number of iterations of k-means.
|
||||
sigma : float or (3,) array-like of floats, optional
|
||||
@@ -46,6 +47,8 @@ def slic(image, n_segments=100, compactness=10., max_iter=10, sigma=None,
|
||||
Whether the input should be converted to Lab colorspace prior to
|
||||
segmentation. For this purpose, the input is assumed to be RGB. Highly
|
||||
recommended.
|
||||
slic_zero: bool, optional
|
||||
True to run SLIC-zero, False to run original SLIC.
|
||||
ratio : float, optional
|
||||
Synonym for `compactness`. This keyword is deprecated.
|
||||
enforce_connectivity: bool, optional (default False)
|
||||
@@ -171,10 +174,17 @@ def slic(image, n_segments=100, compactness=10., max_iter=10, sigma=None,
|
||||
|
||||
# we do the scaling of ratio in the same way as in the SLIC paper
|
||||
# so the values have the same meaning
|
||||
ratio = float(max((step_z, step_y, step_x))) / compactness
|
||||
image = np.ascontiguousarray(image * ratio)
|
||||
step = float(max((step_z, step_y, step_x)))
|
||||
ratio = float(1) / compactness
|
||||
|
||||
if slic_zero:
|
||||
image = np.ascontiguousarray(image * ratio)
|
||||
else:
|
||||
image = np.ascontiguousarray(image * ratio)
|
||||
|
||||
labels = _slic_cython(image, segments, max_iter, spacing)
|
||||
# _slic_cython expects the image in zyx format... but isn't image in xyz
|
||||
# format???
|
||||
labels = _slic_cython(image, segments, step, max_iter, spacing, slic_zero)
|
||||
|
||||
if enforce_connectivity:
|
||||
segment_size = depth * height * width / n_segments
|
||||
@@ -188,4 +198,4 @@ def slic(image, n_segments=100, compactness=10., max_iter=10, sigma=None,
|
||||
if is_2d:
|
||||
labels = labels[0]
|
||||
|
||||
return labels
|
||||
return labels
|
||||
Reference in New Issue
Block a user