传统图像主要分割算法:

  1. 基于阈值的分割

(1)固定阈值分割

(2)直方图双峰法

(3)迭代阈值图像分割

(4)自适应阈值图像分割

(5)最佳阈值法

2.基于边缘的分割

(1)Canny边缘检测器

(2)Harris角点检测器

(3)Sift检测器

(4)Surf检测器

3.基于区域的分割

(1)种子区域生长法

(2)区域分裂合并法

(3)分水岭法

4.基于图论的分割

(1)GraphCut图割

(2)GrabCut分割和抠图

5.基于能量泛函的分割

(1)参数主动轮廓模型

(2)ASM

(3)AAM

(4)CLM

(5)GAC

该文章讲述的最大流与最小割实际上就是图论分割的主要思想。将图像映射为带权无向图,把像素视作节点,将图像分割问题看作是图的顶点划分问题,利用最小剪切准则得到图像的最佳分割。

最大流算法

最大流算法就像水管水流,如何保证S点到T点的水流量最大。其中点与点之间的表示水管最大容量。

最大流解法有很多,例如Ford-Fulkerson算法,Edmond-Karp 算法,Dinic算法等。

Ford-Fulkerson算法

原始图

剩余流量图

在剩余流量图中随便找一条从s到t的路线

减去最小容量

然后构建反向箭头

接着再找一条从s到t的路线,重复上面的计算

继续找新路线

此时已经找不到新的路径从s到t,结束进程。

再利用公式flow = capacity - residual

 - =

既可以得出最大流5。

代码实现:

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, flowdef other_node(self, p):''' 返回边中与p相对的另一顶点 '''return self.v if p == self.w else self.wdef 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.flowdef moddify_flow(self, p, x):''' 将边的流量调整x '''if p == self.w:  # 如果 p=w,将v→w的流量增加xself.flow += xelse:  # 否则将v→w的流量减少xself.flow -= xdef __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, tdef 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('该网络不符合守恒定律')returnprint('%-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 = Gself.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, parentdef dfs(self):''' 获取网络中的一条增广路径 '''path = Nonevisited = set()  # 被访问过的顶点visited.add(self.G.s)q = []q.append(self.Node(self.G.s, None, self.G.t))tempmaxflow = 1e10while len(q):node_v = q.pop(0)v = node_v.wlabel = 0for 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_wlabel = 1breakif label == 1:  # 到达了汇点breakif path is None:tempmaxflow = 0return tempmaxflownode = pathwhile node.parent != self.G.t:  # 计算增广路径上的最小剩余量w, e = node.w, node.etempmaxflow = min(tempmaxflow, e.residual_cap_to(w))node = node.parentnode = pathwhile node.parent != self.G.t:  # 修改残存网w, e = node.w, node.ee.moddify_flow(w, tempmaxflow)node = node.parentreturn tempmaxflowdef start(self):''' 增广路径最大流算法主体方法 '''while True:tempmaxflow = self.dfs()  # 找到一条增广路径if tempmaxflow ==0:breakself.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()

Ford-Fulkerson算法的时间复杂度较高,接下来讲述一种使用较为广泛,时间复杂度低的Dinic算法。

Dinic算法

Dinic算法首先根据剩余流量图建立一个Level Graph,如下:

然后在level graph上寻找阻塞流,再将其映射回原先的residual graph中。

然后在新的residual graph中再次建立level graph图。

再寻找阻塞流,然后再映射回residual graph。如此不断循环,直到在新生成的level graph中找不到从s到t的阻塞流。

再利用公式flow = capacity - residual

-=

最大流量为19。

代码实现

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, flowdef other_node(self, p):''' 返回边中与p相对的另一顶点 '''return self.v if p == self.w else self.wdef 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.flowdef moddify_flow(self, p, x):''' 将边的流量调整x '''if p == self.w:  # 如果 p=w,将v→w的流量增加xself.flow += xelse:  # 否则将v→w的流量减少xself.flow -= xdef __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, tdef 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('该网络不符合守恒定律')returnprint('%-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 = Gself.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, parentdef 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 = 0while len(q)>1:node_v = q.pop(0)if node_v=="end":q.append("end")visited = tempvisited.copy()continuev = node_v.wfor e in self.G.edges(v):  # 遍历连接v的所有边w = e.other_node(v)  # 边的另一顶点,e的指向是v→wif 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 = 1return Network(NewE,self.G.s,self.G.t),labeldef dfs(self,NewNetwork):''' 获取网络中的一条增广路径 '''path = Nonepath2 = Nonevisited = 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 = 1e10while len(q):node_v = q.pop(0)node_v2 = q2.pop(0)v = node_v.wlabel = 0for e in NewNetwork.edges(v):  # 遍历连接v的所有边w = e.other_node(v)  # 边的另一顶点,e的指向是v→we2 = [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_wpath2 = node_w2label = 1breakif label == 1:  # 到达了汇点breakif path is None:tempmaxflow = 0return tempmaxflownode = pathwhile node.parent != self.G.t:  # 计算增广路径上的最小剩余量w, e = node.w, node.etempmaxflow = min(tempmaxflow, e.residual_cap_to(w))node = node.parentnode = path2while node.parent != self.G.t:  # 修改残存网w, e = node.w, node.ee.moddify_flow(w, tempmaxflow)node = node.parentreturn tempmaxflowdef start(self):while True:newnet,label = self.bfs()if label==0:breakwhile True:tempmaxflow = self.dfs(newnet)  # 找到一条增广路径if tempmaxflow == 0:breakself.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()

最小割算法

最小割实际上就是使用的最大流的计算结果。

最大流与最小割之间转化:将最大流的剩余容量图画出来,然后重起点s出发,将可以连在一块的设为s,另一边即为t

总结:

最大流与最小割是图论分割的基础。接下来我们将继续探讨最大流与最小割如何在图像上实现分割。例如graph cut等。

参考文献:

https://www.its203.com/article/qq_35885429/107226535

https://github.com/wangshusen/AdvancedAlgorithms

最大流与最小割(Maxflow与Mincut)相关推荐

  1. 网络流:最大流,最小割 基本概念及算法

    原文:http://www.cnblogs.com/Booble/archive/2011/03/04/1970453.html 参考:http://community.topcoder.com/tc ...

  2. 网络流中最大流和最小割算法

    学习顺序按照下图的改进历程 问题转化:寻找初始解,提升,达到条件停止 求解优化,加回溯边,画残差图,在残差图中寻找一条s可到t的路径 看最大流最小割问题,证明 除 ST外每个点的出度和入度相等,S和T ...

  3. 网络流——最大流和最小割

    最小割问题 ststst割:将节点划分为A,BA,BA,B两个集合,其中源节点s∈As\in As∈A且宿节点t∈Bt\in Bt∈B ststst割的容量:由集合AAA到集合BBB所有出边容量之和. ...

  4. 如何快速理解最大流和最小割

    摘要: 割从哪来-------->最大流和最小割之间的等价关系的阐述. 1.问题引入 1.1思考这样一个问题:在给定的图中,如何判断一个源点s到终点t是否有路径存在呢? 我们首先想到的是用BFS ...

  5. BZOJ 1001: [BeiJing2006]狼抓兔子【最大流/SPFA+最小割,多解】

    1001: [BeiJing2006]狼抓兔子 Time Limit: 15 Sec  Memory Limit: 162 MB Submit: 23822  Solved: 6012 [Submit ...

  6. Forethought Future Cup - Elimination Round G. Zoning Restrictions 最大流(最小割)

    题目链接: https://codeforces.com/contest/1146/problem/G 题意: 你现在要给 nnn 个位置制定高度 hi(1<=hi<=H)h_i (1&l ...

  7. 网络流之最大流和最小割

    最大流问题 最大流:给定有向图中每条边的最大流量(容量),求从源点到汇点的最大流量. 容量网络: 括号左边代表容量,右边代表流量. 残留网络:流网络中剩余可增加的流量 增广路:满足容量条件的一条流量不 ...

  8. 最大流,最小割刷题记录

    T1 P2057 [SHOI2007] 善意的投票 题目 https://www.luogu.com.cn/blog/OnMyOwn/OnMyOwn https://www.luogu.com.cn/ ...

  9. 最大流最小割经典例题_算法: 最大流与最小割

    什么是最大流 最大流要解决的问题是从 S 到 T 怎么才能最大地将数据运到另一边.这个"数据"可以是水,或者网络数据包.举个例子 在上面这个图中将数据从 S 运到 T,其中边的权值 ...

最新文章

  1. (011) java后台开发之泛型类
  2. python 基础学习 正则表达式1(规则)
  3. day13 Python数据基本类型
  4. int main中char** argv与char *argv[]区别?(main函数)
  5. 机器学习术语_机器学习术语神秘化。
  6. 计算机史上首篇教你从算法问题提炼算法思想的文章
  7. 阿里主管通知我试用期延期……
  8. php path separator,php 非常有用的高级函数PATH_SEPARATOR常量和set_include_path
  9. Python | 面试必问,线程与进程的区别,Python中如何创建多线程?
  10. Gsview裁剪EPS文件
  11. 【路径规划】基于matalb穷举法机器人栅格地图避障路径规划【含Matlab源码 1675期】
  12. 程序员小技巧-----如何提升电脑速度
  13. 【每天更新】2022年最新WordPress主题下载(2022-5-12)
  14. 计算机硬盘中病毒吗,硬盘中病毒能格式化吗
  15. HDU6069 Counting Divisors
  16. 根号3表白html,数字表白公式 表白套路情话
  17. 计算机文字录入培训大纲,计算机文字录入处理员教学大纲.doc
  18. 服务器域名绑定公网IP地址
  19. 在线查看相机快门次数_我是亲民_新浪博客
  20. 音视频基础学习之【07.仿优酷界面的UI设计】

热门文章

  1. Matplotlib绘制图片——膨胀算法
  2. Android 中获取网络下载速率的方法
  3. 20本必读的用户体验书目
  4. oracle中调用过程,oracle中如何调用存储过程
  5. ios 事件穿透的原因和解决方法
  6. 下载Intell IDea
  7. 【JavaScript 教程】第六章 数组18—push() :将一个或多个元素添加到数组的末尾...
  8. Logistics回归模型
  9. VAO 与 VBO 的前世今生
  10. 《规范》前端编码规范