def ReadGraphfromMat(filename): f = sio.loadmat(filename) mat = f['im2'][0, 0] nX = int(mat['nX']) nY = int(mat['nY']) nZ = int(mat['nZ']) scale = mat['Hvox'][0] xx = int(nX * scale[0]) yy = int(nY * scale[1]) zz = int(nZ * scale[2]) # read nodes pos = mat['nodePos'].astype(float) radii = mat['nodeDiam'].T # read edges edg = (mat['nodeEdges']).astype('int') connections = [] for i in range(len(edg)): connections.append((edg[i, 0] - 1, edg[i, 1] - 1)) from VascGraph.GeomGraph import Graph G = Graph() G.add_nodes_from(range(pos.shape[0])) G.add_edges_from(connections) for i, p, r in zip(G.GetNodes(), pos, radii): G.node[i]['pos'] = p G.node[i]['r'] = r return G
def Update(self, FullyCC=False): filenameVertices = self.filenameVertices filenameEdges = self.filenameEdges P1, P2, P11, P22 = self.readCGAL(filenameEdges, filenameVertices) p, intersections, c = self.getGraph(P1, P2, P11, P22) G = Graph() G.add_nodes_from(range(np.shape(p)[0])) G.add_edges_from(np.ndarray.tolist(c)) for i in range(np.shape(p)[0]): G.node[i]['pos'] = p[i, :] G.to_undirected() if FullyCC == True: # connected components graphs = list(nx.connected_component_subgraphs(G)) s = 0 ind = 0 for idx, i in enumerate(graphs): if len(i) > s: s = len(i) ind = idx G = graphs[ind] G = fixG(G) self.Graph = G
def BuildGraph(self): ''' 1 Build graph based on info from 'path_net' 2 Set attributes to graph nodes based on info from 'path_attr' ''' def setatt(g, e, v, name): for i, j in zip(e, v): try: if j > G.node[i[0]][name]: G.node[i[0]][name] = j except: G.node[i[0]][name] = j try: if j > G.node[i[1]][name]: G.node[i[1]][name] = j except: G.node[i[1]][name] = j return g p, e = self.ReadNet() if self.path_attr is not None: self.attr = self.ReadAttr() if self.mode == 'di': G = DiGraph() else: G = Graph() G.add_nodes_from(range(len(p))) for i, j in zip(G.GetNodes(), p): G.node[i]['pos'] = j e = np.array(e) - 1 G.add_edges_from(e.tolist()) # set diameter/radius try: d = np.array(self.attr['Dia']).ravel().astype(float) G = setatt(G, e, d, 'd') G = setatt(G, e, d / 2, 'r') except: print('--Cannot set diam!') # set flow try: flow = np.array(self.attr['flow']).ravel().astype(float) G = setatt(G, e, flow, 'flow') except: print('--Cannot set flow!') # set po2 try: po2 = np.array(self.attr['ppO2']).ravel().astype(float) G = setatt(G, e, po2, 'po2') except: print('--Cannot set po2!') self.G = fixG(G)
def __CreateGraph(self): # build graph self.Graph = Graph() ind = np.array(range(self.NNodes)) self.Graph.add_nodes_from(ind) for i, p, r in zip(ind, self.GraphNodes, self.GraphRadius): self.Graph.node[i]['pos'] = p self.Graph.node[i]['r'] = r self.Graph.add_edges_from(self.Connections) self.Graph.remove_edges_from(self.Graph.selfloop_edges()) self.Graph = fixG(self.Graph)
def __GenerateRandomGraphFromLabel(self): #random sampling x = np.random.uniform(low=0, high=self.Shape[0], size=self.NInitialNodes).tolist() y = np.random.uniform(low=0, high=self.Shape[1], size=self.NInitialNodes).tolist() z = np.random.uniform(low=0, high=self.Shape[2], size=self.NInitialNodes).tolist() NodesIndices = self.Label[(np.floor(x).astype('int'), np.floor(y).astype('int'), np.floor(z).astype('int'))] > 0 Index = np.array([x, y, z]).T NodesPos = Index[NodesIndices] # build graph self.NNodes = len(NodesPos) self.Graph = Graph() self.Graph.add_nodes_from(range(self.NNodes)) # assign positions to nodes for i, p in zip(self.Graph.GetNodes(), NodesPos): self.Graph.node[i]['pos'] = p # build connectivity Tree = sp.spatial.cKDTree(NodesPos) NeigborsIndices = Tree.query(NodesPos, k=self.Connection + 1)[1] Edges = [] for ind, i in enumerate(NeigborsIndices): Neigbours = np.unique(i) c = [[ind, j] for j in Neigbours if j != ind and j != self.NNodes] if c: Edges.append(c) #assign connections Edges = [j for i in Edges for j in i] # unravel self.Graph.add_edges_from(Edges)
def __CreateGraph(self): # build graph self.Graph = Graph() totalnodes = 0 for nodes, c, radii, n in zip(self.SegmentsNodes, self.SegmentsConnections, self.SegmentsNodesRadii, self.NNodes): ind = np.array(range(n)) + totalnodes self.Graph.add_nodes_from(ind) for i, p, r in zip(ind, nodes, radii): self.Graph.node[i]['pos'] = p self.Graph.node[i]['r'] = r self.Graph.add_edges_from(c + totalnodes) totalnodes += n self.Graph.remove_edges_from(self.Graph.selfloop_edges()) self.Graph = fixG(self.Graph)
def __GenerateRandomGridGraphFromLabel(self): IndexTrueVoxels = np.where(self.Label) Index = np.array(IndexTrueVoxels).T #Limit NNodes to # of ture voxels if self.NNodes > len(Index): self.NNodes = len(Index) # probibility of true voxels Probability = (self.Label).astype(float) / np.sum(self.Label) Probability = Probability[IndexTrueVoxels] # obtain nodes NodesIndices = np.random.choice(range(len(Probability)), self.NNodes, p=Probability) NodesPos = Index[NodesIndices] # build graph self.Graph = Graph() self.Graph.add_nodes_from(range(self.NNodes)) # assign positions to nodes for i, p in zip(self.Graph.GetNodes(), NodesPos): self.Graph.node[i]['pos'] = p # build connectivity Tree = sp.spatial.cKDTree(NodesPos) NeigborsIndices = Tree.query(NodesPos, k=self.Connection + 1)[1] Edges = [] for ind, i in enumerate(NeigborsIndices): Neigbours = np.unique(i) c = [[ind, j] for j in Neigbours if j != ind and j != self.NNodes] if c: Edges.append(c) #assign connections Edges = [j for i in Edges for j in i] # unravel self.Graph.add_edges_from(Edges)
def to_undirected(self, reciprocal=False, as_view=False): if as_view is True: return nx.graphviews.GraphView(self) # deepcopy when not a view from VascGraph.GeomGraph import Graph G = Graph() G.graph.update(deepcopy(self.graph)) G.add_nodes_from((n, deepcopy(d)) for n, d in self._node.items()) if reciprocal is True: G.add_edges_from((u, v, deepcopy(d)) for u, nbrs in self._adj.items() for v, d in nbrs.items() if v in self._pred[u]) else: G.add_edges_from((u, v, deepcopy(d)) for u, nbrs in self._adj.items() for v, d in nbrs.items()) return G
def __init__(self, path): self.path = path try: with open(self.path, 'r') as f: lines = f.readlines() except: print('Cannot read file!') start = [idx + 1 for idx, i in enumerate(lines) if i[0] == '#'] end = [idx - 1 for idx, i in enumerate(lines) if i[0] == '#'] end = end[1:] for idx, i in enumerate(lines[end[-1]:]): if i[0] == '[': end.append(end[-1] + idx) break pathes = [] for s, e in zip(start, end): a = np.array([[float(j) for j in i.split(' ') if j != ''] for i in lines[s:e]]) pathes.append(a[:, (2, 3, 4)]) g = Graph() for i in pathes: n = g.number_of_nodes() nodes = range(n, n + len(i)) g.add_nodes_from(nodes) for idx, k in enumerate(nodes): g.node[k]['pos'] = np.array(i[idx]) e1 = nodes[0:-1] e2 = nodes[1:] e = [[k1, k2] for k1, k2 in zip(e1, e2)] g.add_edges_from(e) self.graph = g
def Update(self): try: x1, x2 = self.xls['x1'], self.xls['x2'] y1, y2 = self.xls['y1'], self.xls['y2'] z1, z2 = self.xls['z1'], self.xls['z2'] except: x1, x2 = self.xls['V1 x'], self.xls['V2 x'] y1, y2 = self.xls['V1 y'], self.xls['V2 y'] z1, z2 = self.xls['V1 z'], self.xls['V2 z'] ps = [(i, j, k) for i, j, k in zip(x1, y1, z1)] # start node pe = [(i, j, k) for i, j, k in zip(x2, y2, z2)] # end node # all nodes with their id's and pos's p = list(set(ps).union(set(pe))) pid = dict() pos = dict() for idx, i in enumerate(p): pid[str(i)] = idx pos[idx] = i # graph nodes = range(len(p)) e = [(pid[str(i)], pid[str(j)]) for i, j in zip(ps, pe)] edges = [i for i in e if i[0] != i[1]] g = Graph() g.add_nodes_from(nodes) g.add_edges_from(edges) for i in g.GetNodes(): g.node[i]['pos'] = np.array(pos[i]) self.Graph = g
class GenerateGraph: def __init__(self, Label): self.Label = Label self.Shape = np.shape(self.Label) # size of image self.Length = self.Shape[0] * self.Shape[1] * self.Shape[ 2] # number of voxels self.__ComputeArea() # private def __ComputeArea(self): self.Area = np.sum(self.Label > 0) def __CalculateDistMap(self): # # XY=[self.Label[i,:,:] for i in range(self.Shape[0])] #Z-XY # ZX=[self.Label[:,:,i] for i in range(self.Shape[2])] #Y-ZX # ZY=[self.Label[:,i,:] for i in range(self.Shape[1])] #X-ZY # # DistXY=np.array([image.morphology.distance_transform_edt(i) for i in XY]) # DistZX=np.array([image.morphology.distance_transform_edt(i) for i in ZX]) # DistZY=np.array([image.morphology.distance_transform_edt(i) for i in ZY]) # # DistZX=np.rollaxis(DistZX, 0, 3) # DistZY=np.rollaxis(DistZY, 0, 2) # # DistMap_=np.maximum(DistXY, DistZX) # DistMap=np.maximum(DistMap_, DistZY) # # DistMap=filt.maximum_filter(DistMap, size=(3,3,3)) DistMap = image.morphology.distance_transform_edt(self.Label) self.DistMap = DistMap def __AssignDistMapToGraph(self): ''' Assign dist values to graph nodes ''' Nodes = self.Graph.GetNodes() for i in Nodes: Pos = tuple(self.Graph.node[i]['pos'].astype(int)) if Pos[0] < self.Shape[0] and Pos[1] < self.Shape[1] and Pos[ 2] < self.Shape[2]: Dist = self.DistMap[Pos] if Dist < 1: Dist = 1 self.Graph.node[i]['r'] = Dist else: self.Graph.node[i]['r'] = 1 def __GenerateRandomGraphFromLabel(self): #random sampling x = np.random.uniform(low=0, high=self.Shape[0], size=self.NInitialNodes).tolist() y = np.random.uniform(low=0, high=self.Shape[1], size=self.NInitialNodes).tolist() z = np.random.uniform(low=0, high=self.Shape[2], size=self.NInitialNodes).tolist() NodesIndices = self.Label[(np.floor(x).astype('int'), np.floor(y).astype('int'), np.floor(z).astype('int'))] > 0 Index = np.array([x, y, z]).T NodesPos = Index[NodesIndices] # build graph self.NNodes = len(NodesPos) self.Graph = Graph() self.Graph.add_nodes_from(range(self.NNodes)) # assign positions to nodes for i, p in zip(self.Graph.GetNodes(), NodesPos): self.Graph.node[i]['pos'] = p # build connectivity Tree = sp.spatial.cKDTree(NodesPos) NeigborsIndices = Tree.query(NodesPos, k=self.Connection + 1)[1] Edges = [] for ind, i in enumerate(NeigborsIndices): Neigbours = np.unique(i) c = [[ind, j] for j in Neigbours if j != ind and j != self.NNodes] if c: Edges.append(c) #assign connections Edges = [j for i in Edges for j in i] # unravel self.Graph.add_edges_from(Edges) def __GenerateRandomGridGraphFromLabel(self): IndexTrueVoxels = np.where(self.Label) Index = np.array(IndexTrueVoxels).T #Limit NNodes to # of ture voxels if self.NNodes > len(Index): self.NNodes = len(Index) # probibility of true voxels Probability = (self.Label).astype(float) / np.sum(self.Label) Probability = Probability[IndexTrueVoxels] # obtain nodes NodesIndices = np.random.choice(range(len(Probability)), self.NNodes, p=Probability) NodesPos = Index[NodesIndices] # build graph self.Graph = Graph() self.Graph.add_nodes_from(range(self.NNodes)) # assign positions to nodes for i, p in zip(self.Graph.GetNodes(), NodesPos): self.Graph.node[i]['pos'] = p # build connectivity Tree = sp.spatial.cKDTree(NodesPos) NeigborsIndices = Tree.query(NodesPos, k=self.Connection + 1)[1] Edges = [] for ind, i in enumerate(NeigborsIndices): Neigbours = np.unique(i) c = [[ind, j] for j in Neigbours if j != ind and j != self.NNodes] if c: Edges.append(c) #assign connections Edges = [j for i in Edges for j in i] # unravel self.Graph.add_edges_from(Edges) def __GenerateGridGraphFromLabel(self): def VoxelsPositions(Label, Shape, Length): ''' Shape: shape of array indexing in order: rows by row->depth ''' # positions of each voxel z, x, y = np.meshgrid(range(Shape[0]), range(Shape[1]), range(Shape[2]), indexing='ij') x = x[Label.astype(bool)] y = y[Label.astype(bool)] z = z[Label.astype(bool)] VoxelsPos = np.transpose([z, x, y]) return VoxelsPos def GetConnections(Label, Shape, Length): # connections from pathways on array grid Array = (np.reshape(range(Length), Shape) + 1) * Label # incides of voxels in the Array VoxelsIndices = Array[Label.astype(bool)] #-------- path1 = iter( np.transpose( [Array[:, :, 0:-1].ravel(), Array[:, :, 1:].ravel()])) path1 = (i for i in path1 if all(i)) #-------- path2 = iter( np.transpose([ np.swapaxes(Array[:, 0:-1, :], 1, 2).ravel(), np.swapaxes(Array[:, 1:, :], 1, 2).ravel() ])) path2 = (i for i in path2 if all(i)) #-------- path3 = iter( np.transpose([ np.swapaxes(Array[0:-1, :, :], 0, 2).ravel(), np.swapaxes(Array[1:, :, :], 0, 2).ravel() ])) path3 = (i for i in path3 if all(i)) return VoxelsIndices, path1, path2, path3 if self.Sampling is not None: Scale = (1.0 / self.Sampling, 1.0 / self.Sampling, 1.0 / self.Sampling) Label = image.zoom(self.Label.astype(int), Scale) Shape = np.shape(Label) # size of image Length = Shape[0] * Shape[1] * Shape[2] # number of voxels else: Label = self.Label Shape = self.Shape Length = self.Length # voxel indices and thier positions t1 = time() VoxelsPos = VoxelsPositions(Label, Shape, Length) print('create nodes: ' + str(time() - t1)) t1 = time() VoxelsIndices, Connections1, Connections2, Connections3 = GetConnections( Label, Shape, Length) print('create connections: ' + str(time() - t1)) # build graph t1 = time() self.Graph = Graph() self.Graph.add_nodes_from(VoxelsIndices) for ind, p in zip(VoxelsIndices, VoxelsPos): self.Graph.node[ind]['pos'] = p self.Graph.add_edges_from(Connections1) self.Graph.add_edges_from(Connections2) self.Graph.add_edges_from(Connections3) #exclude nodes with less than 2 neighbors NNodesToExclude = 1 while NNodesToExclude > 0: NodesToExclude = [ i for i in self.Graph.GetNodes() if len(self.Graph.GetNeighbors(i)) <= 2 ] self.Graph.remove_nodes_from(NodesToExclude) NNodesToExclude = len(NodesToExclude) if self.Sampling is not None: for i in self.Graph.GetNodes(): self.Graph.node[i][ 'pos'] = self.Graph.node[i]['pos'] * self.Sampling print('create graph: ' + str(time() - t1)) # public def UpdateRandomGraph(self, connection=8, nInitialNodes=100000): self.Connection = connection self.NInitialNodes = nInitialNodes self.__GenerateRandomGraphFromLabel() def UpdateRandomGridGraph(self, connection=8, nNodes=100000): self.Connection = connection self.NNodes = nNodes self.__GenerateRandomGridGraphFromLabel() def UpdateGridGraph(self, Sampling=None): if Sampling is not None: self.Sampling = float(Sampling) else: self.Sampling = Sampling self.__GenerateGridGraphFromLabel() def GetOutput(self): self.__CalculateDistMap() self.__AssignDistMapToGraph() self.Graph = fixG(self.Graph) self.Graph.Area = self.Area return self.Graph def GetArea(self): return self.Area def GetDistMap(self): self.__CalculateDistMap() return self.DistMap
class ReadCenterlineCSV: ''' Class to create a graph given only a centerline (points supposed to have equal spacing between each other) Constructer Input: CSV file with columns: X, Y, Z, Radius ''' def __init__(self, filepath): self.FilePath = filepath self.Resolution = 1.0 self.ConnectionParam = 4 self.__X = [] self.__Y = [] self.__Z = [] self.__Radius = [] # Private def __ReadFile(self): # read info from .tre with open(self.FilePath, 'r') as f: self.__Lines = f.readlines() X = [i.split(',')[0] for i in self.__Lines] self.__X = X[1:] Y = [i.split(',')[1] for i in self.__Lines] self.__Y = Y[1:] Z = [i.split(',')[2] for i in self.__Lines] self.__Z = Z[1:] Radius = [i.split(',')[3] for i in self.__Lines] self.__Radius = np.array(Radius[1:]).astype(float) def __ReadNodes(self): # graph nodes from centerline self.GraphNodes = np.array([self.__X, self.__Y, self.__Z]).T self.GraphNodes = self.GraphNodes.astype('float') self.GraphNodes, ClustersPos, Clusters = AssignToClusters( self.GraphNodes, resolution=self.Resolution) self.GraphRadius = [ np.max([self.__Radius[i] for i in j]) for j in Clusters ] self.NNodes = len(self.GraphNodes) def __CreateConnections(self): # connections from graph nodes self.Connections = [] length = len(self.GraphNodes) Tree = sp.spatial.cKDTree(self.GraphNodes) c = [Tree.query(i, k=self.ConnectionParam)[1] for i in self.GraphNodes] c = np.array(c) connections = [] for i in range(self.ConnectionParam): # obtain and fix connection from tree.query if i > 0: cc = c[:, (0, i)] exclude = np.where(cc[:, 1] >= len(self.GraphNodes)) cc[exclude] = 0 connections.append(cc) self.Connections = np.vstack(tuple(connections)) def __CreateGraph(self): # build graph self.Graph = Graph() ind = np.array(range(self.NNodes)) self.Graph.add_nodes_from(ind) for i, p, r in zip(ind, self.GraphNodes, self.GraphRadius): self.Graph.node[i]['pos'] = p self.Graph.node[i]['r'] = r self.Graph.add_edges_from(self.Connections) self.Graph.remove_edges_from(self.Graph.selfloop_edges()) self.Graph = fixG(self.Graph) # public def Update(self, ConnectionParam=4, Resolution=0.75): ''' Update class Graph Input: ConnectionParam: control number of closest neighbors to a centreline point. Resolution: control at which resolution centerline points should sampled. Higher value imposes lower sampling rate. 0<'Resolution'<=1 Output: create NetworkX undirected graph ''' self.ConnectionParam = ConnectionParam self.Resolution = Resolution self.__ReadFile() self.__ReadNodes() self.__CreateConnections() self.__CreateGraph() def GetOutput(self): refine = RefineGraph(self.Graph) refine.Update() self.Graph = refine.GetOutput() return self.Graph
def __init__(self, filepath, sampling=1): from VascGraph.GeomGraph import Graph try: import h5py except: print('To run this function, \'h5py\' sould be installed.') return # ---- read ----# f=h5py.File(filepath, 'r') refs=[i[0] for i in f.get('GeodesicMSTs/CGPathContinuous')] pathes=[np.array(f[i]).T for i in refs] data=f.get('GeodesicMSTsMatrix/M/data') ir=np.array(f.get('GeodesicMSTsMatrix/M/ir')) jc=np.array(f.get('GeodesicMSTsMatrix/M/jc')) # ----- sampling of pathes nodes ----# ind=[len(i)/sampling for i in pathes] ind=[np.array(range(i))*sampling for i in ind] pathes=[i[indx] for i, indx in zip(pathes, ind)] # ----- build graph from pathes -----# path_ext=[] g=Graph() for path in pathes: n=g.number_of_nodes() nodes=np.array(range(len(path)))+n e1=nodes[1:] e2=nodes[:-1] e=np.array([e1,e2]).T path_ext.append([nodes[0], nodes[-1]]) g.add_nodes_from(nodes) g.add_edges_from(e) for node, pos in zip(nodes, path): g.node[node]['pos']=np.array([pos[1], pos[0], pos[2]]) # ------- connection between pathes ----# path_ext=np.array(path_ext) a = sparse.csc_matrix((data, ir, jc)) ind1, ind2 = np.where(a.todense()>0) e=[] for i,j in zip(ind1,ind2): ee=[[path_ext[i][0], path_ext[j][1]], [path_ext[i][1], path_ext[j][0]], [path_ext[i][0], path_ext[j][0]], [path_ext[i][1], path_ext[j][1]]] poss=np.array([[g.node[k[0]]['pos'], g.node[k[1]]['pos']] for k in ee]) poss= poss[:,0,:]-poss[:,1,:] norm=np.linalg.norm(poss, axis=1) indx=np.where(norm==norm.min())[0][0] e.append(ee[indx]) g.add_edges_from(e) self.graph=g
def __GenerateGridGraphFromLabel(self): def VoxelsPositions(Label, Shape, Length): ''' Shape: shape of array indexing in order: rows by row->depth ''' # positions of each voxel z, x, y = np.meshgrid(range(Shape[0]), range(Shape[1]), range(Shape[2]), indexing='ij') x = x[Label.astype(bool)] y = y[Label.astype(bool)] z = z[Label.astype(bool)] VoxelsPos = np.transpose([z, x, y]) return VoxelsPos def GetConnections(Label, Shape, Length): # connections from pathways on array grid Array = (np.reshape(range(Length), Shape) + 1) * Label # incides of voxels in the Array VoxelsIndices = Array[Label.astype(bool)] #-------- path1 = iter( np.transpose( [Array[:, :, 0:-1].ravel(), Array[:, :, 1:].ravel()])) path1 = (i for i in path1 if all(i)) #-------- path2 = iter( np.transpose([ np.swapaxes(Array[:, 0:-1, :], 1, 2).ravel(), np.swapaxes(Array[:, 1:, :], 1, 2).ravel() ])) path2 = (i for i in path2 if all(i)) #-------- path3 = iter( np.transpose([ np.swapaxes(Array[0:-1, :, :], 0, 2).ravel(), np.swapaxes(Array[1:, :, :], 0, 2).ravel() ])) path3 = (i for i in path3 if all(i)) return VoxelsIndices, path1, path2, path3 if self.Sampling is not None: Scale = (1.0 / self.Sampling, 1.0 / self.Sampling, 1.0 / self.Sampling) Label = image.zoom(self.Label.astype(int), Scale) Shape = np.shape(Label) # size of image Length = Shape[0] * Shape[1] * Shape[2] # number of voxels else: Label = self.Label Shape = self.Shape Length = self.Length # voxel indices and thier positions t1 = time() VoxelsPos = VoxelsPositions(Label, Shape, Length) print('create nodes: ' + str(time() - t1)) t1 = time() VoxelsIndices, Connections1, Connections2, Connections3 = GetConnections( Label, Shape, Length) print('create connections: ' + str(time() - t1)) # build graph t1 = time() self.Graph = Graph() self.Graph.add_nodes_from(VoxelsIndices) for ind, p in zip(VoxelsIndices, VoxelsPos): self.Graph.node[ind]['pos'] = p self.Graph.add_edges_from(Connections1) self.Graph.add_edges_from(Connections2) self.Graph.add_edges_from(Connections3) #exclude nodes with less than 2 neighbors # NNodesToExclude=1 # while NNodesToExclude>0: # NodesToExclude=[i for i in self.Graph.GetNodes() if len(self.Graph.GetNeighbors(i))<=2] # self.Graph.remove_nodes_from(NodesToExclude) # NNodesToExclude=len(NodesToExclude) # reconnect nodes with less that 2 edges (request from Sreekanth ) pos = np.array(self.Graph.GetNodesPos()) nodes = np.array(self.Graph.GetNodes()) NodesToModify = [ i for i in self.Graph.GetNodes() if len(self.Graph.GetNeighbors(i)) <= 2 ] pos_xc_nodes = np.array( [self.Graph.node[k]['pos'] for k in NodesToModify]) new_edges = [] for nn, pp in zip(NodesToModify, pos_xc_nodes): checkp = pos - pp[None, :] checkp = np.sum(checkp**2, axis=1)**0.5 ed_nodes = nodes[checkp <= 2**0.5] new_ed = [[nn, kk] for kk in ed_nodes if kk != nn] #print(len(new_ed)) new_edges.append(new_ed) new_edges = [k2 for k1 in new_edges for k2 in k1] self.Graph.add_edges_from(new_edges) # label extremity nodes at imageborders if self.label_ext: maxx, maxy, maxz = Label.shape maxx -= 1 maxy -= 1 maxz -= 1 pos = self.Graph.GetNodesPos() ext = [] for n, p in zip(self.Graph.GetNodes(), self.Graph.GetNodesPos()): if p[0] == 0 or p[0] == maxx: self.Graph.node[n]['ext'] = 1 if p[1] == 0 or p[1] == maxy: self.Graph.node[n]['ext'] = 1 if p[2] == 0 or p[2] == maxz: self.Graph.node[n]['ext'] = 1 try: dumb = self.Graph.node[n]['ext'] except: self.Graph.node[n]['ext'] = 0 if self.Sampling is not None: for i in self.Graph.GetNodes(): self.Graph.node[i][ 'pos'] = self.Graph.node[i]['pos'] * self.Sampling print('create graph: ' + str(time() - t1))
def ReadFile(self): G_init = nx.read_pajek(self.filename) self.G_init = G_init if self.mode == 'di': G = DiGraph() else: G = Graph() # build geometry for i in list(G_init.nodes()): node = G_init.node[i] # add node #n=int(node['id'].encode()) n = int(i) G.add_node(n) #add position if sys.version_info[0] >= 3: pos = node['pos'] else: pos = node['pos'].encode() pos = pos.split(' ') xyz = [] for j in range(len(pos)): try: value = float(pos[j]) xyz.append(value) except: try: value = pos[j].split('[') try: xyz.append(float(value[1])) except: value = value[1].split(',') xyz.append(float(value[0])) except: try: value = pos[j].split(']') try: xyz.append(float(value[0])) except: value = value[1].split(',') xyz.append(float(value[0])) except: try: value = pos[j].split(',') xyz.append(float(value[0])) except: pass G.node[n]['pos'] = np.array(xyz) # add label try: yORn = node['node'].encode() if yORn == 'False': G.node[n]['node'] = False else: G.node[n]['node'] = True except: pass # add radius try: radius = node['d'].encode() G.node[n]['d'] = float(radius) except: pass # add radius try: radius = node['r'].encode() G.node[n]['r'] = float(radius) except: pass # add radius try: radius = node['r'].encode() G.node[n]['r'] = float(radius.split('[')[1].split(']')[0]) except: pass # add radius try: radius = node['d'].encode() G.node[n]['d'] = float(radius.split('[')[1].split(']')[0]) except: pass # add type try: t = node['type'].encode() G.node[n]['type'] = int(t) except: pass # add branch try: b = node['branch'].encode() G.node[n]['branch'] = int(b) except: pass # add inflow try: b = node['inflow'].encode() G.node[n]['inflow'] = str(int(b)) except: pass # add outflow try: b = node['outflow'].encode() G.node[n]['outflow'] = str(int(b)) except: pass # add sink try: b = node['sink'].encode() G.node[n]['sink'] = str(int(b)) except: pass # add source try: b = node['source'].encode() G.node[n]['source'] = str(int(b)) except: pass # add root try: b = node['root'].encode() G.node[n]['root'] = str(int(b)) except: pass # add flow try: b = node['flow'].encode() G.node[n]['flow'] = float(b) except: pass # add pressure try: b = node['pressure'].encode() G.node[n]['pressure'] = float(b) except: pass # add velocity try: b = node['velocity'].encode() G.node[n]['velocity'] = float(b) except: pass # add velocity try: b = node['so2'].encode() G.node[n]['so2'] = float(b) except: pass # add velocity try: b = node['po2'].encode() G.node[n]['po2'] = float(b) except: pass #build Topology raw_edges = list(G_init.edges()) edges = [(int(i[0]), int(i[1])) for i in raw_edges] G.add_edges_from(edges) for i, j in zip(raw_edges, edges): try: G[j[0]][j[1]]['res'] = G_init[i[0]][i[1]][0]['res'] except: pass try: G[j[0]][j[1]]['flow'] = G_init[i[0]][i[1]][0]['flow'] except: pass try: G[j[0]][j[1]]['pressure'] = G_init[i[0]][i[1]][0]['res'] except: pass try: G[j[0]][j[1]]['inflow'] = G_init[i[0]][i[1]][0]['inflow'] except: pass try: G[j[0]][j[1]]['outflow'] = G_init[i[0]][i[1]][0]['outflow'] except: pass try: G[j[0]][j[1]]['branch'] = G_init[i[0]][i[1]][0]['branch'] except: pass try: G[j[0]][j[1]]['velocity'] = G_init[i[0]][i[1]][0]['velocity'] except: pass try: G[j[0]][j[1]]['pressure'] = G_init[i[0]][i[1]][0]['pressure'] except: pass try: G[j[0]][j[1]]['vol'] = G_init[i[0]][i[1]][0]['vol'] except: pass self.G = G
class ReadMRIGraph: ''' Read 'tre' file for graphs genrated from MRI images''' def __init__(self, filepath): self.FilePath = filepath self.__ObjectType = [] self.__ObjectSubType = [] self.__NDims = [] self.__ID = [] self.__ParentID = [] self.__Color = [] self.__TransformMatrix = [] self.__Offset = [] self.__CenterOfRotation = [] self.__ElementSpacing = [] self.__Root = [] self.__Artery = [] self.__PointDim = [] self.__NPoints = [] self.__Points = [] self.__StartObjectIndices = [] self.__StartPointsIndices = [] # Private def __ReadFile(self): # read info from .tre with open(self.FilePath, 'r') as f: self.__Lines = f.readlines() Read = False for idx, line in enumerate(self.__Lines): if line.split()[0] == 'ObjectType' and line.split()[2] == 'Tube': Read = True self.__StartObjectIndices.append(idx) self.__ObjectType.append(line.split()[2:]) else: if line.split( )[0] == 'ObjectType' and line.split()[2] != 'Tube': Read = False if line.split()[0] == 'ObjectSubType' and Read: self.__ObjectSubType.append(line.split()[2:]) if line.split()[0] == 'NDims' and Read: self.__NDims.append(line.split()[2:]) if line.split()[0] == 'ID' and Read: self.__ID.append(line.split()[2:]) if line.split()[0] == 'ParentID' and Read: self.__ParentID.append(line.split()[2:]) if line.split()[0] == 'Color' and Read: self.__Color.append(line.split()[2:]) if line.split()[0] == 'TransformMatrix' and Read: self.__TransformMatrix.append(line.split()[2:]) if line.split()[0] == 'Offset' and Read: self.__Offset.append(line.split()[2:]) if line.split()[0] == 'CenterOfRotation' and Read: self.__CenterOfRotation.append(line.split()[2:]) if line.split()[0] == 'ElementSpacing' and Read: self.__ElementSpacing.append(line.split()[2:]) if line.split()[0] == 'Root' and Read: self.__Root.append(line.split()[2:]) if line.split()[0] == 'Artery' and Read: self.__Artery.append(line.split()[2:]) if line.split()[0] == 'PointDim' and Read: self.__PointDim.append(line.split()[2:]) if line.split()[0] == 'NPoints' and Read: self.__NPoints.append(line.split()[2:]) if line.split()[0] == 'Points' and Read: self.__StartPointsIndices.append(idx + 1) # number of points in each segment self.__NPoints = np.array(self.__NPoints).astype(int) self.__NPoints = self.__NPoints.ravel() def __ReadSegments(self): #read segments (tube objects) self.Segments = [] self.SegmentsRadii = [] for start, npoints in zip(self.__StartPointsIndices, self.__NPoints): s = self.__Lines[start:start + int(npoints)] s = [i.split() for i in s] s = np.array(s).astype(float) self.SegmentsRadii.append(s[:, 3]) self.Segments.append(s[:, (0, 1, 2)]) def __ReadNodes(self): # nodes from segments self.SegmentsNodes = [] self.SegmentsNodesRadii = [] self.NNodes = [] for i, r in zip(self.Segments, self.SegmentsRadii): nodes, _, ids = AssignToClusters(i) radii = [np.max(r[k]) for k in ids] self.SegmentsNodes.append(nodes) self.SegmentsNodesRadii.append(radii) self.NNodes.append(len(nodes)) def __CreateConnections(self): # connections from segments self.SegmentsConnections = [] for segment in self.SegmentsNodes: length = len(segment) Tree = sp.spatial.cKDTree(segment) c = [ Tree.query(i, k=3, distance_upper_bound=2.0)[1] for i in segment ] c = np.array(c) # obtain and fix connection from tree.query c1 = c[:, (0, 1)] exclude1 = np.where(c1[:, 1] >= len(segment)) c1[exclude1] = 0 c2 = c[:, (0, 2)] exclude2 = np.where(c2[:, 1] >= len(segment)) c2[exclude2] = 0 c = np.vstack((c1, c2)) self.SegmentsConnections.append(c) def __CreateGraph(self): # build graph self.Graph = Graph() totalnodes = 0 for nodes, c, radii, n in zip(self.SegmentsNodes, self.SegmentsConnections, self.SegmentsNodesRadii, self.NNodes): ind = np.array(range(n)) + totalnodes self.Graph.add_nodes_from(ind) for i, p, r in zip(ind, nodes, radii): self.Graph.node[i]['pos'] = p self.Graph.node[i]['r'] = r self.Graph.add_edges_from(c + totalnodes) totalnodes += n self.Graph.remove_edges_from(self.Graph.selfloop_edges()) self.Graph = fixG(self.Graph) # public def Update(self): self.__ReadFile() self.__ReadSegments() self.__ReadNodes() self.__CreateConnections() self.__CreateGraph() def GetSegmentsNodes(self): return self.SegmentsNodes def GetSegmentsNodesRadii(self): return self.SegmentsNodesRadii def GetSegmentsConnections(self): return self.SegmentsConnections def GetOutput(self): refine = RefineGraph(self.Graph) refine.Update() self.Graph = refine.GetOutput() return self.Graph
class GenerateGraph: def __init__(self, Label, DisMap=None, label_ext=False): self.Label = Label self.label_ext = label_ext self.Shape = np.shape(self.Label) # size of image self.Length = self.Shape[0] * self.Shape[1] * self.Shape[ 2] # number of voxels self.__ComputeArea() self.DistMap = DisMap # private def __ComputeArea(self): self.Area = np.sum(self.Label > 0) def __CalculateDistMap(self): if self.DistMap is None: #self.DistMap=image.morphology.distance_transform_edt(self.Label) self.DistMap = DistMap3D(self.Label) def __AssignDistMapToGraph(self): ''' Assign dist values to graph nodes ''' Nodes = self.Graph.GetNodes() for i in Nodes: Pos = tuple(self.Graph.node[i]['pos'].astype(int)) if Pos[0] < self.Shape[0] and Pos[1] < self.Shape[1] and Pos[ 2] < self.Shape[2]: Dist = self.DistMap[Pos] if Dist < 1: Dist = 1 self.Graph.node[i]['r'] = Dist else: self.Graph.node[i]['r'] = 1 def __GenerateRandomGraphFromLabel(self): #random sampling x = np.random.uniform(low=0, high=self.Shape[0], size=self.NInitialNodes).tolist() y = np.random.uniform(low=0, high=self.Shape[1], size=self.NInitialNodes).tolist() z = np.random.uniform(low=0, high=self.Shape[2], size=self.NInitialNodes).tolist() NodesIndices = self.Label[(np.floor(x).astype('int'), np.floor(y).astype('int'), np.floor(z).astype('int'))] > 0 Index = np.array([x, y, z]).T NodesPos = Index[NodesIndices] # build graph self.NNodes = len(NodesPos) self.Graph = Graph() self.Graph.add_nodes_from(range(self.NNodes)) # assign positions to nodes for i, p in zip(self.Graph.GetNodes(), NodesPos): self.Graph.node[i]['pos'] = p # build connectivity Tree = sp.spatial.cKDTree(NodesPos) NeigborsIndices = Tree.query(NodesPos, k=self.Connection + 1)[1] Edges = [] for ind, i in enumerate(NeigborsIndices): Neigbours = np.unique(i) c = [[ind, j] for j in Neigbours if j != ind and j != self.NNodes] if c: Edges.append(c) #assign connections Edges = [j for i in Edges for j in i] # unravel self.Graph.add_edges_from(Edges) def __GenerateRandomGridGraphFromLabel(self): IndexTrueVoxels = np.where(self.Label) Index = np.array(IndexTrueVoxels).T #Limit NNodes to # of ture voxels if self.NNodes > len(Index): self.NNodes = len(Index) # probibility of true voxels Probability = (self.Label).astype(float) / np.sum(self.Label) Probability = Probability[IndexTrueVoxels] # obtain nodes NodesIndices = np.random.choice(range(len(Probability)), self.NNodes, p=Probability) NodesPos = Index[NodesIndices] # build graph self.Graph = Graph() self.Graph.add_nodes_from(range(self.NNodes)) # assign positions to nodes for i, p in zip(self.Graph.GetNodes(), NodesPos): self.Graph.node[i]['pos'] = p # build connectivity Tree = sp.spatial.cKDTree(NodesPos) NeigborsIndices = Tree.query(NodesPos, k=self.Connection + 1)[1] Edges = [] for ind, i in enumerate(NeigborsIndices): Neigbours = np.unique(i) c = [[ind, j] for j in Neigbours if j != ind and j != self.NNodes] if c: Edges.append(c) #assign connections Edges = [j for i in Edges for j in i] # unravel self.Graph.add_edges_from(Edges) def __GenerateGridGraphFromLabel(self): def VoxelsPositions(Label, Shape, Length): ''' Shape: shape of array indexing in order: rows by row->depth ''' # positions of each voxel z, x, y = np.meshgrid(range(Shape[0]), range(Shape[1]), range(Shape[2]), indexing='ij') x = x[Label.astype(bool)] y = y[Label.astype(bool)] z = z[Label.astype(bool)] VoxelsPos = np.transpose([z, x, y]) return VoxelsPos def GetConnections(Label, Shape, Length): # connections from pathways on array grid Array = (np.reshape(range(Length), Shape) + 1) * Label # incides of voxels in the Array VoxelsIndices = Array[Label.astype(bool)] #-------- path1 = iter( np.transpose( [Array[:, :, 0:-1].ravel(), Array[:, :, 1:].ravel()])) path1 = (i for i in path1 if all(i)) #-------- path2 = iter( np.transpose([ np.swapaxes(Array[:, 0:-1, :], 1, 2).ravel(), np.swapaxes(Array[:, 1:, :], 1, 2).ravel() ])) path2 = (i for i in path2 if all(i)) #-------- path3 = iter( np.transpose([ np.swapaxes(Array[0:-1, :, :], 0, 2).ravel(), np.swapaxes(Array[1:, :, :], 0, 2).ravel() ])) path3 = (i for i in path3 if all(i)) return VoxelsIndices, path1, path2, path3 if self.Sampling is not None: Scale = (1.0 / self.Sampling, 1.0 / self.Sampling, 1.0 / self.Sampling) Label = image.zoom(self.Label.astype(int), Scale) Shape = np.shape(Label) # size of image Length = Shape[0] * Shape[1] * Shape[2] # number of voxels else: Label = self.Label Shape = self.Shape Length = self.Length # voxel indices and thier positions t1 = time() VoxelsPos = VoxelsPositions(Label, Shape, Length) print('create nodes: ' + str(time() - t1)) t1 = time() VoxelsIndices, Connections1, Connections2, Connections3 = GetConnections( Label, Shape, Length) print('create connections: ' + str(time() - t1)) # build graph t1 = time() self.Graph = Graph() self.Graph.add_nodes_from(VoxelsIndices) for ind, p in zip(VoxelsIndices, VoxelsPos): self.Graph.node[ind]['pos'] = p self.Graph.add_edges_from(Connections1) self.Graph.add_edges_from(Connections2) self.Graph.add_edges_from(Connections3) #exclude nodes with less than 2 neighbors # NNodesToExclude=1 # while NNodesToExclude>0: # NodesToExclude=[i for i in self.Graph.GetNodes() if len(self.Graph.GetNeighbors(i))<=2] # self.Graph.remove_nodes_from(NodesToExclude) # NNodesToExclude=len(NodesToExclude) # reconnect nodes with less that 2 edges (request from Sreekanth ) pos = np.array(self.Graph.GetNodesPos()) nodes = np.array(self.Graph.GetNodes()) NodesToModify = [ i for i in self.Graph.GetNodes() if len(self.Graph.GetNeighbors(i)) <= 2 ] pos_xc_nodes = np.array( [self.Graph.node[k]['pos'] for k in NodesToModify]) new_edges = [] for nn, pp in zip(NodesToModify, pos_xc_nodes): checkp = pos - pp[None, :] checkp = np.sum(checkp**2, axis=1)**0.5 ed_nodes = nodes[checkp <= 2**0.5] new_ed = [[nn, kk] for kk in ed_nodes if kk != nn] #print(len(new_ed)) new_edges.append(new_ed) new_edges = [k2 for k1 in new_edges for k2 in k1] self.Graph.add_edges_from(new_edges) # label extremity nodes at imageborders if self.label_ext: maxx, maxy, maxz = Label.shape maxx -= 1 maxy -= 1 maxz -= 1 pos = self.Graph.GetNodesPos() ext = [] for n, p in zip(self.Graph.GetNodes(), self.Graph.GetNodesPos()): if p[0] == 0 or p[0] == maxx: self.Graph.node[n]['ext'] = 1 if p[1] == 0 or p[1] == maxy: self.Graph.node[n]['ext'] = 1 if p[2] == 0 or p[2] == maxz: self.Graph.node[n]['ext'] = 1 try: dumb = self.Graph.node[n]['ext'] except: self.Graph.node[n]['ext'] = 0 if self.Sampling is not None: for i in self.Graph.GetNodes(): self.Graph.node[i][ 'pos'] = self.Graph.node[i]['pos'] * self.Sampling print('create graph: ' + str(time() - t1)) # public def UpdateRandomGraph(self, connection=8, nInitialNodes=100000): self.Connection = connection self.NInitialNodes = nInitialNodes self.__GenerateRandomGraphFromLabel() def UpdateRandomGridGraph(self, connection=8, nNodes=100000): self.Connection = connection self.NNodes = nNodes self.__GenerateRandomGridGraphFromLabel() def UpdateGridGraph(self, Sampling=None): if Sampling is not None: self.Sampling = float(Sampling) else: self.Sampling = Sampling self.__GenerateGridGraphFromLabel() def GetOutput(self): self.__CalculateDistMap() self.__AssignDistMapToGraph() self.Graph = fixG(self.Graph) self.Graph.Area = self.Area return self.Graph def GetArea(self): return self.Area def GetDistMap(self): self.__CalculateDistMap() return self.DistMap
def __GenerateGridGraphFromLabel(self): def VoxelsPositions(Label, Shape, Length): ''' Shape: shape of array indexing in order: rows by row->depth ''' # positions of each voxel z, x, y = np.meshgrid(range(Shape[0]), range(Shape[1]), range(Shape[2]), indexing='ij') x = x[Label.astype(bool)] y = y[Label.astype(bool)] z = z[Label.astype(bool)] VoxelsPos = np.transpose([z, x, y]) return VoxelsPos def GetConnections(Label, Shape, Length): # connections from pathways on array grid Array = (np.reshape(range(Length), Shape) + 1) * Label # incides of voxels in the Array VoxelsIndices = Array[Label.astype(bool)] #-------- path1 = iter( np.transpose( [Array[:, :, 0:-1].ravel(), Array[:, :, 1:].ravel()])) path1 = (i for i in path1 if all(i)) #-------- path2 = iter( np.transpose([ np.swapaxes(Array[:, 0:-1, :], 1, 2).ravel(), np.swapaxes(Array[:, 1:, :], 1, 2).ravel() ])) path2 = (i for i in path2 if all(i)) #-------- path3 = iter( np.transpose([ np.swapaxes(Array[0:-1, :, :], 0, 2).ravel(), np.swapaxes(Array[1:, :, :], 0, 2).ravel() ])) path3 = (i for i in path3 if all(i)) return VoxelsIndices, path1, path2, path3 if self.Sampling is not None: Scale = (1.0 / self.Sampling, 1.0 / self.Sampling, 1.0 / self.Sampling) Label = image.zoom(self.Label.astype(int), Scale) Shape = np.shape(Label) # size of image Length = Shape[0] * Shape[1] * Shape[2] # number of voxels else: Label = self.Label Shape = self.Shape Length = self.Length # voxel indices and thier positions t1 = time() VoxelsPos = VoxelsPositions(Label, Shape, Length) print('create nodes: ' + str(time() - t1)) t1 = time() VoxelsIndices, Connections1, Connections2, Connections3 = GetConnections( Label, Shape, Length) print('create connections: ' + str(time() - t1)) # build graph t1 = time() self.Graph = Graph() self.Graph.add_nodes_from(VoxelsIndices) for ind, p in zip(VoxelsIndices, VoxelsPos): self.Graph.node[ind]['pos'] = p self.Graph.add_edges_from(Connections1) self.Graph.add_edges_from(Connections2) self.Graph.add_edges_from(Connections3) #exclude nodes with less than 2 neighbors NNodesToExclude = 1 while NNodesToExclude > 0: NodesToExclude = [ i for i in self.Graph.GetNodes() if len(self.Graph.GetNeighbors(i)) <= 2 ] self.Graph.remove_nodes_from(NodesToExclude) NNodesToExclude = len(NodesToExclude) if self.Sampling is not None: for i in self.Graph.GetNodes(): self.Graph.node[i][ 'pos'] = self.Graph.node[i]['pos'] * self.Sampling print('create graph: ' + str(time() - t1))
def UpdateWithStitching(self, size, niter1=10, niter2=5, is_parallel=False, n_parallel=5, ret=False): ''' this funtion allow to generate graphs as follows: 1) image patching --> 2) patch-based contraction (fixing boundary nodes) --> 3) graph stitching --> 4) boundary contraction --> 5) global contraction --> refinement it is helpful when graphing large inputs. Inputs: size: dimention of a 3D patch --> [size, size, size] niter1: number of contraction iterations on patches niter2: number of contraction iterations on boundary nodes is_parallel: if True, patch-based contraction will run in parallel using 'ray' n_parallel: number of parallel processes (note: for limited RAM memory, 'n_parallel' should be smaller) ret: if True, this function will return the output graph ''' try: from sklearn import neighbors except: print(' \'scikit-learn\' must be instaled to run this funtion!') if is_parallel: try: import ray except: print( ' \'ray\' must be installed to run patch-based contraction in parallel!' ) GraphParallel = activate_parallel() # obtain distance map #self.label=image.morphology.distance_transform_edt(self.label) self.label = DistMap3D(self.label) # patching print('--Extract patches ...') patches, patchesid = Decompose(self.label, size=size) # extract patches patches_shape = [patches.shape[0], patches.shape[1], patches.shape[2]] print('--Obtain semi-contracted graphs from patches ...') # run contraction avoiding boundary nodes for each patch graphs = [] inds = np.arange(0, len(patchesid), n_parallel) patchesid_ = [patchesid[ind:ind + n_parallel] for ind in inds] for inds in patchesid_: if is_parallel: # in parallel ray.init() subpatches = [ray.put(patches[ind]) for ind in inds] subgraphs = [ GraphParallel.remote( patch, niter=niter1, Sampling=self.sampling, DistParam=self.dist_param, MedParam=self.med_param, SpeedParam=self.speed_param, DegreeThreshold=self.degree_threshold, ClusteringResolution=self.clustering_resolution) for patch in subpatches ] subgraphs = [ray.get(g) for g in subgraphs] ray.shutdown() graphs.append(subgraphs) else: # in serial subpatches = [patches[ind] for ind in inds] subgraphs = [ GraphSerial( patch, niter=niter1, Sampling=self.sampling, DistParam=self.dist_param, MedParam=self.med_param, SpeedParam=self.speed_param, DegreeThreshold=self.degree_threshold, ClusteringResolution=self.clustering_resolution) for patch in subpatches ] subgraphs = [g for g in subgraphs] graphs.append(subgraphs) graphs = [k1 for k in graphs for k1 in k] # uravel del patches # adjust the position of graph nodes coming from each patch area = np.sum([k.Area for k in graphs if k is not None]) pluspos = (size) * np.array(patchesid) for plus, g in zip(pluspos, graphs): if g is not None: AddPos(g, plus) print('--Combine semi-contracted graphs ...') fullgraph = EmptyGraph() nnodes = 0 for idx, g in enumerate(graphs): if g is not None: print(' graph id ' + str(idx) + ' added') nnodes += fullgraph.number_of_nodes() new_nodes = nnodes + np.array(range(g.number_of_nodes())) mapping = dict(zip(g.GetNodes(), new_nodes)) g = nx.relabel_nodes(g, mapping) fullgraph.add_nodes_from(g.GetNodes()) fullgraph.add_edges_from(g.GetEdges()) for k in new_nodes: fullgraph.node[k]['pos'] = g.node[k]['pos'] fullgraph.node[k]['r'] = g.node[k]['r'] fullgraph.node[k]['ext'] = g.node[k]['ext'] else: print(' graph id ' + str(idx) + ' is None') fullgraph = fixG(fullgraph) fullgraph.Area = area del graphs print('--Stitch semi-contracted graphs ...') nodes = np.array( [k for k in fullgraph.GetNodes() if fullgraph.node[k]['ext'] == 1]) nodesid = dict(zip(range(len(nodes)), nodes)) pos = np.array([fullgraph.node[k]['pos'] for k in nodes]) pos_tree = neighbors.KDTree(pos) a = pos_tree.query_radius(pos, r=1.0) new_edges = [[(nodesid[k[0]], nodesid[k1]) for k1 in k[1:]] for k in a] new_edges = [k1 for k in new_edges for k1 in k] fullgraph.add_edges_from(new_edges) del a del nodes del pos del new_edges del pos_tree print('--Contract ext nodes ...') ContractExt(fullgraph, niter=niter2, DistParam=self.dist_param, MedParam=self.med_param, SpeedParam=self.speed_param, DegreeThreshold=self.degree_threshold, ClusteringResolution=self.clustering_resolution) print('--Generate final skeleton ...') contract_final = ContractGraph(Graph=fullgraph) contract_final.Update(DistParam=self.dist_param, MedParam=self.med_param, SpeedParam=self.speed_param, DegreeThreshold=self.degree_threshold, StopParam=self.stop_param, NFreeIteration=self.n_free_iteration) gc = contract_final.GetOutput() print('--Refine final skeleton ...') refine = RefineGraph(Graph=gc) refine.Update() gr = refine.GetOutput() gr = fixG(gr) # ----- return ----# if ret: return gr else: self.Graph = gr