def solve_iterative(W, iterations=10): """Find an approximate minimizer of (x.T * W * x) for x_i in {-1, 1}. Args: W: matrix of weights. iterations: number of iterations of finding submodular sub-matrices and solving them in random order. Returns: vector x of {-1, 1}. See Algorithm 1 from Zhuang et al. http://arxiv.org/abs/1603.02844 """ # ignore the diagonal, and symmetrize W = W.copy() W.setdiag(0) W = (W + W.T) / 2 num_elements = W.shape[0] # initial guess of all 1s current_labels = 0 * (np.random.randint(2, size=num_elements) * 2 - 1) for _ in range(iterations): for sub_W, active_indices in generate_submodular(W): sub_W = sub_W.astype(np.float32) # pymaxflow compatibility num_active = len(active_indices) print("solve", active_indices, "\n", sub_W) # We are solving for active_indices. # All others are held fixed. # These are the costs relative to the labels we are holding fixed. costs_wrt_fixed = W.dot(current_labels)[active_indices] print("costs", costs_wrt_fixed) costs_wrt_fixed = costs_wrt_fixed.astype(np.float32) # pymaxflow compatibility # split into positive and negative pieces pos_costs_wrt_fixed = costs_wrt_fixed.copy() neg_costs_wrt_fixed = - costs_wrt_fixed pos_costs_wrt_fixed[pos_costs_wrt_fixed < 0] = 0 neg_costs_wrt_fixed[neg_costs_wrt_fixed < 0] = 0 # set up a graphcut problem for this sub_W. # source = 1, sink = -1 (later mapped to 0). # Costs should be mapped to cuts. # # source == 1 # | # | cost of A == -1 (neg_costs_wrt_fixed) # | # A # | # | cost of A == 1 (pos_costs_wrt_fixed) # | # sink == -1 g = pymaxflow.PyGraph(num_active, num_active ** 2) g.add_node(num_active) # add max capacity to ensure flow is possible. (I'm not sure this is necessary.) g.add_tweights_vectorized(np.arange(num_active, dtype=np.int32), 2 * neg_costs_wrt_fixed, # source capacity 2 * pos_costs_wrt_fixed) # sink capacity # add edges between labels row, col = np.nonzero(sub_W) # multiply by -2 because: # if labels i,j are the same, score += W[i, j] # if labels i,j are different (i.e., 1 & -1), score -= W[i, j] # relative cost of separating vs. not = -2 * W[i, j] vals = -2 * sub_W[row, col] assert np.all(vals >= 0) g.add_edge_vectorized(row.astype(np.int32), col.astype(np.int32), vals, vals) g.maxflow() out = (g.what_segment_vectorized() == pymaxflow.SOURCE) * 2 - 1 print("res", out) # validate solution best = np.inf for possible in itertools.product([-1, 1], repeat=num_active): v = np.array(possible) e = sub_W.dot(v).dot(v) + costs_wrt_fixed.dot(v) if e < best: best_v = v best = e print("best", best_v, best) # set active labels to new configuration current_labels[active_indices] = out print ("NEW", best_v, active_indices, current_labels) print("") print ("C", current_labels, W.dot(current_labels).dot(current_labels)) return (current_labels + 1) / 2
def create_graph(vertices_count, edges_count): return pymaxflow.PyGraph(vertices_count, edges_count)
def graphCutSegment(costs_class0,costs_class1,imlabelsBinary): H=costs_class0.shape[0] W=costs_class0.shape[1] nbpixels=H*W # -----------------------Segmentation method using regional data term and constant edge cost------------------------------- g = pymaxflow.PyGraph(nbpixels,nbpixels * 2) g.add_node(nbpixels) # TODO # encode unary term of the energy in slide 25 (sum_p Dp(fp) +sum_pq Vqp(fq,fp)) # by adding arcs in the graph by calling the function g.add_tweights_vectorized # this function allows to add arcs between nodes and the source node s and a the sink node t (oriented as source->node and node->target) # g.add_tweights_vectorized(indices_nodes,costs_arcs_from_s_to_nodes,costs_arcs_from_nodes_to_t) # with indices_nodes,costs_arcs_from_s_to_nodes,costs_arcs_from_nodes_to_t vector whose lenght is the number of pixels # WARNING, in the contrary to the slide 24 , the pymaxflow code seems to use the convention # that s is in the set of node with labels 0 and t is in the set of node with labels 1 # look at the graph slide 24 to see how to go from Dp(0) and Dp(1) to the arc weights keeping # in mind that pymaxflow use a opposite convention # make sure that indices_nodes,costs_arcs_to_s and costs_arcs_to_t are vectors of the same size # otherwise will get an assertion error # Note :the unvectorized version is documented in the graph.h file un pymaxflow #indices =? #costs_arcs_from_s_to_nodes= ? #costs_arcs_from_nodes_to_t= ? g.add_tweights_vectorized(indices.astype(np.int32),costs_arcs_from_s_to_nodes.astype(np.float32),costs_arcs_from_nodes_to_t.astype(np.float32)) #We check that the minimization of this energy without extra node gives back the same labels as imlabelsBinary print("calling maxflow") g.maxflow() out = g.what_segment_vectorized() imlabels2=out.reshape((H,W)) assert(np.all(imlabelsBinary==imlabels2)) # TODO # encode binary terms of the energy in slide 25 (sum_p Dp(fp) +sum_pq Vqp(fq,fp)) # by considering first horizontal edges between neighboring pixels then vertical edges # you add oriented arcs in the graph between nodes by calling the function g.add_edge_vectorized # g.add_edge_vectorized(indices_node_i,indices_node_j,weight_arc_i_to_j,weight_arc_j_to_i) # in our case we use weight_arc_i_to_j=weight_arc_i_to_j=alpha # first create a matrix indices = np.arange(nbpixels) .reshape(H,W) an use # then use submaxtrices extracted from indices then flattened to create indices_node_i and indices_node_j # Note : you can have a look on the example in test.py in the pymaxflow directory alpha=0.1 #------ adding horizontal edges------ indices = np.arange(nbpixels) .reshape(H,W).astype(np.int32) #indices_node_i = ? #indices_node_j = ? #cost_diff= ? g.add_edge_vectorized(indices_node_i, indices_node_j, cost_diff ,cost_diff) #------ adding vertical edges------ #indices_node_i = ? #indices_node_j = ? #cost_diff=n ? g.add_edge_vectorized(indices_node_i, indices_node_j, cost_diff, cost_diff) # Getting the result image print("calling maxflow") g.maxflow() out = g.what_segment_vectorized() imlabelsGC=out.reshape((H,W)) return imlabelsGC
center_coords] += gap_completion_distances[:, :, di2][ intermediate_coords] di2reverse = (di2 + 4) % 8 inflow_smooth[ center_coords] += smooth_distances[:, :, di2reverse][ exterior_coords] inflow_gap[ center_coords] += gap_completion_distances[:, :, di2reverse][ exterior_coords] for smoothing_factor in smoothing_factors: for gap_completion_factor in gap_completion_factors: with timer.Timer("setup"): flow_graph = pymaxflow.PyGraph( terminal_matrix_prob.shape[0], 8 * terminal_matrix_prob.shape[0]) flow_graph.add_node(terminal_matrix_prob.shape[0]) ## Load the terminal matrix terminal_matrix = terminal_matrix_prob + \ terminal_matrix_smooth * smoothing_factor + \ terminal_matrix_gap_completion * gap_completion_factor flow_graph.add_tweights_vectorized( node_indices.ravel(), terminal_matrix[:, 0].ravel(), terminal_matrix[:, 1].ravel()) # compute the source/sink difference for the nodes source_sink_cap = terminal_matrix[:,0].flatten() - \
import sys import pymaxflow import pylab import numpy as np eps = 0.01 im = pylab.imread(sys.argv[1]).astype(np.float32) indices = np.arange(im.size).reshape(im.shape).astype(np.int32) g = pymaxflow.PyGraph(im.size, im.size * 3) g.add_node(im.size) # adjacent diffs = np.abs(im[:, 1:] - im[:, :-1]).ravel() + eps e1 = indices[:, :-1].ravel() e2 = indices[:, 1:].ravel() g.add_edge_vectorized(e1, e2, diffs, 0 * diffs) # adjacent up diffs = np.abs(im[1:, 1:] - im[:-1, :-1]).ravel() + eps e1 = indices[1:, :-1].ravel() e2 = indices[:-1, 1:].ravel() g.add_edge_vectorized(e1, e2, diffs, 0 * diffs) # adjacent down diffs = np.abs(im[:-1, 1:] - im[1:, :-1]).ravel() + eps e1 = indices[:-1, :-1].flatten() e2 = indices[1:, 1:].ravel() g.add_edge_vectorized(e1, e2, diffs, 0 * diffs)