Traditional image main segmentation algorithm:
Threshold based segmentation
(1) Fixed threshold segmentation
(2) Histogram bimodal method
(3) Iterative threshold image segmentation
(4) Adaptive threshold image segmentation
(5) Optimal threshold method
2. Edge-based segmentation
(1) Canny edge detector
(2) Harris corner detector
(3) Sift detector
(4) Surf detector
3. Region-based segmentation
(1) Seed region growth method
(2) Region splitting and merging method
(3) Watershed method
4. Segmentation based on graph theory
(1) GraphCut graph cut
(2) GrabCut segmentation and matting
5. Segmentation based on energy functional
(1) Parametric active contour model
(2)ASM
(3)AAM
(4)CLM
(5)GAC
The maximum flow and minimum cut described in this article are actually the main ideas of graph theory segmentation. The image is mapped to a weighted undirected graph, the pixels are regarded as nodes, the image segmentation problem is regarded as the vertex division problem of the graph, and the optimal segmentation of the image is obtained by using the minimum shear criterion.
Maximum Flow Algorithm
The maximum flow algorithm is like water flow in a water pipe, how to ensure the maximum water flow from point S to point T. Among them, the points between the points indicate the maximum capacity of the water pipe.
There are many maximum flow solutions, such as Ford-Fulkerson algorithm, Edmond-Karp algorithm, Dinic algorithm and so on.
Ford-Fulkerson Algorithm
The original image
residual flow diagram
Randomly find a route from s to t in the remaining flow graph
minus minimum capacity
then construct the reverse arrow
Then find a route from s to t, repeat the above calculation
continue to find new routes
At this time, no new path can be found from s to t, and the process ends.
Reuse the formula flow = capacity - residual
- =
The maximum flow 5 can be obtained.
Code:
class Edge():
''' 流网络中的边 '''
def __init__(self, v, w, cap, flow=0):
'''
定义一条边 v→w
:param v: 起点
:param w: 终点
:param cap: 容量
:param flow: v→w上的流量
'''
self.v, self.w, self.cap, self.flow = v, w, cap, flow
def other_node(self, p):
''' 返回边中与p相对的另一顶点 '''
return self.v if p == self.w else self.w
def residual_cap_to(self, p):
'''
计算残存边的剩余容量
如果p=w,residual_cap_to(p)返回 v→w 的剩余容量
如果p=v,residual_cap_to(p)返回 w→v 的剩余容量
'''
return self.cap - self.flow if p == self.w else self.flow
def moddify_flow(self, p, x):
''' 将边的流量调整x '''
if p == self.w: # 如果 p=w,将v→w的流量增加x
self.flow += x
else: # 否则将v→w的流量减少x
self.flow -= x
def __str__(self):
return str(self.v) + '→' + str(self.w)
class Network():
''' 流网络 '''
def __init__(self, E: list, s: int, t: int):
'''
:param E: 边集
:param s: 原点
:param t: 汇点
:return:
'''
self.E, self.s, self.t = E, s, t
def edges_from(self, v):
''' 从v顶点流出的边 '''
return [edge for edge in self.E if edge.v == v]
def edges_to(self, v):
''' 流入v顶点的边 '''
return [edge for edge in self.E if edge.w == v]
def edges(self, v):
''' 连接v顶点的所有边 '''
return self.edges_from(v) + self.edges_to(v)
def flows_from(self, v):
'''v顶点的流出量 '''
edges = self.edges_from(v)
return sum([e.flow for e in edges])
def flows_to(self, v):
''' v顶点的流入量 '''
edges = self.edges_to(v)
return sum([e.flow for e in edges])
def check(self):
''' 源点的流出是否等于汇点的流入 '''
return self.flows_from(self.s) == self.flows_to(self.t)
def display(self):
if self.check() is False:
print('该网络不符合守恒定律')
return
print('%-10s%-8s%-8s' % ('边', '容量', '流'))
for e in self.E:
print('%-10s%-10d%-8s' %
(e, e.cap, e.flow if e.flow < e.cap else str(e.flow) + '*'))
class FordFulkerson():
def __init__(self, G: Network):
self.G = G
self.max_flow = 0 # 最大流
class Node:
''' 用于记录路径的轨迹 '''
def __init__(self, w, e: Edge, parent):
'''
:param w: 顶点
:param e: 从上一顶点流入w的边
:param parent: 上一顶点
'''
self.w, self.e, self.parent = w, e, parent
def dfs(self):
''' 获取网络中的一条增广路径 '''
path = None
visited = set() # 被访问过的顶点
visited.add(self.G.s)
q = []
q.append(self.Node(self.G.s, None, self.G.t))
tempmaxflow = 1e10
while len(q):
node_v = q.pop(0)
v = node_v.w
label = 0
for e in self.G.edges(v): # 遍历连接v的所有边
w = e.other_node(v) # 边的另一顶点,e的指向是v→w
# v→w有剩余容量且w没有被访问过
if e.residual_cap_to(w) > 0 and w not in visited:
visited.add(w)
node_w = self.Node(w, e, node_v)
q.append(node_w)
if w == self.G.t: # 到达了汇点
path = node_w
label = 1
break
if label == 1: # 到达了汇点
break
if path is None:
tempmaxflow = 0
return tempmaxflow
node = path
while node.parent != self.G.t: # 计算增广路径上的最小剩余量
w, e = node.w, node.e
tempmaxflow = min(tempmaxflow, e.residual_cap_to(w))
node = node.parent
node = path
while node.parent != self.G.t: # 修改残存网
w, e = node.w, node.e
e.moddify_flow(w, tempmaxflow)
node = node.parent
return tempmaxflow
def start(self):
''' 增广路径最大流算法主体方法 '''
while True:
tempmaxflow = self.dfs() # 找到一条增广路径
if tempmaxflow ==0:
break
self.max_flow += tempmaxflow # 扩充最大流
def display(self):
print('最大网络流 = ', self.max_flow)
print('%-10s%-8s%-8s' % ('边', '容量', '流'))
for e in self.G.E:
print('%-10s%-10d%-8s' %
(e, e.cap, e.flow if e.flow < e.cap else str(e.flow) + '*'))
E = [Edge(1, 2, 4), Edge(1, 3, 2), Edge(2, 4, 2), Edge(2, 5, 4),
Edge(2, 3, 1), Edge(3, 5, 2), Edge(4, 6, 3), Edge(5, 6, 3)]
s, t = 1, 6
G = Network(E, s, t)
ford_fullkerson = FordFulkerson(G)
ford_fullkerson.start()
ford_fullkerson.display()
The Ford-Fulkerson algorithm has a high time complexity. Next, a Dinic algorithm that is widely used and has a low time complexity is described.
Dinic algorithm
The Dinic algorithm first establishes a Level Graph based on the remaining flow graph, as follows:
Then look for the blocking flow on the level graph, and map it back to the original residual graph.
Then create the level graph again in the new residual graph.
Then look for the blocking flow, and then map back to the residual graph. This loop continues until no blocking flow from s to t can be found in the newly generated level graph.
Reuse the formula flow = capacity - residual
-=
The maximum flow is 19.
Code
class Edge():
''' 流网络中的边 '''
def __init__(self, v, w, cap, flow=0):
'''
定义一条边 v→w
:param v: 起点
:param w: 终点
:param cap: 容量
:param flow: v→w上的流量
'''
self.v, self.w, self.cap, self.flow = v, w, cap, flow
def other_node(self, p):
''' 返回边中与p相对的另一顶点 '''
return self.v if p == self.w else self.w
def residual_cap_to(self, p):
'''
计算残存边的剩余容量
如果p=w,residual_cap_to(p)返回 v→w 的剩余容量
如果p=v,residual_cap_to(p)返回 w→v 的剩余容量
'''
return self.cap - self.flow if p == self.w else self.flow
def moddify_flow(self, p, x):
''' 将边的流量调整x '''
if p == self.w: # 如果 p=w,将v→w的流量增加x
self.flow += x
else: # 否则将v→w的流量减少x
self.flow -= x
def __str__(self):
return str(self.v) + '→' + str(self.w)
class Network():
''' 流网络 '''
def __init__(self, E: list, s: int, t: int):
'''
:param E: 边集
:param s: 原点
:param t: 汇点
:return:
'''
self.E, self.s, self.t = E, s, t
def edges_from(self, v):
''' 从v顶点流出的边 '''
return [edge for edge in self.E if edge.v == v]
def edges_to(self, v):
''' 流入v顶点的边 '''
return [edge for edge in self.E if edge.w == v]
def edges(self, v):
''' 连接v顶点的所有边 '''
return self.edges_from(v) + self.edges_to(v)
def flows_from(self, v):
'''v顶点的流出量 '''
edges = self.edges_from(v)
return sum([e.flow for e in edges])
def flows_to(self, v):
''' v顶点的流入量 '''
edges = self.edges_to(v)
return sum([e.flow for e in edges])
def check(self):
''' 源点的流出是否等于汇点的流入 '''
return self.flows_from(self.s) == self.flows_to(self.t)
def display(self):
if self.check() is False:
print('该网络不符合守恒定律')
return
print('%-10s%-8s%-8s' % ('边', '容量', '流'))
for e in self.E:
print('%-10s%-10d%-8s' %
(e, e.cap, e.flow if e.flow < e.cap else str(e.flow) + '*'))
class FordFulkerson():
def __init__(self, G: Network):
self.G = G
self.max_flow = 0 # 最大流
class Node:
''' 用于记录路径的轨迹 '''
def __init__(self, w, e: Edge, parent):
'''
:param w: 顶点
:param e: 从上一顶点流入w的边
:param parent: 上一顶点
'''
self.w, self.e, self.parent = w, e, parent
def bfs(self):
visited = {self.G.s}
tempvisited = {self.G.s}
q = []
q.append(self.Node(self.G.s, None, self.G.t))
q.append("end")
NewE = []
label = 0
while len(q)>1:
node_v = q.pop(0)
if node_v=="end":
q.append("end")
visited = tempvisited.copy()
continue
v = node_v.w
for e in self.G.edges(v): # 遍历连接v的所有边
w = e.other_node(v) # 边的另一顶点,e的指向是v→w
if e.residual_cap_to(w) > 0 and w not in visited and e not in NewE:
tempvisited.add(w)
node_w = self.Node(w, e, node_v)
q.append(node_w)
NewE.append(e)
if w == self.G.t: # 到达了汇点
label = 1
return Network(NewE,self.G.s,self.G.t),label
def dfs(self,NewNetwork):
''' 获取网络中的一条增广路径 '''
path = None
path2 = None
visited = set() # 被访问过的顶点
visited.add(self.G.s)
q = []
q.append(self.Node(self.G.s, None, self.G.t))
q2 = []
q2.append(self.Node(self.G.s, None, self.G.t))
tempmaxflow = 1e10
while len(q):
node_v = q.pop(0)
node_v2 = q2.pop(0)
v = node_v.w
label = 0
for e in NewNetwork.edges(v): # 遍历连接v的所有边
w = e.other_node(v) # 边的另一顶点,e的指向是v→w
e2 = [edge for edge in self.G.E if edge==e][0]
# v→w有剩余容量且w没有被访问过
if e.residual_cap_to(w) > 0 and w not in visited:
visited.add(w)
node_w = self.Node(w, e, node_v)
q.append(node_w)
node_w2 = self.Node(w, e2, node_v2)
q2.append(node_w2)
if w == self.G.t: # 到达了汇点
path = node_w
path2 = node_w2
label = 1
break
if label == 1: # 到达了汇点
break
if path is None:
tempmaxflow = 0
return tempmaxflow
node = path
while node.parent != self.G.t: # 计算增广路径上的最小剩余量
w, e = node.w, node.e
tempmaxflow = min(tempmaxflow, e.residual_cap_to(w))
node = node.parent
node = path2
while node.parent != self.G.t: # 修改残存网
w, e = node.w, node.e
e.moddify_flow(w, tempmaxflow)
node = node.parent
return tempmaxflow
def start(self):
while True:
newnet,label = self.bfs()
if label==0:
break
while True:
tempmaxflow = self.dfs(newnet) # 找到一条增广路径
if tempmaxflow == 0:
break
self.max_flow += tempmaxflow # 扩充最大流
def display(self):
print('最大网络流 = ', self.max_flow)
print('%-10s%-8s%-8s' % ('边', '容量', '流'))
for e in self.G.E:
print('%-10s%-10d%-8s' %
(e, e.cap, e.flow if e.flow < e.cap else str(e.flow) + '*'))
E = [Edge(1, 2, 10), Edge(1, 3, 10), Edge(2, 4, 4), Edge(2, 5, 8),
Edge(2, 3, 2), Edge(3, 5, 9), Edge(4, 6, 10), Edge(5, 6, 10),Edge(5, 4, 6)]
s, t = 1, 6
G = Network(E, s, t)
ford_fullkerson = FordFulkerson(G)
ford_fullkerson.start()
ford_fullkerson.display()
Min-cut Algorithm
The min-cut is actually the computation of the max-flow used.
Conversion between the maximum flow and the minimum cut: draw the remaining capacity of the maximum flow, then start from the starting point s, set the one that can be connected together as s, and the other side is t
Summarize:
Maximum flow and minimum cut are the basis of graph theory segmentation. Next, we will continue to explore how the maximum flow and minimum cut can achieve segmentation on the image. For example graph cut etc.
references:
https://www.its203.com/article/qq_35885429/107226535
https://github.com/wangshusen/AdvancedAlgorithms