示例#1
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