def make_neuron_graph(self, skeleton, skeleton_labels, trunks, branchpoints, endpoints, image): '''Make a table that captures the graph relationship of the skeleton skeleton - binary skeleton image + outline of seed objects skeleton_labels - labels matrix of skeleton trunks - binary image with trunk points as 1 branchpoints - binary image with branchpoints as 1 endpoints - binary image with endpoints as 1 image - image for intensity measurement returns two tables. Table 1: edge table The edge table is a numpy record array with the following named columns in the following order: v1: index into vertex table of first vertex of edge v2: index into vertex table of second vertex of edge length: # of intermediate pixels + 2 (for two vertices) total_intensity: sum of intensities along the edge Table 2: vertex table The vertex table is a numpy record array: i: I coordinate of the vertex j: J coordinate of the vertex label: the vertex's label kind: kind of vertex = "T" for trunk, "B" for branchpoint or "E" for endpoint. ''' i, j = np.mgrid[0:skeleton.shape[0], 0:skeleton.shape[1]] # # Give each point of interest a unique number # points_of_interest = trunks | branchpoints | endpoints number_of_points = np.sum(points_of_interest) # # Make up the vertex table # tbe = np.zeros(points_of_interest.shape, '|S1') tbe[trunks] = 'T' tbe[branchpoints] = 'B' tbe[endpoints] = 'E' i_idx = i[points_of_interest] j_idx = j[points_of_interest] poe_labels = skeleton_labels[points_of_interest] tbe = tbe[points_of_interest] vertex_table = { self.VF_I: i_idx, self.VF_J: j_idx, self.VF_LABELS: poe_labels, self.VF_KIND: tbe } # # First, break the skeleton by removing the branchpoints, endpoints # and trunks # broken_skeleton = skeleton & (~points_of_interest) # # Label the broken skeleton: this labels each edge differently # edge_labels, nlabels = morph.label_skeleton(skeleton) # # Reindex after removing the points of interest # edge_labels[points_of_interest] = 0 if nlabels > 0: indexer = np.arange(nlabels + 1) unique_labels = np.sort(np.unique(edge_labels)) nlabels = len(unique_labels) - 1 indexer[unique_labels] = np.arange(len(unique_labels)) edge_labels = indexer[edge_labels] # # find magnitudes and lengths for all edges # magnitudes = fix( scind.sum(image, edge_labels, np.arange(1, nlabels + 1, dtype=np.int32))) lengths = fix( scind.sum(np.ones(edge_labels.shape), edge_labels, np.arange(1, nlabels + 1, dtype=np.int32))).astype(int) else: magnitudes = np.zeros(0) lengths = np.zeros(0, int) # # combine the edge labels and indexes of points of interest with padding # edge_mask = edge_labels != 0 all_labels = np.zeros(np.array(edge_labels.shape) + 2, int) all_labels[1:-1, 1:-1][edge_mask] = edge_labels[edge_mask] + number_of_points all_labels[i_idx + 1, j_idx + 1] = np.arange(1, number_of_points + 1) # # Collect all 8 neighbors for each point of interest # p1 = np.zeros(0, int) p2 = np.zeros(0, int) for i_off, j_off in ((0, 0), (0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1), (2, 2)): p1 = np.hstack((p1, np.arange(1, number_of_points + 1))) p2 = np.hstack((p2, all_labels[i_idx + i_off, j_idx + j_off])) # # Get rid of zeros which are background # p1 = p1[p2 != 0] p2 = p2[p2 != 0] # # Find point_of_interest -> point_of_interest connections. # p1_poi = p1[(p2 <= number_of_points) & (p1 < p2)] p2_poi = p2[(p2 <= number_of_points) & (p1 < p2)] # # Make sure matches are labeled the same # same_labels = ( skeleton_labels[i_idx[p1_poi - 1], j_idx[p1_poi - 1]] == skeleton_labels[i_idx[p2_poi - 1], j_idx[p2_poi - 1]]) p1_poi = p1_poi[same_labels] p2_poi = p2_poi[same_labels] # # Find point_of_interest -> edge # p1_edge = p1[p2 > number_of_points] edge = p2[p2 > number_of_points] # # Now, each value that p2_edge takes forms a group and all # p1_edge whose p2_edge are connected together by the edge. # Possibly they touch each other without the edge, but we will # take the minimum distance connecting each pair to throw out # the edge. # edge, p1_edge, p2_edge = morph.pairwise_permutations(edge, p1_edge) indexer = edge - number_of_points - 1 lengths = lengths[indexer] magnitudes = magnitudes[indexer] # # OK, now we make the edge table. First poi<->poi. Length = 2, # magnitude = magnitude at each point # poi_length = np.ones(len(p1_poi)) * 2 poi_magnitude = (image[i_idx[p1_poi - 1], j_idx[p1_poi - 1]] + image[i_idx[p2_poi - 1], j_idx[p2_poi - 1]]) # # Now the edges... # poi_edge_length = lengths + 2 poi_edge_magnitude = (image[i_idx[p1_edge - 1], j_idx[p1_edge - 1]] + image[i_idx[p2_edge - 1], j_idx[p2_edge - 1]] + magnitudes) # # Put together the columns # v1 = np.hstack((p1_poi, p1_edge)) v2 = np.hstack((p2_poi, p2_edge)) lengths = np.hstack((poi_length, poi_edge_length)) magnitudes = np.hstack((poi_magnitude, poi_edge_magnitude)) # # Sort by p1, p2 and length in order to pick the shortest length # indexer = np.lexsort((lengths, v1, v2)) v1 = v1[indexer] v2 = v2[indexer] lengths = lengths[indexer] magnitudes = magnitudes[indexer] if len(v1) > 0: to_keep = np.hstack( ([True], (v1[1:] != v1[:-1]) | (v2[1:] != v2[:-1]))) v1 = v1[to_keep] v2 = v2[to_keep] lengths = lengths[to_keep] magnitudes = magnitudes[to_keep] # # Put it all together into a table # edge_table = { self.EF_V1: v1, self.EF_V2: v2, self.EF_LENGTH: lengths, self.EF_TOTAL_INTENSITY: magnitudes } return edge_table, vertex_table
def make_neuron_graph(self, skeleton, skeleton_labels, trunks, branchpoints, endpoints, image): '''Make a table that captures the graph relationship of the skeleton skeleton - binary skeleton image + outline of seed objects skeleton_labels - labels matrix of skeleton trunks - binary image with trunk points as 1 branchpoints - binary image with branchpoints as 1 endpoints - binary image with endpoints as 1 image - image for intensity measurement returns two tables. Table 1: edge table The edge table is a numpy record array with the following named columns in the following order: v1: index into vertex table of first vertex of edge v2: index into vertex table of second vertex of edge length: # of intermediate pixels + 2 (for two vertices) total_intensity: sum of intensities along the edge Table 2: vertex table The vertex table is a numpy record array: i: I coordinate of the vertex j: J coordinate of the vertex label: the vertex's label kind: kind of vertex = "T" for trunk, "B" for branchpoint or "E" for endpoint. ''' i,j = np.mgrid[0:skeleton.shape[0], 0:skeleton.shape[1]] # # Give each point of interest a unique number # points_of_interest = trunks | branchpoints | endpoints number_of_points = np.sum(points_of_interest) # # Make up the vertex table # tbe = np.zeros(points_of_interest.shape, '|S1') tbe[trunks] = 'T' tbe[branchpoints] = 'B' tbe[endpoints] = 'E' i_idx = i[points_of_interest] j_idx = j[points_of_interest] poe_labels = skeleton_labels[points_of_interest] tbe = tbe[points_of_interest] vertex_table = { self.VF_I: i_idx, self.VF_J: j_idx, self.VF_LABELS: poe_labels, self.VF_KIND: tbe } # # First, break the skeleton by removing the branchpoints, endpoints # and trunks # broken_skeleton = skeleton & (~points_of_interest) # # Label the broken skeleton: this labels each edge differently # edge_labels, nlabels = morph.label_skeleton(skeleton) # # Reindex after removing the points of interest # edge_labels[points_of_interest] = 0 if nlabels > 0: indexer = np.arange(nlabels+1) unique_labels = np.sort(np.unique(edge_labels)) nlabels = len(unique_labels)-1 indexer[unique_labels] = np.arange(len(unique_labels)) edge_labels = indexer[edge_labels] # # find magnitudes and lengths for all edges # magnitudes = fix(scind.sum(image, edge_labels, np.arange(1, nlabels+1,dtype=np.int32))) lengths = fix(scind.sum(np.ones(edge_labels.shape), edge_labels, np.arange(1, nlabels+1,dtype=np.int32))).astype(int) else: magnitudes = np.zeros(0) lengths = np.zeros(0, int) # # combine the edge labels and indexes of points of interest with padding # edge_mask = edge_labels != 0 all_labels = np.zeros(np.array(edge_labels.shape)+2, int) all_labels[1:-1,1:-1][edge_mask] = edge_labels[edge_mask] + number_of_points all_labels[i_idx+1, j_idx+1] = np.arange(1, number_of_points+1) # # Collect all 8 neighbors for each point of interest # p1 = np.zeros(0,int) p2 = np.zeros(0,int) for i_off, j_off in ((0,0), (0,1), (0,2), (1,0), (1,2), (2,0), (2,1), (2,2)): p1 = np.hstack((p1, np.arange(1, number_of_points+1))) p2 = np.hstack((p2, all_labels[i_idx+i_off,j_idx+j_off])) # # Get rid of zeros which are background # p1 = p1[p2 != 0] p2 = p2[p2 != 0] # # Find point_of_interest -> point_of_interest connections. # p1_poi = p1[(p2 <= number_of_points) & (p1 < p2)] p2_poi = p2[(p2 <= number_of_points) & (p1 < p2)] # # Make sure matches are labeled the same # same_labels = (skeleton_labels[i_idx[p1_poi-1], j_idx[p1_poi-1]] == skeleton_labels[i_idx[p2_poi-1], j_idx[p2_poi-1]]) p1_poi = p1_poi[same_labels] p2_poi = p2_poi[same_labels] # # Find point_of_interest -> edge # p1_edge = p1[p2 > number_of_points] edge = p2[p2 > number_of_points] # # Now, each value that p2_edge takes forms a group and all # p1_edge whose p2_edge are connected together by the edge. # Possibly they touch each other without the edge, but we will # take the minimum distance connecting each pair to throw out # the edge. # edge, p1_edge, p2_edge = morph.pairwise_permutations(edge, p1_edge) indexer = edge - number_of_points - 1 lengths = lengths[indexer] magnitudes = magnitudes[indexer] # # OK, now we make the edge table. First poi<->poi. Length = 2, # magnitude = magnitude at each point # poi_length = np.ones(len(p1_poi)) * 2 poi_magnitude = (image[i_idx[p1_poi-1], j_idx[p1_poi-1]] + image[i_idx[p2_poi-1], j_idx[p2_poi-1]]) # # Now the edges... # poi_edge_length = lengths + 2 poi_edge_magnitude = (image[i_idx[p1_edge-1], j_idx[p1_edge-1]] + image[i_idx[p2_edge-1], j_idx[p2_edge-1]] + magnitudes) # # Put together the columns # v1 = np.hstack((p1_poi, p1_edge)) v2 = np.hstack((p2_poi, p2_edge)) lengths = np.hstack((poi_length, poi_edge_length)) magnitudes = np.hstack((poi_magnitude, poi_edge_magnitude)) # # Sort by p1, p2 and length in order to pick the shortest length # indexer = np.lexsort((lengths, v1, v2)) v1 = v1[indexer] v2 = v2[indexer] lengths = lengths[indexer] magnitudes = magnitudes[indexer] if len(v1) > 0: to_keep = np.hstack(([True], (v1[1:] != v1[:-1]) | (v2[1:] != v2[:-1]))) v1 = v1[to_keep] v2 = v2[to_keep] lengths = lengths[to_keep] magnitudes = magnitudes[to_keep] # # Put it all together into a table # edge_table = { self.EF_V1: v1, self.EF_V2: v2, self.EF_LENGTH: lengths, self.EF_TOTAL_INTENSITY: magnitudes } return edge_table, vertex_table