Background subtraction¶
In [1]:
%matplotlib notebook
# loading standard modules
import numpy as np
import math
import matplotlib.pyplot as plt
from skimage import img_as_ubyte
from skimage.color import rgb2grey
Load Image Sequence¶
In [2]:
imgs = []
for i in range(1, 10):
imgs.append(plt.imread(‘images/%d.png’ %i))
Show Image Sequence¶
In [3]:
for i in range(len(imgs)):
plt.figure()
plt.title(“image ” + str(i+1))
plt.imshow(imgs[i])









Compute The Median Image of the image sequence¶
In [4]:
# every pixel value of the median image is the median of all image pixel value at this position
images = np.zeros(shape=imgs[0].shape + (len(imgs),))
for i in range(len(imgs)):
images[:,:,:,i] = imgs[i]
imgMedian = np.median(images, axis=3)
plt.figure()
plt.imshow(imgMedian)
plt.title(“median image”)

Out[4]:
Compute the Difference Image¶
In [5]:
differenceImages = [0]*len(imgs)
for i in range(len(imgs)):
differenceImages[i] = imgs[i] – imgMedian
Segment object from background using Kmeans¶
In [6]:
from sklearn.cluster import KMeans
kmeansModels = []
kmeansPreds = []
for i in range(len(differenceImages)):
diffImag = differenceImages[i]
# kmeans on difference image
kmeans = KMeans(n_clusters=2, random_state=0).fit(diffImag.reshape((-1, 4)))
kmeansModels.append(kmeans)
pred = kmeans.labels_.reshape(diffImag.shape[:-1])
# show the segmentation mask
plt.figure()
plt.title(“kmeans segmentation mask for image ” + str(i+1))
if(pred[0, 0] == 1):
pred = 1 – pred
kmeansPreds.append(pred)
plt.imshow(pred, cmap=”gray”)









Graph Cuts class adapted from HW1¶
In [7]:
import maxflow
class MyGraphCuts:
bgr_value = 0
obj_value = 1
none_value = 2
def __init__(self, img, isFourNeighbor=True, sigma=0.1, inf=1000):
self.num_rows = img.shape[0]
self.num_cols = img.shape[1]
self.img = np.mean(img, -1)
if isFourNeighbor:
self.d = [(0, 1), (1, 0)]
else:
self.d = [(-1, 1), (0, 1), (1, 1), (1, 0)]
self.sigma = sigma
self.inf = inf
def compute_labels(self, seed_mask):
num_rows = self.num_rows
num_cols = self.num_cols
label_mask = np.full((num_rows, num_cols), self.none_value, dtype=’uint8′)
g = maxflow.GraphFloat()
arr = g.add_nodes(self.num_rows * self.num_cols)
arr = arr.reshape(self.num_rows, self.num_cols)
sigma2 = self.sigma ** 2
for i in range(self.num_rows):
for j in range(self.num_cols):
if seed_mask[i, j] == self.bgr_value:
g.add_tedge(arr[i, j], self.inf, 0)
if seed_mask[i, j] == self.obj_value:
g.add_tedge(arr[i, j], 0, self.inf)
for d in self.d:
ni = i + d[0]
nj = j + d[1]
if ni in range(self.num_rows) and nj in range(self.num_cols):
w = np.exp(- ((self.img[i, j] – self.img[ni, nj]) ** 2) / (2 * sigma2))
g.add_edge(arr[i, j], arr[ni, nj], w, w)
g.maxflow()
segments = g.get_grid_segments(arr)
label_mask[segments == True] = self.obj_value
label_mask[segments == False] = self.bgr_value
return label_mask
In [8]:
def computeCenter(b):
“””
compute the forground center of the mask b
“””
r = 0.0
c = 0.0
count = 0
for i in range(b.shape[0]):
for j in range(b.shape[1]):
if b[i, j] == 1:
count += 1
r += i
c += j
r /= count
c /= count
return (r,c)
Segment object from background using graph cuts¶
I get background and foreground seed from the segmentation computed by kmeans, and then using the seeds and difference image as input to segment using graph cuts.
In [9]:
def getSeed(b, center, rr, cr, rb, cb):
“””
Get background, foreground seed from mask b which is computed by kmeans.
“””
res= np.zeros(b.shape, dtype = ‘int’) + 2
for i in range(b.shape[0]):
for j in range(b.shape[1]):
if b[i, j] == 1:
if np.abs(i – center[0]) < rr and np.abs(j - center[1]) < cr:
## it is within sensible range, set as foreground seed
res[i, j] = 1
else:
if np.abs(i - center[0]) > rb or np.abs(j – center[1]) > cb:
## it is outside sensible range, set as background seed
res[i, j] = 0
return res
graphCutsPreds = []
# for i in range(len(differenceImages)):
for i in range(9):
diffImag = differenceImages[i]
graphcuts = MyGraphCuts(diffImag, isFourNeighbor=True, sigma=0.01)
## using graph cuts with seeds computed from segmentation by kmeans
pred = graphcuts.compute_labels(getSeed(kmeansPreds[i], computeCenter(kmeansPreds[i]), 250, 100, 200, 50))
if(pred[0, 0] == 1):
pred = 1 – pred
graphCutsPreds.append(pred)
plt.figure()
plt.imshow(pred, cmap=”gray”)
plt.title(“graph cuts segmentation mask for image ” + str(i+1))

/Users/vagrant/anaconda42/anaconda/lib/python2.7/site-packages/matplotlib/pyplot.py:524: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`).
max_open_warning, RuntimeWarning)








Summary¶
In this project, I first estimate the background by computing the median image of the image sequence, and then compute the difference image by subtracting each image with median image. Then I use kmeans to segment on the difference image. Finally, I use graph cuts with seeds computed from segmentation mask got from kmeans. From the shown figure above, we can see that the segmentation of kmeans is good, and with graph cuts, the segmented foreground is more connected.
In [ ]: