Skip to content

Commit

Permalink
Add spacing support for new, speeded-up SLIC
Browse files Browse the repository at this point in the history
  • Loading branch information
jni committed Sep 16, 2013
1 parent 610a0d1 commit 846765e
Show file tree
Hide file tree
Showing 3 changed files with 39 additions and 6 deletions.
15 changes: 11 additions & 4 deletions skimage/segmentation/_slic.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ from skimage.util import regular_grid

def _slic_cython(double[:, :, :, ::1] image_zyx,
double[:, ::1] segments,
Py_ssize_t max_iter):
Py_ssize_t max_iter,
double[:] spacing):
"""Helper function for SLIC segmentation.
Parameters
Expand All @@ -23,6 +24,7 @@ def _slic_cython(double[:, :, :, ::1] image_zyx,
The initial centroids obtained by SLIC as [Z, Y, X, C...].
max_iter : int
The maximum number of k-means iterations.
spacing : 1D array of double, shape (3,)
Returns
-------
Expand Down Expand Up @@ -55,6 +57,11 @@ def _slic_cython(double[:, :, :, ::1] image_zyx,
cdef char change
cdef double dist_center, cx, cy, cz, dy, dz

cdef double sz, sy, sx
sz = spacing[0]
sy = spacing[1]
sx = spacing[2]

for i in range(max_iter):
change = 0
distance[:, :, :] = DBL_MAX
Expand All @@ -76,11 +83,11 @@ def _slic_cython(double[:, :, :, ::1] image_zyx,
x_max = <Py_ssize_t>min(cx + 2 * step_x + 1, width)

for z in range(z_min, z_max):
dz = (cz - z) ** 2
dz = (sz * (cz - z)) ** 2
for y in range(y_min, y_max):
dy = (cy - y) ** 2
dy = (sy * (cy - y)) ** 2
for x in range(x_min, x_max):
dist_center = dz + dy + (cx - x) ** 2
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
Expand Down
12 changes: 10 additions & 2 deletions skimage/segmentation/slic_superpixels.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@


def slic(image, n_segments=100, compactness=10., max_iter=10, sigma=None,
multichannel=True, convert2lab=True, ratio=None):
spacing=None, multichannel=True, convert2lab=True, ratio=None):
"""Segments image using k-means clustering in Color-(x,y,z) space.
Parameters
Expand All @@ -31,6 +31,9 @@ def slic(image, n_segments=100, compactness=10., max_iter=10, sigma=None,
Width of Gaussian smoothing kernel for pre-processing for each
dimension of the image. The same sigma is applied to each dimension in
case of a scalar value. Zero means no smoothing.
spacing : (3,) array-like of floats, optional
The voxel spacing along each image dimension. By default, `slic`
assumes uniform spacing (same voxel resolution along z, y and x).
multichannel : bool, optional
Whether the last axis of the image is to be interpreted as multiple
channels or another spatial dimension.
Expand Down Expand Up @@ -103,11 +106,16 @@ def slic(image, n_segments=100, compactness=10., max_iter=10, sigma=None,
# Add channel as single last dimension
image = image[..., np.newaxis]

if spacing is None:
spacing = np.ones(3)
elif type(spacing) in [list, tuple]:
spacing = np.array(spacing, float)
if not isinstance(sigma, coll.Iterable):
sigma = np.array([sigma, sigma, sigma], float)
elif type(sigma) in [list, tuple]:
sigma = np.array(sigma, float)
if (sigma > 0).any():
sigma /= spacing.astype(float)
sigma = list(sigma) + [0]
image = ndimage.gaussian_filter(image, sigma)

Expand Down Expand Up @@ -139,7 +147,7 @@ def slic(image, n_segments=100, compactness=10., max_iter=10, sigma=None,
ratio = float(max((step_z, step_y, step_x))) / compactness
image = np.ascontiguousarray(image * ratio)

labels = _slic_cython(image, segments, max_iter)
labels = _slic_cython(image, segments, max_iter, spacing)

if is2d:
labels = labels[0]
Expand Down
18 changes: 18 additions & 0 deletions skimage/segmentation/tests/test_slic.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,24 @@ def test_list_sigma():
assert_equal(seg_sigma, result_sigma)


def test_spacing():
rnd = np.random.RandomState(0)
img = np.array([[1, 1, 1, 0, 0],
[1, 1, 0, 0, 0]], np.float)
result_non_spaced = np.array([[0, 0, 0, 1, 1],
[0, 0, 1, 1, 1]], np.int)
result_spaced = np.array([[0, 0, 0, 0, 0],
[1, 1, 1, 1, 1]], np.int)
img += 0.1 * rnd.normal(size=img.shape)
seg_non_spaced = slic(img, n_segments=2, sigma=0, multichannel=False,
compactness=1.0)
seg_spaced = slic(img, n_segments=2, sigma=0, spacing=[1, 500, 1],
compactness=1.0, multichannel=False)
assert_equal(seg_non_spaced, result_non_spaced)
assert_equal(seg_spaced, result_spaced)



if __name__ == '__main__':
from numpy import testing
testing.run_module_suite()

0 comments on commit 846765e

Please sign in to comment.