在用深度学习做完肿瘤分割后,因为需要对比实验,所以当时(2019-4-13)在传统方法里找到过Felzen的Graph-Based Segmentation,而且那个时候还混淆了Graph-Cut分割和Graph-Based分割,因为看名字以为Graph-Based segmentation是一个大的类别,其实并不是。
当时虽然也学习了关于这个分割算法的知识,但是流于形式,一下就忘了,仅用python里的sklearn包两句话实现了分割,分割后的结果表现为超像素,并不是我需要的,所以不了了之。时隔一个多月,再次因为项目需要借用学姐的代码去分割肝脏,去重新学习这个算法。现在竟然不知不觉对同一个东西有了新的理解高度,虽然说相对于其他人来说可能早就知道这些算法了,但自己相比较与过去有了进步,光这点来说,都是我继续坚持下的动力。
这篇还未写完,最近很多杂事,过段时间来补充,文中若有错误,望指出。
概念总结:
这些概念的依赖关系对于我自己理解而言还挺重要的,自底向上理解与实践会更加透彻,所以代码的实现会依次包括如下:(注:这些实现均不是我自己写的,来自于github与教学网站)
1、检测图中是否有回路(两种实现方式,DFS与Union-Find)
2、MST算法
3、Graph-Based segmentation
4、Selective-Search
为了避免篇幅过长,本文 python实现(一),将实现detect cycle
(一)DFS 实现 detect graph cycle
# Python program to detect cycle
# in a graph
from collections import defaultdict
class Graph():
def __init__(self,vertices):
self.graph = defaultdict(list)
self.V = vertices
def addEdge(self,u,v):
self.graph[u].append(v)
def isCyclicUtil(self, v, visited, recStack):
# Mark current node as visited and
# adds to recursion stack
visited[v] = True #自己理解,若自己输入的边没有重复或错误时,该结构可以不要
recStack[v] = True # 自己理解为当前搜索路径上的临时栈
# Recur for all neighbours
# if any neighbour is visited and in
# recStack then graph is cyclic
for neighbour in self.graph[v]:
if visited[neighbour] == False:
if self.isCyclicUtil(neighbour, visited, recStack) == True:
return True
elif recStack[neighbour] == True:
return True
# The node needs to be poped from
# recursion stack before function ends
recStack[v] = False
return False
# Returns true if graph is cyclic else false
def isCyclic(self):
visited = [False] * self.V
recStack = [False] * self.V
for node in range(self.V):
if visited[node] == False:
if self.isCyclicUtil(node,visited,recStack) == True:
return True
return False
g = Graph(4)
g.addEdge(0, 1)
g.addEdge(0, 2)
g.addEdge(1, 2)
g.addEdge(2, 0)
g.addEdge(2, 3)
g.addEdge(3, 3)
if g.isCyclic() == 1:
print("Graph has a cycle")
else:
print("Graph has no cycle")
(二)朴素版 Disjoint-Set(Union-Find) 实现 detect graph cycle
注:Disjoint-Set(或者叫做Union-Find)其实只是一种数据结构
# Python Program for union-find algorithm to detect cycle in a undirected graph
# we have one egde for any two vertex i.e 1-2 is either 1-2 or 2-1 but not both
from collections import defaultdict
#This class represents a undirected graph using adjacency list representation
class Graph:
def __init__(self,vertices):
self.V= vertices #No. of vertices
self.graph = defaultdict(list) # default dictionary to store graph
# function to add an edge to graph
def addEdge(self,u,v):
self.graph[u].append(v)
# A utility function to find the subset of an element i
def find_parent(self, parent,i):
if parent[i] == -1:
return i
if parent[i]!= -1:
return self.find_parent(parent,parent[i])
# A utility function to do union of two subsets
def union(self,parent,x,y):
x_set = self.find_parent(parent, x)
y_set = self.find_parent(parent, y)
parent[x_set] = y_set
# The main function to check whether a given graph
# contains cycle or not
def isCyclic(self):
# Allocate memory for creating V subsets and
# Initialize all subsets as single element sets
parent = [-1]*(self.V)
# Iterate through all edges of graph, find subset of both
# vertices of every edge, if both subsets are same, then
# there is cycle in graph.
for i in self.graph:
for j in self.graph[i]:
x = self.find_parent(parent, i)
y = self.find_parent(parent, j)
if x == y:
return True
self.union(parent,x,y)
# Create a graph given in the above diagram
g = Graph(3)
g.addEdge(0, 1)
g.addEdge(1, 2)
g.addEdge(2, 0)
if g.isCyclic():
print("Graph contains cycle")
else :
print("Graph does not contain cycle ")
(二)优化版 Disjoint-Set(Union-Find) 实现 detect graph cycle
通过union-by-rank和path compression实现优化,
union-by-rank可以解决树的构建过程中degenerate成线性的问题,
path compression则是在查找的过程中将第n层子树直接赋值给父节点,减少下次查找同样的节点其时间开销
# A union by rank and path compression based
# program to detect cycle in a graph
from collections import defaultdict
# a structure to represent a graph
class Graph:
def __init__(self, num_of_v):
self.num_of_v = num_of_v
self.edges = defaultdict(list)
# graph is represented as an
# array of edges
def add_edge(self, u, v):
self.edges[u].append(v)
class Subset:
def __init__(self, parent, rank):
self.parent = parent
self.rank = rank
# A utility function to find set of an element
# node(uses path compression technique)
def find(subsets, node):
if subsets[node].parent != node:
# 这儿赋值就是path compression,可以flatten tree
subsets[node].parent = find(subsets, subsets[node].parent)
return subsets[node].parent
# A function that does union of two sets
# of u and v(uses union by rank)
def union(subsets, u, v):
# Attach smaller rank tree under root
# of high rank tree(Union by Rank)
# union-by-rank
if subsets[u].rank > subsets[v].rank:
subsets[v].parent = u
elif subsets[v].rank > subsets[u].rank:
subsets[u].parent = v
# If ranks are same, then make one as
# root and increment its rank by one
else:
subsets[v].parent = u
subsets[u].rank += 1
# The main function to check whether a given
# graph contains cycle or not
def isCycle(graph):
# Allocate memory for creating sets
subsets = []
for u in range(graph.num_of_v):
subsets.append(Subset(u, 0))
# Iterate through all edges of graph,
# find sets of both vertices of every
# edge, if sets are same, then there
# is cycle in graph.
for u in graph.edges:
u_rep = find(subsets, u)
for v in graph.edges[u]:
v_rep = find(subsets, v)
if u_rep == v_rep:
return True
else:
union(subsets, u_rep, v_rep)
# Driver Code
g = Graph(3)
# add edge 0-1
g.add_edge(0, 1)
# add edge 1-2
g.add_edge(1, 2)
# add edge 0-2
g.add_edge(0, 2)
if isCycle(g):
print('Graph contains cycle')
else:
print('Graph does not contain cycle')
# This code is contributed by
# Sampath Kumar Surine