计算边的代码如下:
def create_edge(img, width, x, y, x1, y1, diff):
vertex_id = lambda x, y: y * width + x
w = diff(img, x, y, x1, y1)
return (vertex_id(x, y), vertex_id(x1, y1), w)
def build_graph(img, width, height, diff, neighborhood_8=False):
# 列表里存放两个节点的id以及距离,例如:(0,1,2.5)
graph_edges = []
# y的取值范围为0~height-1
for y in range(height):
for x in range(width):
# 当y=0时,也就是像素矩阵的第一行,此时计算的是第一行两两像素之间的diff
if x > 0:
graph_edges.append(create_edge(img, width, x, y, x-1, y, diff))
if y > 0:
graph_edges.append(create_edge(img, width, x, y, x, y-1, diff))
if neighborhood_8:
if x > 0 and y > 0:
graph_edges.append(create_edge(img, width, x, y, x-1, y-1, diff))
if x > 0 and y < height-1:
graph_edges.append(create_edge(img, width, x, y, x-1, y+1, diff))
return graph_edges
这段代码主要是用于求图中每个节点之间的距离,x的取值是从0~width-1,y同理。
当y=0,也就是对应于图像像素的第一行,此时计算的是第一行两两像素之间的距离,这里要注意一点,当x和y的值都取0,就是图形矩阵的第一个位置(0,0)时,循环体是不执行任何操作的,也就是计算从(0,1)位置的像素开始,计算(0,1)和(0,0)的距离,(0,2)和(0,1)之间的距离,直到最后一个像素和前一个像素的距离。
当y>0,也就是从图像像素矩阵的第二行开始,计算每个像素和它上方还有左方像素的距离,注意,对于(1,0)来说,左边是没有像素的,此时只计算(1,0)和它上方的像素(0,0)的距离,(1,1)就计算和(0,1)、(1,0)的距离。
如下图:
# const=K
def segment_graph(graph_edges, num_nodes, const, min_size, threshold_func):
# Step 1: initialization
# 初始化一个节点列表,列表存放节点对象
forest = Forest(num_nodes)
# edge[2]为之前的graph_edge列表中的元素(0,1,2.5)的第三个值,也就是距离
weight = lambda edge: edge[2]
# 用像素之间的距离值进行排序
sorted_graph = sorted(graph_edges, key=weight)
# threshold用于调整某个区域内的差异值
threshold = [ threshold_func(1, const) for _ in range(num_nodes) ]
# Step 2: merging
# edge=(0,1,2.5),也就是id为0的节点与id为1的节点之间的距离为2.5
for edge in sorted_graph:
# 寻找id_0的母节点(一开始为它本身)
parent_a = forest.find(edge[0])
parent_b = forest.find(edge[1])
#如果两节点的差距小于它们区域内的差距阈值
a_condition = weight(edge) <= threshold[parent_a]
b_condition = weight(edge) <= threshold[parent_b]
if parent_a != parent_b and a_condition and b_condition:
forest.merge(parent_a, parent_b)
a = forest.find(parent_a)
threshold[a] = weight(edge) + threshold_func(forest.nodes[a].size, const)
return remove_small_components(forest, sorted_graph, min_size)
def remove_small_components(forest, graph, min_size):
for edge in graph:
a = forest.find(edge[0])
b = forest.find(edge[1])
if a != b and (forest.size_of(a) < min_size or forest.size_of(b) < min_size):
forest.merge(a, b)
return forest
# random()返回一个0~1之间的数
def generate_image(forest, width, height):
# 返回一个RGB像素列表,每个像素的RGB值随机
random_color = lambda: (int(random()*255), int(random()*255), int(random()*255))
colors = [random_color() for i in range(width*height)]
# 创建一个宽度为width,高度为height的黑色图像
img = Image.new('RGB', (width, height))
#返回img的每个像素值,可以用来修改img的像素值
im = img.load()
# 过程为,比如x=y=0时,对应id为0的像素,先给它随机赋予一个RGB值
# 当y=0,x=1时,对应id为1的像素,假设它父母为0(两者一个区域),则im(1,0)=im(0,0),也就时赋予它和0号相同的RGB值
for y in range(height):
for x in range(width):
comp = forest.find(y * width + x)
im[x, y] = colors[comp]
return img.transpose(Image.ROTATE_270).transpose(Image.FLIP_LEFT_RIGHT)
基于图的图像分割原理参考的文章:
https://blog.csdn.net/surgewong/article/details/39008861