MyGraphCuts3
In [1]:
%matplotlib notebook
In [2]:
# loading standard modules
import numpy as np
import matplotlib.pyplot as plt
import maxflow
from skimage import img_as_ubyte
from skimage.color import rgb2grey
# loading custom module (requires file asg1.py in the same directory as the notebook file)
from asg1 import Figure, GraphCutsPresenter
In [3]:
class MyGraphCuts:
bgr_value = 0
obj_value = 1
none_value = 2
def __init__(self, img, isFourNeighbor=True, sigma=1, inf=1000):
self.fig = Figure()
self.pres = GraphCutsPresenter(img, self)
self.pres.connect_figure(self.fig)
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 run(self):
self.fig.show()
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
Notes about the basic graph cut interface:¶
To provide the regional hard constraints (seeds) for object and background segments use left and right mouse clicks (mouse dragging works somewhat too). Use mouse wheel to change the brush size.
The seed mask is built by the “GraphCutsPresenter”. Each mouse release activates “on_mouse_up” function of the presenter, which asks the linked MyGraphCuts object to “compute_labels” for all pixels
based on the provided seed mask.
You should use “PyMaxflow” library (already imported into this notebook if you ran the second cell) to build a weighted graph and to compute a minimum s/t cut defining all pixel labels from the seeds as explain in topic 5.
In [4]:
img = plt.imread(‘images/canada.bmp’)
app = MyGraphCuts(img[200:800,:800], isFourNeighbor=True, sigma=0.1)
app.run()
In [5]:
app = MyGraphCuts(img[200:800,:800], isFourNeighbor=True, sigma=1)
app.run()
In [6]:
app = MyGraphCuts(img[200:800,:800], isFourNeighbor=True, sigma=10)
app.run()
Signma Experiment Observation¶
In the experimentation. I tried sigma = 0.1, 1, 10 respectively. The result of sigma = 0.1 and 1 have no noticable difference. But when using signma = 10, the resulting objective value region will become bigger than when signma=0.1 and 1.
Finite Cost T-links¶
My strategy is to use a very large value like 1000 to be the t-link cost.
In [7]:
app = MyGraphCuts(img[200:800,:800], isFourNeighbor=False)
app.run()
In [8]:
app = MyGraphCuts(img[200:800,:800], isFourNeighbor=True)
app.run()
Compare the results on 4 and 8 connected grids¶
I observe that 8 neighbor graph may resulting larger objective value region.
Similarities and differences for “intelligent sccissors” and “intelligent paint”¶
Similarities: Both let user gives hint(set the seed) and they optimize a objective to have a better segmentation. Difference: Intelligent sccissors compute the shortest path from seed to other pixels, intelligent paint computes the minimum cut that separates background and foreground.
In [ ]: