From 131dea07a0157421854083af4bdb629edc5c280d Mon Sep 17 00:00:00 2001 From: Michal Romaniuk Date: Tue, 21 Jan 2014 19:25:21 +0000 Subject: [PATCH] Merged the separate loops for SLIC-zero and SLIC into one, and some minor improvements based on feedback on Github. --- skimage/segmentation/_slic.pyx | 55 ++++++++---------------- skimage/segmentation/slic_superpixels.py | 17 ++++---- skimage/segmentation/tests/test_slic.py | 1 + 3 files changed, 28 insertions(+), 45 deletions(-) diff --git a/skimage/segmentation/_slic.pyx b/skimage/segmentation/_slic.pyx index eb9742b1..ea5d9a30 100644 --- a/skimage/segmentation/_slic.pyx +++ b/skimage/segmentation/_slic.pyx @@ -10,12 +10,13 @@ cimport numpy as cnp 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, - bool slic_zero, + bint slic_zero, ): """Helper function for SLIC segmentation. @@ -36,7 +37,6 @@ def _slic_cython(double[:, :, :, ::1] image_zyx, slic_zero : bool True to run SLIC-zero, False to run original SLIC. - Returns ------- nearest_segments : 3D array of int, shape (Z, Y, X) @@ -122,42 +122,25 @@ def _slic_cython(double[:, :, :, ::1] image_zyx, x_min = max(cx - 2 * step_x, 0) x_max = min(cx + 2 * step_x + 1, width) - # 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 - + 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 + if slic_zero: dist_center += dist_color / max_dist_color[k] + else: + dist_center += dist_color - 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 + 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: diff --git a/skimage/segmentation/slic_superpixels.py b/skimage/segmentation/slic_superpixels.py index 3c447ff8..b0175b71 100644 --- a/skimage/segmentation/slic_superpixels.py +++ b/skimage/segmentation/slic_superpixels.py @@ -12,7 +12,8 @@ from skimage.color import rgb2lab def slic(image, n_segments=100, compactness=10., max_iter=10, sigma=None, spacing=None, multichannel=True, convert2lab=True, ratio=None, - enforce_connectivity=False, min_size_factor=0.5, max_size_factor=3): + enforce_connectivity=False, min_size_factor=0.5, max_size_factor=3, + slic_zero=False): """Segments image using k-means clustering in Color-(x,y,z) space. Parameters @@ -47,8 +48,6 @@ 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) @@ -59,6 +58,8 @@ def slic(image, n_segments=100, compactness=10., max_iter=10, sigma=None, max_size_factor: float, optional Proportion of the maximum connected segment size. A value of 3 works in most of the cases. + slic_zero: bool, optional + True to run SLIC-zero, False to run original SLIC. Returns ------- labels : 2D or 3D array @@ -169,21 +170,19 @@ def slic(image, n_segments=100, compactness=10., max_iter=10, sigma=None, segments_y[..., np.newaxis], segments_x[..., np.newaxis], segments_color - ], axis=-1).reshape(-1, 3 + image.shape[3]) + ], axis=-1).reshape(-1, 3 + image.shape[3]) segments = np.ascontiguousarray(segments) # we do the scaling of ratio in the same way as in the SLIC paper # so the values have the same meaning step = float(max((step_z, step_y, step_x))) - ratio = float(1) / compactness - + ratio = 1.0 / compactness + if slic_zero: image = np.ascontiguousarray(image * ratio) else: image = np.ascontiguousarray(image * ratio) - # _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: @@ -198,4 +197,4 @@ def slic(image, n_segments=100, compactness=10., max_iter=10, sigma=None, if is_2d: labels = labels[0] - return labels \ No newline at end of file + return labels diff --git a/skimage/segmentation/tests/test_slic.py b/skimage/segmentation/tests/test_slic.py index 15f03437..a0ea39f1 100644 --- a/skimage/segmentation/tests/test_slic.py +++ b/skimage/segmentation/tests/test_slic.py @@ -147,6 +147,7 @@ def test_enforce_connectivity(): assert_equal(segments_connected, result_connected) assert_equal(segments_disconnected, result_disconnected) + if __name__ == '__main__': from numpy import testing