Image Segmentation Source Parsing Based on Graph

Posted by Tbull on Thu, 07 Nov 2019 20:26:03 +0100

The code to calculate the edge is as follows:

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):
# The list contains the IDS and distances of two nodes, for example: (0,1,2.5)
    graph_edges = []
    # y ranges from 0 to height-1
    for y in range(height):
        for x in range(width):
            # When y=0, which is the first row of the pixel matrix, the diff between the first row and the two pixels is calculated
            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

This code is mainly used to find the distance between each node in the graph. The value of x is from 0 to width-1, and y is the same.
When y=0, the first row corresponding to the image pixel, the distance between the first row and the two pixels is calculated. It is important to note that when the x and Y values are both 0, which is the first position (0, 0) of the graphics matrix, the loop does nothing, that is, calculates the distance between (0, 1) and (0, 0) starting from the pixel at (0, 1).The distance between (0, 2) and (0, 1) until the last and previous pixels.
When y>0, which is the second row of the image pixel matrix, calculates the distance between each pixel and the left pixel above it. Note that for (1, 0), there is no pixel on the left, and only the distance between (1, 0) and the pixel above it (0, 0), (1, 1) the distance between (0, 1), (1, 0) is calculated.
As follows:

# const=K
def segment_graph(graph_edges, num_nodes, const, min_size, threshold_func):
    # Step 1: initialization
    # Initialize a list of nodes to hold node objects
    forest = Forest(num_nodes)
    # edge[2] is the third value of the element (0,1,2.5) in the previous graph_edge list, that is, distance
    weight = lambda edge: edge[2]
    # Sort by distance between pixels
    sorted_graph = sorted(graph_edges, key=weight)
    # Thresholds are used to adjust for differences within an area
    threshold = [ threshold_func(1, const) for _ in range(num_nodes) ]
    # Step 2: merging
    # edge=(0,1,2.5), that is, the distance between a node with id 0 and a node with id 1 is 2.5
    for edge in sorted_graph:
        # Find the parent node of id_0 (starting with itself)
        parent_a = forest.find(edge[0])
        parent_b = forest.find(edge[1])
        #If the gap between two nodes is less than the gap threshold within their region
        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() returns a number between 0 and 1
def generate_image(forest, width, height):
    # Returns a list of RGB pixels with random RGB values for each pixel
    random_color = lambda: (int(random()*255), int(random()*255), int(random()*255))
    colors = [random_color() for i in range(width*height)]    
    # Create a black image with width and height of height
    img = Image.new('RGB', (width, height))
    #Returns each pixel value of the img, which can be used to modify the pixel value of the img
    im = img.load()
    # When the process is, for example, x=y=0, the corresponding pixel with id 0 is randomly assigned an RGB value first
    # When y=0, x=1, the corresponding id is 1 pixel, assuming that its parent is 0 (one area of both), im(1,0)=im(0,0), which gives it the same RGB value as 0.
    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)

Articles for reference on the principles of image segmentation based on graphs:
https://blog.csdn.net/surgewong/article/details/39008861

Topics: Lambda less