Exemplo n.º 1
0
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
Exemplo n.º 2
0
    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
Exemplo n.º 3
0
 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
Exemplo n.º 4
0
    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
Exemplo n.º 6
0
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 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
Exemplo n.º 8
0
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
Exemplo n.º 9
0
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
Exemplo n.º 10
0
    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 
Exemplo n.º 11
0
    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