diff --git a/doc/examples/plot_random_walker_segmentation.py b/doc/examples/plot_random_walker_segmentation.py index fa70e503..0c494de5 100644 --- a/doc/examples/plot_random_walker_segmentation.py +++ b/doc/examples/plot_random_walker_segmentation.py @@ -25,30 +25,11 @@ from scipy import ndimage import matplotlib.pyplot as plt from skimage.segmentation import random_walker - - -def microstructure(l=256): - """ - Synthetic binary data: binary microstructure with blobs. - - Parameters - ---------- - - l: int, optional - linear size of the returned image - """ - n = 5 - x, y = np.ogrid[0:l, 0:l] - mask = np.zeros((l, l)) - generator = np.random.RandomState(1) - points = l * generator.rand(2, n ** 2) - mask[(points[0]).astype(np.int), (points[1]).astype(np.int)] = 1 - mask = ndimage.gaussian_filter(mask, sigma=l / (4. * n)) - return (mask > mask.mean()).astype(np.float) - +from skimage.data import binary_blobs +import skimage # Generate noisy synthetic data -data = microstructure(l=128) +data = skimage.img_as_float(binary_blobs(length=128, seed=1)) data += 0.35 * np.random.randn(*data.shape) markers = np.zeros(data.shape, dtype=np.uint) markers[data < -0.3] = 1 diff --git a/skimage/data/__init__.py b/skimage/data/__init__.py index 2be829ac..1711185c 100644 --- a/skimage/data/__init__.py +++ b/skimage/data/__init__.py @@ -10,7 +10,7 @@ import os as _os from .. import data_dir from ..io import imread, use_plugin - +from ._binary_blobs import binary_blobs __all__ = ['load', 'camera', diff --git a/skimage/data/_binary_blobs.py b/skimage/data/_binary_blobs.py new file mode 100644 index 00000000..f441fce2 --- /dev/null +++ b/skimage/data/_binary_blobs.py @@ -0,0 +1,53 @@ +import numpy as np +from ..filters import gaussian_filter + + +def binary_blobs(length=512, blob_size_fraction=0.1, n_dim=2, + volume_fraction=0.5, seed=None): + """ + Generate synthetic binary image with several rounded blob-like objects. + + Parameters + ---------- + length : int, optional + Linear size of output image. + blob_size_fraction : float, optional + Typical linear size of blob, as a fraction of ``length``, should be + smaller than 1. + n_dim : int, optional + Number of dimensions of output image. + volume_fraction : float, default 0.5 + Fraction of image pixels covered by the blobs (where the output is 1). + Should be in [0, 1]. + seed : int, optional + Seed to initialize the random number generator. + + Returns + ------- + blobs : ndarray of bools + Output binary image + + Examples + -------- + >>> from skimage import data + >>> data.binary_blobs(length=5, blob_size_fraction=0.2, seed=1) + array([[ True, False, True, True, True], + [ True, True, True, False, True], + [False, True, False, True, True], + [ True, False, False, True, True], + [ True, False, False, False, True]], dtype=bool) + >>> blobs = data.binary_blobs(length=256, blob_size_fraction=0.1) + >>> # Finer structures + >>> blobs = data.binary_blobs(length=256, blob_size_fraction=0.05) + >>> # Blobs cover a smaller volume fraction of the image + >>> blobs = data.binary_blobs(length=256, volume_fraction=0.3) + """ + rs = np.random.RandomState(seed) + shape = tuple([length] * n_dim) + mask = np.zeros(shape) + n_pts = max(int(1. / blob_size_fraction) ** n_dim, 1) + points = (length * rs.rand(n_dim, n_pts)).astype(np.int) + mask[[indices for indices in points]] = 1 + mask = gaussian_filter(mask, sigma=0.25 * length * blob_size_fraction) + threshold = np.percentile(mask, 100 * (1 - volume_fraction)) + return np.logical_not(mask < threshold) diff --git a/skimage/data/tests/test_data.py b/skimage/data/tests/test_data.py index bfcdc571..38e4543a 100644 --- a/skimage/data/tests/test_data.py +++ b/skimage/data/tests/test_data.py @@ -1,5 +1,6 @@ +import numpy as np import skimage.data as data -from numpy.testing import assert_equal +from numpy.testing import assert_equal, assert_almost_equal def test_lena(): @@ -7,6 +8,7 @@ def test_lena(): lena = data.lena() assert_equal(lena.shape, (512, 512, 3)) + def test_astronaut(): """ Test that "astronaut" image can be loaded. """ astronaut = data.astronaut() @@ -54,6 +56,18 @@ def test_coffee(): data.coffee() +def test_binary_blobs(): + blobs = data.binary_blobs(length=128) + assert_almost_equal(blobs.mean(), 0.5, decimal=1) + blobs = data.binary_blobs(length=128, volume_fraction=0.25) + assert_almost_equal(blobs.mean(), 0.25, decimal=1) + blobs = data.binary_blobs(length=32, volume_fraction=0.25, n_dim=3) + assert_almost_equal(blobs.mean(), 0.25, decimal=1) + other_realization = data.binary_blobs(length=32, volume_fraction=0.25, + n_dim=3) + assert not np.all(blobs == other_realization) + + if __name__ == "__main__": from numpy.testing import run_module_suite run_module_suite()