Boundary (border) following

Couldn't find Moore boundary tracking algorithm (gw page 797) implemented in scikit-image, though it might be behind the covers as there are several ways to find boundaries: http://scikit-image.org/docs/dev/api/skimage.segmentation.html

I'll describe it instead.


In [1]:
%pylab inline
# turn of interpolation in imshow
mpl.rcParams['image.interpolation'] = 'none'

# create an image
img = np.zeros((8,8))
img[2,1:6] = 1
img[2:5, 5] = 1
imshow(img);


Populating the interactive namespace from numpy and matplotlib

We have an edge


In [2]:
# first point, upper left
img[2,1] = 2

# start position for clockwise turn
img[2,0] = 3

# visualize
imshow(img);


Red: start point of edge search

Yellow: first boundary point


In [3]:
# traverse clockwise around first point to find border
img[1,0:3] = 3

# border found
img[2,2] = 4

# visualize
imshow(img);


Orange: Clockwise search

Green: Points in boundary

Red: Found connected point


In [4]:
# last empty pixel before new point is new start for clockwise turn
img[1:3,0] = 0
img[1,1] = 0

# border point is added
img[2,2] = 2

imshow(img);


Yellow: Points in boundary

Red: New edge search point


In [5]:
# now repeat
img[1,3] = 3
img[2,3] = 4
imshow(img);


Repeat the steps over and over.

Chain code

Chain codes gives direction of border.

Using 0 left, 1 up, 2 right, 3 down, codes for border above would be:

0 (left)
0 (left)
0 (left)
0 (left)
3 (down)
3 (down)
or 000033


This might prove useful in finding direction an edge:

  • take a segment of edge
  • compute overall direction
  • compute variance of direction

Polygon


In [6]:
from skimage import data, measure
from skimage.color import rgb2gray

# get sample image
img = data.coffee()
img = rgb2gray(img)

# show it
figure(figsize=(14,14))
imshow(img, cmap="gray")

# find contours
contours = measure.find_contours(img, level=0.9)
# remove small ones
contours = [c for c in contours
                if c.shape[0] > 100]
# draw them
for contour in contours:
    plot(contour[:,1], contour[:,0])
xlim(0,img.shape[1])
ylim(img.shape[0],0);


Lets make the contours to polygons


In [7]:
figure(figsize=(14,14))
imshow(img, cmap="gray")
for contour in contours:
    polygon = measure.approximate_polygon(contour, 10)
    plot(polygon[:,1], polygon[:,0])
xlim(0,img.shape[1])
ylim(img.shape[0],0);


1D signature

Find center of the circle, plot 1d signature (gw page 809)


In [8]:
# pick the first circle
circle = contours[0]

# find center of points
cy = np.mean(circle[:,0])
cx = np.mean(circle[:,1])

# calculate distance to each point
# assume the points are in order and equally spaces
distance = np.zeros(circle.shape[0])
for i,pos in enumerate(circle):
    y,x = pos
    distance[i] = sqrt((x-cx)**2 + (y-cy)**2)

ylim(0,120)
plot(distance);


Neat! Seems like it is a ellipse, not a circle :-)

Lets do the same with the polygon.


In [9]:
# find center of points
cy = np.mean(polygon[:,0])
cx = np.mean(polygon[:,1])

# calculate distance to each point
# assume the points are in order and equally spaces
distance = np.zeros(polygon.shape[0])
for i,pos in enumerate(polygon):
    y,x = pos
    distance[i] = sqrt((x-cx)**2 + (y-cy)**2)

ylim(0,110)
plot(distance);


Convex hull

Smallest convex set H which contains whole set S


In [10]:
from skimage.morphology import star, convex_hull_image
# create a set
S = star(60).astype(bool)
imshow(S)

# calculate convex hull
H = convex_hull_image(S)

# display it
figure()
imshow(H);


Same with our own defined polygon


In [15]:
from skimage.draw import polygon
# our polygon with four vertices
vertices = (np.array([0,100,0,50]), np.array([0,100,200,100]))
# create mask
mask = polygon(*vertices)

# create image
img = np.zeros((100,200))
img[mask] = 1

# create convex hull
H = convex_hull_image(img)

imshow(img)
figure()
imshow(H);


Skeletons

Two approaches exists in scikit-image: skeletonize and medial_axis


In [20]:
from skimage.morphology import medial_axis, skeletonize

medial = medial_axis(img)
imshow(medial)
title('medial axis')

skelet = skeletonize(img)
figure()
title('skeletonize')
imshow(skelet);


medial_axis may return distance to background also with return_distance=True