Explore the use of Chan-Vese active contours for image segmentation on a small sample of natural and medical images
Author: Jacob Reinhold
import os
import sys
from IPython.display import HTML
import matplotlib.pyplot as plt
from matplotlib import animation, rc
import numpy as np
from PIL import Image
from scipy.ndimage import distance_transform_edt as distance
from skimage import data, img_as_float
from skimage.color import rgb2gray
from skimage.draw import circle_perimeter
from skimage.filters import gaussian
from skimage.segmentation import chan_vese, active_contour
Support in-notebook plotting
%matplotlib inline
Report versions
print('numpy version: {}'.format(np.__version__))
from matplotlib import __version__ as mplver
print('matplotlib version: {}'.format(mplver))
numpy version: 1.15.4 matplotlib version: 3.0.2
pv = sys.version_info
print('python version: {}.{}.{}'.format(pv.major, pv.minor, pv.micro))
python version: 3.7.1
Reload packages where content for package development
%load_ext autoreload
%autoreload 2
def plot_results(img, cv, rotn=3, figsize=(8,8)):
fig, axes = plt.subplots(2, 2, figsize=figsize)
ax = axes.flatten()
ax[0].imshow(np.rot90(img,rotn), cmap="gray")
ax[0].set_axis_off()
ax[0].set_title("Original Image", fontsize=12)
ax[1].imshow(np.rot90(cv[0],rotn), cmap="gray")
ax[1].set_axis_off()
title = "Chan-Vese segmentation - {} iterations".format(len(cv[2]))
ax[1].set_title(title, fontsize=12)
ax[2].imshow(np.rot90(cv[1],rotn), cmap="gray")
ax[2].set_axis_off()
ax[2].set_title("Final Level Set", fontsize=12)
ax[3].plot(np.array(cv[2])/1000)
ax[3].set_title("Evolution of energy over iterations", fontsize=12)
fig.tight_layout()
def animate(image, segs, interval=20):
fig, ax = plt.subplots(figsize=(8, 8))
ax.imshow(image, cmap='gray');
im = ax.imshow(segs[0], alpha=0.5, cmap='inferno');
ax.axis('off')
def init():
im.set_data(segs[0])
return [im]
def animate(i):
im.set_array(segs[i])
return [im]
anim = animation.FuncAnimation(fig, animate, init_func=init,
frames=len(segs), interval=20, blit=True);
return anim
img = np.zeros((100, 100))
rr, cc = circle_perimeter(35, 45, 25)
img[rr, cc] = 1
img = gaussian(img, 10)
Kass, M.; Witkin, A.; Terzopoulos, D. “Snakes: Active contour models”. International Journal of Computer Vision 1 (4): 321 (1988). DOI:10.1007/BF00133570
s = np.linspace(0, 2*np.pi, 100)
init = 50 * np.array([np.cos(s), np.sin(s)]).T + 50
snake = active_contour(img, init, w_edge=0, w_line=1)
fig, ax = plt.subplots(figsize=(7, 7))
ax.imshow(img, cmap=plt.cm.gray)
ax.plot(init[:, 0], init[:, 1], '--r', lw=3)
ax.plot(snake[:, 0], snake[:, 1], '-b', lw=3)
ax.set_xticks([]), ax.set_yticks([])
ax.axis([0, img.shape[1], img.shape[0], 0]);
init = small_disk(img.shape, (49, 49), 40)
plt.imshow(init,cmap='gray'); plt.axis('off'); plt.title('Initial level set');
cv = chan_vese(img, mu=0.07, lambda1=1, lambda2=1, tol=1e-3, max_iter=500,
dt=0.5, init_level_set=init, extended_output=True)
plot_results(img, cv, 0, (10,10))
img = np.zeros((100, 100))
rr, cc = circle_perimeter(35, 45, 25)
img[rr, cc] = 1
img = gaussian(img, 10)
img += np.random.rand(*img.shape) * 0.01
s = np.linspace(0, 2*np.pi, 100)
init = 50 * np.array([np.cos(s), np.sin(s)]).T + 50
snake = active_contour(img, init, w_edge=0, w_line=1)
fig, ax = plt.subplots(figsize=(7, 7))
ax.imshow(img, cmap=plt.cm.gray)
ax.plot(init[:, 0], init[:, 1], '--r', lw=3)
ax.plot(snake[:, 0], snake[:, 1], '-b', lw=3)
ax.set_xticks([]), ax.set_yticks([])
ax.axis([0, img.shape[1], img.shape[0], 0]);
init = small_disk(img.shape, (49, 49), 40)
plt.imshow(init,cmap='gray'); plt.axis('off'); plt.title('Initial level set');
cv = chan_vese(img, mu=0.07, lambda1=1, lambda2=1, tol=1e-3, max_iter=5000,
dt=0.5, init_level_set=init, extended_output=True)
plot_results(img, cv, 0, (10,10))
img = data.astronaut()
img = rgb2gray(img)
s = np.linspace(0, 2*np.pi, 400)
x = 220 + 100*np.cos(s)
y = 100 + 100*np.sin(s)
init = np.array([x, y]).T
snake = active_contour(gaussian(img, 3),
init, alpha=0.015, beta=10, gamma=0.001)
fig, ax = plt.subplots(figsize=(7, 7))
ax.imshow(img, cmap=plt.cm.gray)
ax.plot(init[:, 0], init[:, 1], '--r', lw=3)
ax.plot(snake[:, 0], snake[:, 1], '-b', lw=3)
ax.set_xticks([]), ax.set_yticks([])
ax.axis([0, img.shape[1], img.shape[0], 0]);
def small_disk(image_size, center, radius):
centerX, centerY = center
res = np.ones(image_size)
res[centerY, centerX] = 0.
return (radius-distance(res)) / (radius*3)
original = data.astronaut()
astro = rgb2gray(original)
image = img_as_float(astro)
init = small_disk(image.shape, (220, 100), 100)
cv = chan_vese(image, mu=0.07, lambda1=1, lambda2=1, tol=1e-3, max_iter=1,
dt=0.5, init_level_set=init, extended_output=True)
plt.figure(figsize=(6,6)); plt.imshow(cv[1],cmap='gray'); plt.title('Initial level set'); plt.axis('off');
original = data.astronaut()
astro = rgb2gray(original)
image = img_as_float(astro)
init = small_disk(image.shape, (220, 100), 100)
cv = chan_vese(image, mu=0.07, lambda1=1, lambda2=1, tol=1e-3, max_iter=5000,
dt=0.5, init_level_set=init, extended_output=True)
plot_results(image, cv, 0, (10,10))
segs = np.load('circastro.npy')
anim = animate(image, segs);
HTML(anim.to_html5_video())
original = data.astronaut()
astro = rgb2gray(original)
image = img_as_float(astro)
cv = chan_vese(image, mu=0.07, lambda1=1, lambda2=1, tol=1e-3, max_iter=1,
dt=0.5, init_level_set="checkerboard", extended_output=True)
plt.figure(figsize=(6,6)); plt.imshow(cv[1],cmap='gray'); plt.title('Initial level set'); plt.axis('off');
original = data.astronaut()
astro = rgb2gray(original)
image = img_as_float(astro)
cv = chan_vese(image, mu=0.07, lambda1=1, lambda2=1, tol=1e-3, max_iter=5000,
dt=0.5, init_level_set="checkerboard", extended_output=True)
plot_results(image, cv, 0, (10,10))
segs = np.load('astrosegs.npy')
anim = animate(image, segs);
HTML(anim.to_html5_video())
image = img_as_float(data.camera())
cv = chan_vese(image, mu=0.25, lambda1=1, lambda2=1, tol=1e-3, max_iter=200,
dt=0.5, init_level_set="checkerboard", extended_output=True)
plot_results(image, cv, 0)
image = img_as_float(data.text())
cv = chan_vese(image, mu=0.01, lambda1=1, lambda2=1, tol=1e-3, max_iter=5000,
dt=0.5, init_level_set="checkerboard", extended_output=True)
plot_results(image, cv, 0, (18,8))
from glob import glob
fns = sorted(glob('imgs/*.tif'))
imgs = [Image.open(f) for f in fns]
def show(x,ax,t=''): ax.imshow(np.rot90(x,3),cmap='gray');ax.axis('off');ax.set_title(t);
f, ax1 = plt.subplots(1,1,figsize=(12,8))
show(imgs[0],ax1,'Img 1');
img1, img2 = [np.asarray(im) for im in imgs]
cv = chan_vese(img1, mu=0.01, lambda1=1, lambda2=1, tol=1e-3, max_iter=5000,
dt=0.5, init_level_set="checkerboard", extended_output=True)
plot_results(img1, cv, 3, (8,10))