def segmentation(self): self.K = TreeModel() self.K_to_P = defaultdict(list) # ki -> list of (i, d)'s self.P_to_K = {} # pi -> (ki, d) self.level_to_graph = [None for _ in range(len(self.level_sets))] self.level_to_segment_graphs = [None for _ in range(len(self.level_sets))] for level, points in self.level_sets.items(): N_level_inter = self.N.subgraph(points) segment_nodes_list = nx.connected_components(N_level_inter) self.level_to_graph[level] = N_level_inter self.level_to_segment_graphs[level] = \ nx.connected_component_subgraphs(N_level_inter) for segment_nodes in segment_nodes_list: segment_centroid = harray(mean(self.P[[segment_nodes]], axis=0)) node = self.K.add_node(pos=segment_centroid, points=set(segment_nodes), level=level) max_dist = float('-inf') avg_dist = 0 for j in segment_nodes: d = dist(segment_centroid, self.P[j]) max_dist = max(max_dist, d) avg_dist += d self.K_to_P[node.id].append((j, d)) assert j not in self.P_to_K self.P_to_K[j] = (node.id, d) # initial radius estimation (can be refined with # volume_reconstruction) avg_dist /= len(segment_nodes) node.radius = avg_dist
def compute_nearest_neighbors_in_radius(self, r): start = time.time() kdtree1 = KDTree(self.P) kdtree2 = KDTree(self.P) result = kdtree1.query_ball_tree(kdtree2, r) self.N_full = nx.Graph() for i, i_nns in enumerate(result): for j in i_nns: if i == j: continue d = dist(self.P[i], self.P[j]) self.N_full.add_edge(i, j, weight=d) print time.time() - start print len(self.N_full.edges()) self.find_nn_connected_components()
def segmentation(self): self.K = TreeModel() self.K_to_P = defaultdict(list) # ki -> list of (i, d)'s self.P_to_K = {} # pi -> (ki, d) self.level_to_graph = [None for _ in range(len(self.level_sets))] self.level_to_segment_graphs = [ None for _ in range(len(self.level_sets)) ] for level, points in self.level_sets.items(): N_level_inter = self.N.subgraph(points) segment_nodes_list = nx.connected_components(N_level_inter) self.level_to_graph[level] = N_level_inter self.level_to_segment_graphs[level] = \ nx.connected_component_subgraphs(N_level_inter) for segment_nodes in segment_nodes_list: segment_centroid = harray(mean(self.P[[segment_nodes]], axis=0)) node = self.K.add_node(pos=segment_centroid, points=set(segment_nodes), level=level) max_dist = float('-inf') avg_dist = 0 for j in segment_nodes: d = dist(segment_centroid, self.P[j]) max_dist = max(max_dist, d) avg_dist += d self.K_to_P[node.id].append((j, d)) assert j not in self.P_to_K self.P_to_K[j] = (node.id, d) # initial radius estimation (can be refined with # volume_reconstruction) avg_dist /= len(segment_nodes) node.radius = avg_dist
def volume_reconstruction(self): for ki in self.K: if not self.K[ki].children: kj = ki while self.K[kj].parent is not None: kj_start_points = self.level_start_points[self.K[kj].level] \ & self.K[kj].points # if not, will use initial radius estimation (not good!) if kj_start_points: kj_to_parent_midpoint = mean( (self.K[kj].pos, self.K[self.K[kj].parent].pos), axis=0) radius = 0 for pi in kj_start_points: radius += dist(self.P[pi], kj_to_parent_midpoint) radius /= len(kj_start_points) self.K[kj].radius = radius kj = self.K[kj].parent # segment radius smoothing roots = set() for ki in self.K: if not self.K[ki].children: segment = {} # kj -> radius kj = ki while self.K[kj].parent is not None: segment[kj] = self.K[kj].radius if len(self.K[kj].children) > 1 or \ self.K[self.K[kj].parent].parent is None: # flush segment avg_segment_radius = sum( segment.values()) / len(segment) for kk in segment: self.K[kk].radius = avg_segment_radius segment = {} kj = self.K[kj].parent if self.K[ki].parent is None: roots.add(ki) # roots radius #print 'roots: %s' % roots for ki in roots: #assert self.K[ki].get('radius', None) is None rad = 0 for kj in self.K[ki].children: rad += self.K[kj].radius rad /= len(self.K[ki].children) self.K[ki].radius = rad # decreasing radius smoothing need_smoothing = True while need_smoothing: need_smoothing = False for ki in self.K: if not self.K[ki].children: kj = ki prev_radius = None while self.K[kj].parent is not None: curr_radius = self.K[kj].radius next_radius = self.K[self.K[kj].parent].radius if curr_radius > next_radius: need_smoothing = True if prev_radius: curr_radius = (prev_radius + next_radius) / 2 else: curr_radius = next_radius curr_radius -= (0.01 * curr_radius) self.K[kj].radius = curr_radius prev_radius = curr_radius kj = self.K[kj].parent
def skeleton_reconstruction(self, use_greedy_search=True, extend_end_segments=True): for k in self.K: if self.K[k].level == 0: continue potential_k_parents = [] # list of (dist, potential_k_parent)'s found_k_parent = False for i, dist_ki in self.K_to_P[k]: # travel from k toward source, via one of its belonging paths for j in self.shortest_paths[i][::-1]: if j not in self.P_to_K: continue l, dist_lj = self.P_to_K[j] if self.K[l].level >= self.K[k].level: continue dist_kl = dist(self.K[k].pos, self.K[l].pos) cost = dist_ki + dist_kl + dist_lj potential_k_parents.append((cost, l)) if use_greedy_search: # for full search (takes really longer), # comment out these two lines (not sure it # makes sense though!) found_k_parent = True break if found_k_parent: break #assert potential_k_parents if not potential_k_parents: print "warning: couldn't find a parent for skeleton node %s" % k continue k_parent = sorted(potential_k_parents)[0][1] self.K[k].parent = k_parent self.K[k_parent].children.add(k) self.K.remove_orphan_nodes() if extend_end_segments: # more precise method, derived from: # http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html for k, node in self.K.items(): if not node.children: # find point with max dist from source p_max_dist = [float('-inf'), None] for i in node.points: if self.P_dist[i] > p_max_dist[0]: p_max_dist[0] = self.P_dist[i] p_max_dist[1] = i p_max_dist = self.P[p_max_dist[1]] x1 = self.K[node.parent].pos x2 = node.pos x0 = p_max_dist s = -dot((x1 - x0), (x2 - x1)) / (linalg.norm(x2 - x1)**2) v = x1 + (x2 - x1) * s self.K[k].pos = v if node.parent is None: p_min_dist = [float('inf'), None] # should be the src point? for i in node.points: if self.P_dist[i] < p_min_dist[0]: p_min_dist[0] = self.P_dist[i] p_min_dist[1] = i p_min_dist = self.P[p_min_dist[1]] first_child_k = list(node.children)[0] x1 = self.K[first_child_k].pos x2 = node.pos x0 = p_min_dist s = -dot((x1 - x0), (x2 - x1)) / (linalg.norm(x2 - x1)**2) v = x1 + (x2 - x1) * s self.K[k].pos = v
def volume_reconstruction(self): for ki in self.K: if not self.K[ki].children: kj = ki while self.K[kj].parent is not None: kj_start_points = self.level_start_points[self.K[kj].level] \ & self.K[kj].points # if not, will use initial radius estimation (not good!) if kj_start_points: kj_to_parent_midpoint = mean((self.K[kj].pos, self.K[self.K[kj].parent].pos), axis=0) radius = 0 for pi in kj_start_points: radius += dist(self.P[pi], kj_to_parent_midpoint) radius /= len(kj_start_points) self.K[kj].radius = radius kj = self.K[kj].parent # segment radius smoothing roots = set() for ki in self.K: if not self.K[ki].children: segment = {} # kj -> radius kj = ki while self.K[kj].parent is not None: segment[kj] = self.K[kj].radius if len(self.K[kj].children) > 1 or \ self.K[self.K[kj].parent].parent is None: # flush segment avg_segment_radius = sum(segment.values()) / len(segment) for kk in segment: self.K[kk].radius = avg_segment_radius segment = {} kj = self.K[kj].parent if self.K[ki].parent is None: roots.add(ki) # roots radius #print 'roots: %s' % roots for ki in roots: #assert self.K[ki].get('radius', None) is None rad = 0 for kj in self.K[ki].children: rad += self.K[kj].radius rad /= len(self.K[ki].children) self.K[ki].radius = rad # decreasing radius smoothing need_smoothing = True while need_smoothing: need_smoothing = False for ki in self.K: if not self.K[ki].children: kj = ki prev_radius = None while self.K[kj].parent is not None: curr_radius = self.K[kj].radius next_radius = self.K[self.K[kj].parent].radius if curr_radius > next_radius: need_smoothing = True if prev_radius: curr_radius = (prev_radius + next_radius) / 2 else: curr_radius = next_radius curr_radius -= (0.01 * curr_radius) self.K[kj].radius = curr_radius prev_radius = curr_radius kj = self.K[kj].parent
def skeleton_reconstruction(self, use_greedy_search=True, extend_end_segments=True): for k in self.K: if self.K[k].level == 0: continue potential_k_parents = [] # list of (dist, potential_k_parent)'s found_k_parent = False for i, dist_ki in self.K_to_P[k]: # travel from k toward source, via one of its belonging paths for j in self.shortest_paths[i][::-1]: if j not in self.P_to_K: continue l, dist_lj = self.P_to_K[j] if self.K[l].level >= self.K[k].level: continue dist_kl = dist(self.K[k].pos, self.K[l].pos) cost = dist_ki + dist_kl + dist_lj potential_k_parents.append((cost, l)) if use_greedy_search: # for full search (takes really longer), # comment out these two lines (not sure it # makes sense though!) found_k_parent = True break if found_k_parent: break #assert potential_k_parents if not potential_k_parents: print "warning: couldn't find a parent for skeleton node %s" % k continue k_parent = sorted(potential_k_parents)[0][1] self.K[k].parent = k_parent self.K[k_parent].children.add(k) self.K.remove_orphan_nodes() if extend_end_segments: # more precise method, derived from: # http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html for k, node in self.K.items(): if not node.children: # find point with max dist from source p_max_dist = [float('-inf'), None] for i in node.points: if self.P_dist[i] > p_max_dist[0]: p_max_dist[0] = self.P_dist[i] p_max_dist[1] = i p_max_dist = self.P[p_max_dist[1]] x1 = self.K[node.parent].pos x2 = node.pos x0 = p_max_dist s = -dot((x1 - x0), (x2 - x1)) / (linalg.norm(x2 - x1) ** 2) v = x1 + (x2 - x1) * s self.K[k].pos = v if node.parent is None: p_min_dist = [float('inf'), None] # should be the src point? for i in node.points: if self.P_dist[i] < p_min_dist[0]: p_min_dist[0] = self.P_dist[i] p_min_dist[1] = i p_min_dist = self.P[p_min_dist[1]] first_child_k = list(node.children)[0] x1 = self.K[first_child_k].pos x2 = node.pos x0 = p_min_dist s = -dot((x1 - x0), (x2 - x1)) / (linalg.norm(x2 - x1) ** 2) v = x1 + (x2 - x1) * s self.K[k].pos = v