mirror of
https://github.com/wassname/scikit-image.git
synced 2026-06-29 17:53:25 +08:00
170 lines
6.3 KiB
Python
170 lines
6.3 KiB
Python
# coding=utf-8
|
|
|
|
import collections as coll
|
|
import numpy as np
|
|
from scipy import ndimage
|
|
import warnings
|
|
|
|
from skimage.util import img_as_float, regular_grid
|
|
from skimage.segmentation._slic import _slic_cython
|
|
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):
|
|
"""Segments image using k-means clustering in Color-(x,y,z) space.
|
|
|
|
Parameters
|
|
----------
|
|
image : 2D, 3D or 4D ndarray
|
|
Input image, which can be 2D or 3D, and grayscale or multichannel
|
|
(see `multichannel` parameter).
|
|
n_segments : int, optional
|
|
The (approximate) number of labels in the segmented output image.
|
|
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.
|
|
max_iter : int, optional
|
|
Maximum number of iterations of k-means.
|
|
sigma : float or (3,) array-like of floats, optional
|
|
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.
|
|
Note, that `sigma` is automatically scaled if it is scalar and a
|
|
manual voxel spacing is provided (see Notes section).
|
|
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).
|
|
This parameter controls the weights of the distances along z, y,
|
|
and x during k-means clustering.
|
|
multichannel : bool, optional
|
|
Whether the last axis of the image is to be interpreted as multiple
|
|
channels or another spatial dimension.
|
|
convert2lab : bool, optional
|
|
Whether the input should be converted to Lab colorspace prior to
|
|
segmentation. For this purpose, the input is assumed to be RGB. Highly
|
|
recommended.
|
|
ratio : float, optional
|
|
Synonym for `compactness`. This keyword is deprecated.
|
|
|
|
Returns
|
|
-------
|
|
labels : 2D or 3D array
|
|
Integer mask indicating segment labels.
|
|
|
|
Raises
|
|
------
|
|
ValueError
|
|
If:
|
|
- the image dimension is not 2 or 3 and `multichannel == False`, OR
|
|
- the image dimension is not 3 or 4 and `multichannel == True`
|
|
|
|
Notes
|
|
-----
|
|
* If `sigma > 0`, the image is smoothed using a Gaussian kernel prior to
|
|
segmentation.
|
|
|
|
* If `sigma` is scalar and `spacing` is provided, the kernel width is
|
|
divided along each dimension by the spacing. For example, if ``sigma=1``
|
|
and ``spacing=[5, 1, 1]``, the effective `sigma` is ``[0.2, 1, 1]``. This
|
|
ensures sensible smoothing for anisotropic images.
|
|
|
|
* The image is rescaled to be in [0, 1] prior to processing.
|
|
|
|
* Images of shape (M, N, 3) are interpreted as 2D RGB images by default. To
|
|
interpret them as 3D with the last dimension having length 3, use
|
|
`multichannel=False`.
|
|
|
|
References
|
|
----------
|
|
.. [1] Radhakrishna Achanta, Appu Shaji, Kevin Smith, Aurelien Lucchi,
|
|
Pascal Fua, and Sabine Süsstrunk, SLIC Superpixels Compared to
|
|
State-of-the-art Superpixel Methods, TPAMI, May 2012.
|
|
|
|
Examples
|
|
--------
|
|
>>> from skimage.segmentation import slic
|
|
>>> from skimage.data import lena
|
|
>>> img = lena()
|
|
>>> segments = slic(img, n_segments=100, compactness=10, sigma=0)
|
|
|
|
Increasing the compactness parameter yields more square regions:
|
|
|
|
>>> segments = slic(img, n_segments=100, compactness=20, sigma=0)
|
|
|
|
"""
|
|
|
|
if sigma is None:
|
|
warnings.warn('Default value of keyword `sigma` changed from ``1`` '
|
|
'to ``0``.')
|
|
sigma = 0
|
|
if ratio is not None:
|
|
warnings.warn('Keyword `ratio` is deprecated. Use `compactness` '
|
|
'instead.')
|
|
compactness = ratio
|
|
|
|
image = img_as_float(image)
|
|
is_2d = False
|
|
if image.ndim == 2:
|
|
# 2D grayscale image
|
|
image = image[np.newaxis, ..., np.newaxis]
|
|
is_2d = True
|
|
elif image.ndim == 3 and multichannel:
|
|
# Make 2D multichannel image 3D with depth = 1
|
|
image = image[np.newaxis, ...]
|
|
is_2d = True
|
|
elif image.ndim == 3 and not multichannel:
|
|
# Add channel as single last dimension
|
|
image = image[..., np.newaxis]
|
|
|
|
if spacing is None:
|
|
spacing = np.ones(3)
|
|
elif isinstance(spacing, (list, tuple)):
|
|
spacing = np.array(spacing, dtype=np.double)
|
|
|
|
if not isinstance(sigma, coll.Iterable):
|
|
sigma = np.array([sigma, sigma, sigma], dtype=np.double)
|
|
sigma /= spacing.astype(np.double)
|
|
elif isinstance(sigma, (list, tuple)):
|
|
sigma = np.array(sigma, dtype=np.double)
|
|
if (sigma > 0).any():
|
|
# add zero smoothing for multichannel dimension
|
|
sigma = list(sigma) + [0]
|
|
image = ndimage.gaussian_filter(image, sigma)
|
|
|
|
if convert2lab and multichannel:
|
|
if image.shape[3] != 3:
|
|
raise ValueError("Lab colorspace conversion requires a RGB image.")
|
|
image = rgb2lab(image)
|
|
|
|
depth, height, width = image.shape[:3]
|
|
|
|
# initialize cluster centroids for desired number of segments
|
|
grid_z, grid_y, grid_x = np.mgrid[:depth, :height, :width]
|
|
slices = regular_grid(image.shape[:3], n_segments)
|
|
step_z, step_y, step_x = [int(s.step) for s in slices]
|
|
segments_z = grid_z[slices]
|
|
segments_y = grid_y[slices]
|
|
segments_x = grid_x[slices]
|
|
|
|
segments_color = np.zeros(segments_z.shape + (image.shape[3],))
|
|
segments = np.concatenate([segments_z[..., np.newaxis],
|
|
segments_y[..., np.newaxis],
|
|
segments_x[..., np.newaxis],
|
|
segments_color
|
|
], 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
|
|
ratio = float(max((step_z, step_y, step_x))) / compactness
|
|
image = np.ascontiguousarray(image * ratio)
|
|
|
|
labels = _slic_cython(image, segments, max_iter, spacing)
|
|
|
|
if is_2d:
|
|
labels = labels[0]
|
|
|
|
return labels
|