diff --git a/doc/examples/plot_km_segmentation.py b/doc/examples/plot_km_segmentation.py index ed8cf983..3a5d6128 100644 --- a/doc/examples/plot_km_segmentation.py +++ b/doc/examples/plot_km_segmentation.py @@ -6,31 +6,16 @@ import matplotlib.pyplot as plt import numpy as np from skimage.data import lena -from skimage.segmentation import km_segmentation +from skimage.segmentation import km_segmentation, visualize_boundaries from skimage.util import img_as_float +from skimage.color import rgb2lab img = img_as_float(lena()).copy("C") -segments = km_segmentation(img, ratio=2.0, n_segments=200) +segments = km_segmentation(rgb2lab(img), ratio=10.0, n_segments=1000) print("number of segments: %d" % len(np.unique(segments))) -plt.subplot(131, title="original") -plt.imshow(img, interpolation='nearest') +boundaries_mine = visualize_boundaries(img, segments) +plt.imshow(boundaries_mine) plt.axis("off") - -plt.subplot(132, title="superpixels") -# shuffle the labels for better visualization -plt.imshow(segments, interpolation='nearest', cmap=plt.cm.prism) -plt.axis("off") - -plt.subplot(133, title="mean color") -colors = [np.bincount(segments.ravel(), img[:, :, c].ravel()) for c in - xrange(img.shape[2])] -counts = np.bincount(segments.ravel()) -colors = np.vstack(colors) / counts -plt.imshow(colors.T[segments], interpolation='nearest') -plt.axis("off") - -plt.subplots_adjust(wspace=0.02, hspace=0.02, top=0.9, - bottom=0.02, left=0.02, right=0.98) plt.show() diff --git a/doc/examples/plot_quickshift.py b/doc/examples/plot_quickshift.py index 5adf1969..9b096459 100644 --- a/doc/examples/plot_quickshift.py +++ b/doc/examples/plot_quickshift.py @@ -25,30 +25,19 @@ import matplotlib.pyplot as plt import numpy as np from skimage.data import lena -from skimage.segmentation import quickshift +from skimage.segmentation import quickshift, visualize_boundaries from skimage.util import img_as_float +from skimage.color import rgb2lab img = img_as_float(lena())[::2, ::2, :].copy("C") -segments = quickshift(img, kernel_size=5, max_dist=20) +segments = quickshift(rgb2lab(img), kernel_size=5, max_dist=20) +segments_rgb = quickshift(img, kernel_size=5, max_dist=20) print("number of segments: %d" % len(np.unique(segments))) - -fig, (ax_org, ax_sp, ax_mean) = plt.subplots(1, 3) -ax_org.set_title("original") -ax_org.imshow(img, interpolation='nearest') -ax_org.axis("off") - -ax_sp.set_title("superpixels") -ax_sp.imshow(segments, interpolation='nearest', cmap=plt.cm.prism) -ax_sp.axis("off") - -colors = [np.bincount(segments.ravel(), img[:, :, c].ravel()) for c in - xrange(img.shape[2])] -counts = np.bincount(segments.ravel()) -colors = np.vstack(colors) / counts -ax_mean.set_title("mean color") -ax_mean.imshow(colors.T[segments], interpolation='nearest') -ax_mean.axis("off") -fig.subplots_adjust(wspace=0.02, hspace=0.02, top=0.9, - bottom=0.02, left=0.02, right=0.98) +boundaries = visualize_boundaries(img, segments) +boundaries_rgb = visualize_boundaries(img, segments_rgb) +plt.imshow(boundaries) +plt.figure() +plt.imshow(boundaries_rgb) +plt.axis("off") plt.show() diff --git a/skimage/__init__.py b/skimage/__init__.py index ad37f425..b1c331ff 100644 --- a/skimage/__init__.py +++ b/skimage/__init__.py @@ -88,6 +88,7 @@ test = _setup_test() test_verbose = _setup_test(verbose=True) + def get_log(name=None): """Return a console logger. diff --git a/skimage/filter/tests/test_thresholding.py b/skimage/filter/tests/test_thresholding.py index 97d3d9e3..d17f9b84 100644 --- a/skimage/filter/tests/test_thresholding.py +++ b/skimage/filter/tests/test_thresholding.py @@ -77,11 +77,13 @@ def test_otsu_camera_image(): assert 86 < threshold_otsu(camera) < 88 + def test_otsu_coins_image(): coins = skimage.img_as_ubyte(data.coins()) assert 106 < threshold_otsu(coins) < 108 + def test_otsu_coins_image_as_float(): coins = skimage.img_as_float(data.coins()) assert 0.41 < threshold_otsu(coins) < 0.42 diff --git a/skimage/segmentation/__init__.py b/skimage/segmentation/__init__.py index b2c97448..380e937d 100644 --- a/skimage/segmentation/__init__.py +++ b/skimage/segmentation/__init__.py @@ -2,6 +2,7 @@ from .random_walker_segmentation import random_walker from .felzenszwalb import felzenszwalb_segmentation from .km_segmentation import km_segmentation from .quickshift import quickshift +from .boundaries import find_boundaries, visualize_boundaries __all__ = [random_walker, quickshift, felzenszwalb_segmentation, - km_segmentation] + km_segmentation, find_boundaries, visualize_boundaries] diff --git a/skimage/segmentation/boundaries.py b/skimage/segmentation/boundaries.py new file mode 100644 index 00000000..b40ecb01 --- /dev/null +++ b/skimage/segmentation/boundaries.py @@ -0,0 +1,19 @@ +import numpy as np +from ..morphology import dilation, square +from ..util import img_as_float + + +def find_boundaries(label_img): + boundaries = np.zeros(label_img.shape, dtype=np.bool) + boundaries[1:, :] += label_img[1:, :] != label_img[:-1, :] + boundaries[:, 1:] += label_img[:, 1:] != label_img[:, :-1] + return boundaries + + +def visualize_boundaries(img, label_img): + img = img_as_float(img, force_copy=True) + boundaries = find_boundaries(label_img) + outer_boundaries = dilation(boundaries.astype(np.uint8), square(2)) + img[outer_boundaries != 0, :] = np.array([0, 0, 0]) # black + img[boundaries, :] = np.array([1, 1, 0]) # yellow + return img diff --git a/skimage/segmentation/km_segmentation.pyx b/skimage/segmentation/km_segmentation.pyx index d0674be4..47faab7f 100644 --- a/skimage/segmentation/km_segmentation.pyx +++ b/skimage/segmentation/km_segmentation.pyx @@ -5,12 +5,12 @@ from scipy import ndimage from ..util import img_as_float -def km_segmentation(image, n_segments=100, ratio=10., max_iter=100, sigma=1.0): +def km_segmentation(image, n_segments=100, ratio=10., max_iter=10, sigma=1): """Segments image using k-means clustering in Color-(x,y) space. Parameters ---------- - image: (width, height, 3) ndarray + image: (width, height, 3) ndarray Input image ratio: float Balances color-space proximity and image-space proximity. @@ -50,7 +50,8 @@ def km_segmentation(image, n_segments=100, ratio=10., max_iter=100, sigma=1.0): means_y = grid_y[::step, ::step] means_x = grid_x[::step, ::step] - means_color = image[means_y, means_x, :] + n_seeds = len(means_y) + means_color = np.zeros((n_seeds, n_seeds, 3)) cdef np.ndarray[dtype=np.float_t, ndim=2] means = np.dstack([means_y, means_x, means_color]).reshape(-1, 5) cdef np.float_t* current_mean cdef np.float_t* mean_entry @@ -63,13 +64,14 @@ def km_segmentation(image, n_segments=100, ratio=10., max_iter=100, sigma=1.0): cdef double dist_mean cdef np.ndarray[dtype=np.int_t, ndim=2] nearest_mean = np.zeros((height, width), dtype=np.int) - cdef np.ndarray[dtype=np.float_t, ndim=2] distance = np.ones((height, width), dtype=np.float) * np.inf + cdef np.ndarray[dtype=np.float_t, ndim=2] distance = np.empty((height, width)) cdef np.float_t* image_p = image_yx.data cdef np.float_t* distance_p = distance.data cdef np.float_t* current_distance cdef np.float_t* current_pixel cdef double tmp for i in xrange(max_iter): + distance.fill(np.inf) changes = 0 current_mean = means.data # assign pixels to means @@ -105,5 +107,6 @@ def km_segmentation(image, n_segments=100, ratio=10., max_iter=100, sigma=1.0): means_list = [np.bincount(nearest_mean.ravel(), image_yx[:, :, j].ravel()) for j in xrange(5)] in_mean = np.bincount(nearest_mean.ravel()) + in_mean[in_mean == 0] = 1 means = (np.vstack(means_list) / in_mean).T.copy("C") return nearest_mean