diff --git a/doc/examples/plot_active_contours.py b/doc/examples/plot_active_contours.py index 32689adc..911bc174 100644 --- a/doc/examples/plot_active_contours.py +++ b/doc/examples/plot_active_contours.py @@ -28,7 +28,7 @@ import matplotlib.pyplot as plt from skimage.color import rgb2gray from skimage import data from skimage.filters import gaussian_filter -from skimage.segmentation import active_contour_model +from skimage.segmentation import active_contour img = data.astronaut() img = rgb2gray(img) @@ -38,7 +38,7 @@ x = 220 + 100*np.cos(s) y = 100 + 100*np.sin(s) init = np.array([x, y]).T -snake = active_contour_model(gaussian_filter(img, 3), +snake = active_contour(gaussian_filter(img, 3), init, alpha=0.015, beta=10, gamma=0.001) fig = plt.figure(figsize=(7, 7)) @@ -65,7 +65,7 @@ x = np.linspace(5, 424, 100) y = np.linspace(136, 50, 100) init = np.array([x, y]).T -snake = active_contour_model(gaussian_filter(img, 1), init, bc='fixed', +snake = active_contour(gaussian_filter(img, 1), init, bc='fixed', alpha=0.1, beta=1.0, w_line=-5, w_edge=0, gamma=0.1) fig = plt.figure(figsize=(9, 5)) diff --git a/skimage/segmentation/__init__.py b/skimage/segmentation/__init__.py index a1a316f4..103ca5a4 100644 --- a/skimage/segmentation/__init__.py +++ b/skimage/segmentation/__init__.py @@ -1,5 +1,5 @@ from .random_walker_segmentation import random_walker -from .active_contour_model import active_contour_model +from .active_contour_model import active_contour from ._felzenszwalb import felzenszwalb from .slic_superpixels import slic from ._quickshift import quickshift @@ -9,7 +9,7 @@ from ._join import join_segmentations, relabel_from_one, relabel_sequential __all__ = ['random_walker', - 'active_contour_model', + 'active_contour', 'felzenszwalb', 'slic', 'quickshift', diff --git a/skimage/segmentation/active_contour_model.py b/skimage/segmentation/active_contour_model.py index 882ab559..c6ee27f2 100644 --- a/skimage/segmentation/active_contour_model.py +++ b/skimage/segmentation/active_contour_model.py @@ -1,13 +1,14 @@ +import warnings import numpy as np from skimage import img_as_float import scipy.linalg -from scipy.interpolate import RectBivariateSpline +from scipy.interpolate import RectBivariateSpline, interp2d from skimage.filters import sobel -def active_contour_model(image, snake, alpha=0.01, beta=0.1, - w_line=0, w_edge=1, gamma=0.01, - bc='periodic', max_px_move=1.0, - max_iterations=2500, convergence=0.1): +def active_contour(image, snake, alpha=0.01, beta=0.1, + w_line=0, w_edge=1, gamma=0.01, + bc='periodic', max_px_move=1.0, + max_iterations=2500, convergence=0.1): """Active contour model. Active contours by fitting snakes to features of images. Supports single @@ -59,20 +60,28 @@ def active_contour_model(image, snake, alpha=0.01, beta=0.1, -------- >>> from skimage.draw import circle_perimeter >>> from skimage.filters import gaussian_filter - Create and smooth image: + >>> # Create and smooth image: >>> img = np.zeros((100, 100)) >>> rr, cc = circle_perimeter(35, 45, 25) >>> img[rr, cc] = 1 >>> img = gaussian_filter(img, 2) - Initiliaze spline: + >>>> # Initiliaze spline: >>> s = np.linspace(0, 2*np.pi,100) >>> init = 50*np.array([np.cos(s), np.sin(s)]).T+50 - Fit spline to image: + >>> # Fit spline to image: >>> snake = active_contour_model(img, init, w_edge=0, w_line=1) >>> int(np.mean(np.sqrt((45-snake[:, 0])**2 + (35-snake[:, 1])**2))) 25 """ + scipy_version = map(int, scipy.__version__.split('.')) + new_scipy = scipy_version[0]>0 or \ + (scipy_version[0]==0 and scipy_version[1]>=14) + if not new_scipy: + warnings.warn('You are using an old version of scipy. ' + 'Upgrading to a version newer than 0.14.0 ' + 'will signifcantly improve the performance ' + 'of this algorithm.') max_iterations = int(max_iterations) if max_iterations <= 0: @@ -109,8 +118,13 @@ def active_contour_model(image, snake, alpha=0.01, beta=0.1, img = w_line*img + w_edge*edge[0] # Interpolate for smoothness: - intp = RectBivariateSpline(np.arange(img.shape[1]), - np.arange(img.shape[0]), img.T, kx=2, ky=2, s=0) + if new_scipy: + intp = RectBivariateSpline(np.arange(img.shape[1]), + np.arange(img.shape[0]), img.T, kx=2, ky=2, s=0) + else: + intp = np.vectorize(interp2d(np.arange(img.shape[1]), + np.arange(img.shape[0]), img, kind='cubic', copy=False, + bounds_error=False, fill_value=0)) x, y = snake[:, 0].copy(), snake[:, 1].copy() xsave = np.empty((convergence_order, len(x))) @@ -156,13 +170,17 @@ def active_contour_model(image, snake, alpha=0.01, beta=0.1, A[-2, -4:] = [-1, 3, -3, 1] efree = True - # Only one inversion is needed: + # Only one inversion is needed for implicit spline energy minimization: inv = scipy.linalg.inv(A+gamma*np.eye(n)) - # Explcit time stepping for image energy minimization: + # Explicit time stepping for image energy minimization: for i in xrange(max_iterations): - fx = intp(x, y, dx=1, grid=False) - fy = intp(x, y, dy=1, grid=False) + if new_scipy: + fx = intp(x, y, dx=1, grid=False) + fy = intp(x, y, dy=1, grid=False) + else: + fx = intp(x, y, dx=1) + fy = intp(x, y, dy=1) if sfixed: fx[0] = 0 fy[0] = 0 @@ -190,7 +208,8 @@ def active_contour_model(image, snake, alpha=0.01, beta=0.1, x[:] += dx y[:] += dy - # Convergence criteria: + # Convergence criteria needs to compare to a number of previous + # configurations since oscillations can occur. j = i%(convergence_order+1) if j < convergence_order: xsave[j, :] = x diff --git a/skimage/segmentation/tests/test_active_contour_model.py b/skimage/segmentation/tests/test_active_contour_model.py index fa30ad3a..b53995bd 100644 --- a/skimage/segmentation/tests/test_active_contour_model.py +++ b/skimage/segmentation/tests/test_active_contour_model.py @@ -2,7 +2,7 @@ import numpy as np from skimage import data from skimage.color import rgb2gray from skimage.filters import gaussian_filter -from skimage.segmentation import active_contour_model +from skimage.segmentation import active_contour from numpy.testing import assert_equal, assert_allclose, assert_raises def test_periodic_reference(): @@ -12,7 +12,7 @@ def test_periodic_reference(): x = 220 + 100*np.cos(s) y = 100 + 100*np.sin(s) init = np.array([x, y]).T - snake = active_contour_model(gaussian_filter(img, 3), init, + snake = active_contour(gaussian_filter(img, 3), init, alpha=0.015, beta=10, w_line=0, w_edge=1, gamma=0.001) refx = [299, 298, 298, 298, 298, 297, 297, 296, 296, 295] refy = [98, 99, 100, 101, 102, 103, 104, 105, 106, 108] @@ -25,7 +25,7 @@ def test_fixed_reference(): x = np.linspace(5, 424, 100) y = np.linspace(136, 50, 100) init = np.array([x, y]).T - snake = active_contour_model(gaussian_filter(img, 1), init, bc='fixed', + snake = active_contour(gaussian_filter(img, 1), init, bc='fixed', alpha=0.1, beta=1.0, w_line=-5, w_edge=0, gamma=0.1) refx = [5, 9, 13, 17, 21, 25, 30, 34, 38, 42] refy = [136, 135, 134, 133, 132, 131, 129, 128, 127, 125] @@ -38,7 +38,7 @@ def test_free_reference(): x = np.linspace(5, 424, 100) y = np.linspace(70, 40, 100) init = np.array([x, y]).T - snake = active_contour_model(gaussian_filter(img, 3), init, bc='free', + snake = active_contour(gaussian_filter(img, 3), init, bc='free', alpha=0.1, beta=1.0, w_line=-5, w_edge=0, gamma=0.1) refx = [10, 13, 16, 19, 23, 26, 29, 32, 36, 39] refy = [76, 76, 75, 74, 73, 72, 71, 70, 69, 69] @@ -57,17 +57,17 @@ def test_RGB(): x = np.linspace(5, 424, 100) y = np.linspace(136, 50, 100) init = np.array([x, y]).T - snake = active_contour_model(imgR, init, bc='fixed', + snake = active_contour(imgR, init, bc='fixed', alpha=0.1, beta=1.0, w_line=-5, w_edge=0, gamma=0.1) refx = [5, 9, 13, 17, 21, 25, 30, 34, 38, 42] refy = [136, 135, 134, 133, 132, 131, 129, 128, 127, 125] assert_equal(np.array(snake[:10, 0], dtype=np.int32), refx) assert_equal(np.array(snake[:10, 1], dtype=np.int32), refy) - snake = active_contour_model(imgG, init, bc='fixed', + snake = active_contour(imgG, init, bc='fixed', alpha=0.1, beta=1.0, w_line=-5, w_edge=0, gamma=0.1) assert_equal(np.array(snake[:10, 0], dtype=np.int32), refx) assert_equal(np.array(snake[:10, 1], dtype=np.int32), refy) - snake = active_contour_model(imgRGB, init, bc='fixed', + snake = active_contour(imgRGB, init, bc='fixed', alpha=0.1, beta=1.0, w_line=-5/3., w_edge=0, gamma=0.1) assert_equal(np.array(snake[:10, 0], dtype=np.int32), refx) assert_equal(np.array(snake[:10, 1], dtype=np.int32), refy) @@ -80,15 +80,15 @@ def test_end_points(): x = 220 + 100*np.cos(s) y = 100 + 100*np.sin(s) init = np.array([x, y]).T - snake = active_contour_model(gaussian_filter(img, 3), init, + snake = active_contour(gaussian_filter(img, 3), init, bc='periodic', alpha=0.015, beta=10, w_line=0, w_edge=1, gamma=0.001, max_iterations=100) assert np.sum(np.abs(snake[0, :]-snake[-1, :])) < 2 - snake = active_contour_model(gaussian_filter(img, 3), init, + snake = active_contour(gaussian_filter(img, 3), init, bc='free', alpha=0.015, beta=10, w_line=0, w_edge=1, gamma=0.001, max_iterations=100) assert np.sum(np.abs(snake[0, :]-snake[-1, :])) > 2 - snake = active_contour_model(gaussian_filter(img, 3), init, + snake = active_contour(gaussian_filter(img, 3), init, bc='fixed', alpha=0.015, beta=10, w_line=0, w_edge=1, gamma=0.001, max_iterations=100) assert_allclose(snake[0, :], [x[0], y[0]], atol=1e-5) @@ -99,9 +99,9 @@ def test_bad_input(): x = np.linspace(5, 424, 100) y = np.linspace(136, 50, 100) init = np.array([x, y]).T - assert_raises(ValueError, active_contour_model, img, init, + assert_raises(ValueError, active_contour, img, init, bc='wrong') - assert_raises(ValueError, active_contour_model, img, init, + assert_raises(ValueError, active_contour, img, init, max_iterations=-15)