Esempio n. 1
0
def loadVertexDataFile(infile):
    """Loads the given Freesurfer vertex data, label, or annotation file.

    This function return different things depending on what ``infile`` is:

     - If ``infile`` is a vertex data file, a ``(nvertices,)`` array is
       returned, containing one value for each vertex in the mesh.

     - If ``infile`` is a ``mgh``/``mgz`` file, the image data is returned
       as-is, with dimensions of length 1 squeezed out (under the assumption
       that the image contains scalar vertex data).

     - If ``infile`` is a vertex label file, a tuple containing the following
       is returned:

       - a ``(n,)`` array, containing the indices of all vertices that are
         specified in the file.

       - a ``(n,)`` array, containing scalar value for each vertex

     - If ``infile`` is a vertex annotation file, a tuple containing the
       following is returned:

       - a ``(n,)`` array  containing the indices of all ``n`` vertices that
         are specified in the file.

       - a ``(l, 5)`` array containing the RGBA colour, and the label value,
         for every label that is specified in the file.

       - A list of length ``l``, containing the names of every label that is
         specified in the file.

    """

    if isVertexDataFile(infile):
        return nibfs.read_morph_data(infile)

    elif isVertexLabelFile(infile):
        return nibfs.read_label(infile, read_scalars=True)

    elif isVertexAnnotFile(infile):

        # nibabel 2.2.1 is broken w.r.t. .annot files.
        # raise ValueError('.annot files are not yet supported')

        labels, lut, names = nibfs.read_annot(infile, orig_ids=False)
        return labels, lut, names

    elif isVertexMGHFile(infile):
        return fslmgh.MGHImage(infile)[:].squeeze()

    else:
        raise ValueError('Unrecognised freesurfer '
                         'file type: {}'.format(infile))
Esempio n. 2
0
def backproject_label(label_file, subj, hemi):
    """Return label indices on individual subject surface."""
    label_verts = fs.read_label(label_file)

    # Define map of label on fsaverage surface
    label = np.zeros(163842, np.int)
    label[label_verts] = 1

    # Reverse normalize and convert to vertex indices
    subj_label = surface_transform(label, subj, hemi)
    subj_label_verts = np.argwhere(subj_label).squeeze()
    return subj_label_verts
Esempio n. 3
0
    def load_label(self, name):
        """Load in a Freesurfer .label file.

        Label files are just text files indicating the vertices included
        in the label. Each Surface instance has a dictionary of labels, keyed
        by the name (which is taken from the file name if not given as an
        argument.

        """
        from nibabel import freesurfer
        label = freesurfer.read_label(
            path.join(self.data_path, 'label',
                      '%s.%s.label' % (self.hemi, name)))
        label_array = np.zeros_like(self.x).astype(np.int)
        label_array[label] = 1
        self.labels[name] = label_array
Esempio n. 4
0
 def img2imgcoord_by_surf(self, target_subject, wf_base_dir=None, source_surface = 'pial', source_map_surface='pial', target_surface='pial'):
     
     if wf_base_dir is None and self.working_dir is not None:
         wf_base_dir = self.working_dir
         
     elif wf_base_dir is None and self.working_dir is None:
         print('Working dir has not been specified, results will be stored in:  ', os.path.abspath('.'))             
         wf_base_dir = os.path.abspath('.')
     
     rois,rois_paths = self.create_surf_roi(extents=2, wf_base_dir= wf_base_dir, wf_name='img2imgcoord_by_surf_roi', surface=source_surface, map_surface=source_map_surface, label2vol=False)
     
     wf = pe.Workflow(name='label2label',base_dir=wf_base_dir)
     for i in range(self.npoints):
         l2l = Label2Label()
         l2l.inputs.hemisphere = self.hemi[i]
         l2l.inputs.subject_id = target_subject
         l2l.inputs.sphere_reg = os.path.join(self.freesurfer_dir, target_subject, 'surf', self.hemi[i]+'.'+'sphere.reg')
         l2l.inputs.white = os.path.join(self.freesurfer_dir, target_subject, 'surf', self.hemi[i]+'.'+'white')
         
         l2l.inputs.source_subject = self.subject
         l2l.inputs.source_label = rois_paths[i]
         l2l.inputs.source_white = os.path.join(self.freesurfer_dir, self.subject, 'surf', self.hemi[i]+'.'+'white')
         l2l.inputs.source_sphere_reg = os.path.join(self.freesurfer_dir, self.subject, 'surf', self.hemi[i]+'.'+'sphere.reg')
         l2l.subjects_dir = self.freesurfer_dir
         l2l_node = pe.Node(l2l,'label2label_{i}'.format(i=i))
         wf.add_nodes([l2l_node])
     try:
         wf.run()
     except RuntimeError:
         pass
   
     for i in range(self.npoints):
         out_label_file = os.path.join(self.freesurfer_dir, target_subject, 'label', os.path.basename(rois_paths[i]).split('.label')[0]+'_converted'+'.label')
         shutil.move(out_label_file, os.path.join(wf_base_dir, 'label2label','label2label_{i}'.format(i=i)))
      
     new_coords = np.zeros((self.npoints,3))    
     for i in range(self.npoints):
         label_file = os.path.join(wf_base_dir, 'label2label','label2label_{i}'.format(i=i),os.path.basename(rois_paths[i]).split('.label')[0]+'_converted'+'.label')
         label_vertices = read_label(label_file)
         label_vertices.sort()
         label = Label(label_vertices,hemi=self.hemi[i],subject=target_subject)
         vertex = label.center_of_mass()
         targ_surf = FreesurferSurf(hemi=label.hemi, surf=target_surface, subject = target_subject, subjects_dir=self.freesurfer_dir)
         new_coords[i,:] = targ_surf.get_coords(vertex)
     return new_coords
Esempio n. 5
0
    def load_label(self, name):
        """Load in a Freesurfer .label file.

        Label files are just text files indicating the vertices included
        in the label. Each Surface instance has a dictionary of labels, keyed
        by the name (which is taken from the file name if not given as an
        argument.

        """
        label = freesurfer.read_label(
            path.join(self.data_path, 'label',
                      '%s.%s.label' % (self.hemi, name)))
        label_array = np.zeros(len(self.x), np.int)
        label_array[label] = 1
        try:
            self.labels[name] = label_array
        except AttributeError:
            self.labels = {name: label_array}
Esempio n. 6
0
    def load_data(self, filename):
        """ Load the data from a surface scalar file

        Parameters
        ----------
        filename: str
            Pathstr to a surface scalar file

        Returns
        -------
        self: a Surface obejct
        """

        if filename.endswith(('.curv', '.sulc', '.volume', '.thickness', '.area')):
            data = np.expand_dims(freesurfer.read_morph_data(filename), axis=-1)

        elif filename.endswith(('.shape.gii', '.func.gii')):
            data = np.expand_dims(nib.load(filename).darrays[0].data, axis=-1)

        elif filename.endswith(('.mgz', '.mgh')):
            data = nib.load(filename).get_data()
            data = data.reshape((data.shape[0], data.shape[-1]))

        elif filename.endswith(('.dscalar.nii', '.dseries.nii')):
            data = nib.load(filename).get_data()
            data = data.T

        elif filename.endswith('.label.gii'):
            data = np.expand_dims(nib.load(filename).darrays[0].data, axis=-1)

        elif filename.endswith('.dlabel.nii'):
            data = nib.load(filename).get_data().T

        elif filename.endswith('.label'):
            data = np.expand_dims(freesurfer.read_label(filename), axis=-1)

        elif filename.endswith('.annot'):
            data, _, _ = freesurfer.read_annot(filename)

        else:
            suffix = os.path.split(filename)[1].split('.')[-1]
            raise ImageFileError('This file format-{} is not supported at present.'.format(suffix))

        self.data = data
Esempio n. 7
0
def doSurfaceCorrelation():
    '''
    This method correlates two surfaces with one another within a certain
    radius and writes out the result as a third surface file

    The input format of all files should be mgh.
    The mask should be an overlay of zeroes and ones.

    Notes:
        To run the whole thing on individual labels, we need to specify the
        path to the label directory that contains the labels for the correct
        hemisphere and template. Then, we can cut out the appropriate part and
        store it in the file.

    Testing:
    - can I load the files that I have transformed with nibabel as morph files?
    '''
    # Stuff that should be defined dynamically elsewhere
    gradientTemp = cf.gradientTemp
    overlayTemp = cf.overlayTemp
    maskTemp = cf.maskTemp
    surfaceTemp = cf.templatePath
    inputDir = cf.correlationInputDir
    radii = cf.radii
    hemispheres = cf.hemipsheres
    score = cf.score
    tempDir = cf.tempDir
    outDir = cf.correlationOutDir
    outName = cf.correlationOutName
    useAbsVals = cf.useAbsVals
    labelPath = cf.labelPath
    doLabel = cf.doLabel

    subjectList = loadSubjectList()

    if doLabel:
        # First, unpack the labels
        findLabels()
        # Load the label list
        f = open(labelPath, 'rb')
        labels = f.readlines()
        f.close()

    labelList = []
    for line in labels:
        label = line.strip()
    labelList.append(label)

    for hemi in hemispheres:
        if hemi == 'lh':
            altHemi = 'L'
        elif hemi == 'rh':
            altHemi = 'R'
        else:
            message = ('Your specified hemisphere (%s) is invalid. Ending' %
                       (hemi))
            raise Exception(message)
        # Load the template, we only need it once
        surfacePath = (surfaceTemp % (hemi))
        surface = sp.fileops.loadSurface(surfacePath)

        for subID in subjectList:
            subDir = os.path.join(inputDir, subID)
            subOutDir = os.path.join(outDir, subID)

            if not os.path.isdir(subOutDir):
                os.makedirs(subOutDir)

            # Generate the paths that we want to look at
            gradientName = (gradientTemp % (subID, altHemi))
            overlayName = (overlayTemp % (subID, hemi))
            overlayName = ('%s.mgh' % overlayName)
            overlayPath = os.path.join(subDir, overlayName)

            maskPath = (maskTemp % (hemi))

            # Check if we have the overlay
            if not os.path.isfile(overlayPath):
                message = ('Could not find overlay at %s.\nQuitting!' %
                           (overlayPath))
                raise Exception(message)

            # Check if we already have the gradient in mgh format
            gradientMgh = ('%s.mgh' % gradientName)
            gradientMghOutPath = os.path.join(subDir, gradientName)
            gradientMghPath = os.path.join(subDir, gradientMgh)
            if not os.path.isfile(gradientMghPath):
                # Get the oneD file
                gradientOneD = ('%s.1D' % (gradientName))
                gradientOneDPath = os.path.join(subDir, gradientOneD)
                if not os.path.isfile(gradientOneDPath):
                    message = (
                        'Could not find either 1D or mgh gradient in %s\n(%s / %s)'
                        % (subDir, gradientOneDPath, gradientMghPath))
                    raise Exception(message)
                # Generate the mgh file
                tempOneD = sp.fileops.loadVector(gradientOneDPath)
                tempOutName = ('%s_temp' % gradientName)
                tempOut = os.path.join(tempDir, tempOutName)
                outStr = sp.fileops.writeVector(surface,
                                                tempOneD,
                                                mode='ascii')
                savePath = sp.fileops.saveTxt(tempOut,
                                              outStr,
                                              'asc',
                                              hemi=hemi)
                sp.fileops.convertMorphAsciiMgh(savePath,
                                                surfacePath,
                                                outType='mgh',
                                                outPath=gradientMghOutPath)

            # Get the files loaded
            gradient = sp.fileops.loadScalar(gradientMghPath)
            overlay = sp.fileops.loadScalar(overlayPath)
            if useAbsVals:
                overlay = np.abs(overlay)
            keepVerteces = sp.fileops.loadVector(maskPath, drop=2)

            # Construct a graph to represent the surface
            graph, numberVerteces = sp.procops.buildGraph(surface,
                                                          weighted=True)
            # Truncate the graph based on the mask
            truncGraph = sp.procops.keepNodes(graph, keepVerteces)

            # For each radius, correlate the two values
            for radius in radii:
                # Generate the distance dictionary for the current radius
                distanceDict = sp.procops.buildNeighbors(truncGraph, radius)
                vertVec = sp.procops.slideRoiValues(numberVerteces,
                                                    keepVerteces,
                                                    distanceDict,
                                                    gradient,
                                                    morphVec2=overlay,
                                                    score=score)
                # Generate the output paths
                tempName = (outName % (subID, radius, hemi))
                saveName = (outName % (subID, radius, hemi))

                if doLabel:
                    # Get the label vector and take the average of the
                    # correlation map
                    #
                    # make a storage vector for the label processing
                    labelVec = np.zeros_like(vertVec)
                    for label in labelList:
                        # make label name
                        labelName = os.path.basename(label)
                        # read the label
                        labVec = nfs.read_label(label)
                        # use the indices to take a slice out of the overlay
                        sliceVec = vertVec[labVec]
                        # take the average of that slice
                        avgSlice = np.mean(sliceVec)
                        # and write it back into the appropriate verteces
                        labelVec[labVec] = avgSlice

                    # Adjust the names for the save files
                    tempName = ('%s_label' % tempName)
                    saveName = ('%s_label' % outName)

                    outVec = labelVec
                else:
                    # If we are not using label computation, just write the
                    # vertex-vise vector
                    outVec = vertVec

                # Generate the paths for the output
                tempOut = os.path.join(tempDir, tempName)
                saveOut = os.path.join(subOutDir, saveName)

                # Generate the output files
                outStr = sp.fileops.writeVector(surface, outVec, mode='ascii')
                savePath = sp.fileops.saveTxt(tempOut,
                                              outStr,
                                              'asc',
                                              hemi=hemi)
                sp.fileops.convertMorphAsciiMgh(savePath,
                                                surfacePath,
                                                outType='mgh',
                                                outPath=saveOut)
"""
The easiest way to label any vertex that could be in the region is with
add_label.
"""
brain.add_label("BA1", color="#A6BDDB")

"""
You can also threshold based on the probability of that region being at each
vertex.
"""
brain.add_label("BA1", color="#2B8CBE", scalar_thresh=.5)

"""
It's also possible to plot just the label boundary, in case you wanted to
overlay the label on an activation plot to asses whether it falls within that
region.
"""
brain.add_label("BA45", color="#F0F8FF", borders=3, scalar_thresh=.5)
brain.add_label("BA45", color="#F0F8FF", alpha=.3, scalar_thresh=.5)

"""
Finally, with a few tricks, you can display the whole probabilistic map.
"""
subjects_dir = environ["SUBJECTS_DIR"]
label_file = join(subjects_dir, "fsaverage", "label", "lh.BA6.label")

prob_field = np.zeros_like(brain._geo.x)
ids, probs = read_label(label_file, read_scalars=True)
prob_field[ids] = probs
brain.add_data(prob_field, thresh=1e-5, colormap="RdPu")
                      min=-.8,
                      max=.8,
                      colorbar=False)
"""
The easiest way to label any vertex that could be in the region is with
add_label.
"""
brain.add_label("BA1", color="#A6BDDB")
"""
You can also threshold based on the probability of that region being at each
vertex.
"""
brain.add_label("BA1", color="#2B8CBE", scalar_thresh=.5)
"""
It's also possible to plot just the label boundary, in case you wanted to
overlay the label on an activation plot to asses whether it falls within that
region.
"""
brain.add_label("BA45", color="#F0F8FF", borders=3, scalar_thresh=.5)
brain.add_label("BA45", color="#F0F8FF", alpha=.3, scalar_thresh=.5)
"""
Finally, with a few tricks, you can display the whole probabilistic map.
"""
subjects_dir = environ["SUBJECTS_DIR"]
label_file = join(subjects_dir, "fsaverage", "label", "lh.BA6.label")

prob_field = np.zeros_like(brain.geo['lh'].x)
ids, probs = read_label(label_file, read_scalars=True)
prob_field[ids] = probs
brain.add_data(prob_field, thresh=1e-5, colormap="RdPu")
def doSurfaceCorrelation():
    '''
    This method correlates two surfaces with one another within a certain
    radius and writes out the result as a third surface file

    The input format of all files should be mgh.
    The mask should be an overlay of zeroes and ones.

    Notes:
        To run the whole thing on individual labels, we need to specify the
        path to the label directory that contains the labels for the correct
        hemisphere and template. Then, we can cut out the appropriate part and
        store it in the file.

    Testing:
    - can I load the files that I have transformed with nibabel as morph files?
    '''
    # Stuff that should be defined dynamically elsewhere
    gradientTemp = cf.gradientTemp
    overlayTemp = cf.overlayTemp
    maskTemp = cf.maskTemp
    surfaceTemp = cf.templatePath
    inputDir = cf.correlationInputDir
    radii = cf.radii
    hemispheres = cf.hemipsheres
    score = cf.score
    tempDir = cf.tempDir
    outDir = cf.correlationOutDir
    outName = cf.correlationOutName
    useAbsVals = cf.useAbsVals
    labelPath = cf.labelPath
    doLabel = cf.doLabel

    subjectList = loadSubjectList()

    if doLabel:
        # First, unpack the labels
        findLabels()
        # Load the label list
        f = open(labelPath, 'rb')
        labels = f.readlines()
        f.close()

    labelList = []
    for line in labels:
        label = line.strip()
    labelList.append(label)

    for hemi in hemispheres:
        if hemi == 'lh':
            altHemi = 'L'
        elif hemi == 'rh':
            altHemi = 'R'
        else:
            message = ('Your specified hemisphere (%s) is invalid. Ending' % (hemi))
            raise Exception(message)
        # Load the template, we only need it once
        surfacePath = (surfaceTemp % (hemi))
        surface = sp.fileops.loadSurface(surfacePath)

        for subID in subjectList:
            subDir = os.path.join(inputDir, subID)
            subOutDir = os.path.join(outDir, subID)

            if not os.path.isdir(subOutDir):
                os.makedirs(subOutDir)

            # Generate the paths that we want to look at
            gradientName = (gradientTemp % (subID, altHemi))
            overlayName = (overlayTemp % (subID, hemi))
            overlayName = ('%s.mgh' % overlayName)
            overlayPath = os.path.join(subDir, overlayName)

            maskPath = (maskTemp % (hemi))

            # Check if we have the overlay
            if not os.path.isfile(overlayPath):
                message = ('Could not find overlay at %s.\nQuitting!' % (overlayPath))
                raise Exception(message)

            # Check if we already have the gradient in mgh format
            gradientMgh = ('%s.mgh' % gradientName)
            gradientMghOutPath = os.path.join(subDir, gradientName)
            gradientMghPath = os.path.join(subDir, gradientMgh)
            if not os.path.isfile(gradientMghPath):
                # Get the oneD file
                gradientOneD = ('%s.1D' % (gradientName))
                gradientOneDPath = os.path.join(subDir, gradientOneD)
                if not os.path.isfile(gradientOneDPath):
                    message = ('Could not find either 1D or mgh gradient in %s\n(%s / %s)' % (subDir, gradientOneDPath, gradientMghPath))
                    raise Exception(message)
                # Generate the mgh file
                tempOneD = sp.fileops.loadVector(gradientOneDPath)
                tempOutName = ('%s_temp' % gradientName)
                tempOut = os.path.join(tempDir, tempOutName)
                outStr = sp.fileops.writeVector(surface, tempOneD, mode='ascii')
                savePath = sp.fileops.saveTxt(tempOut, outStr, 'asc',
                                              hemi=hemi)
                sp.fileops.convertMorphAsciiMgh(savePath, surfacePath,
                                                outType='mgh',
                                                outPath=gradientMghOutPath)

            # Get the files loaded
            gradient = sp.fileops.loadScalar(gradientMghPath)
            overlay = sp.fileops.loadScalar(overlayPath)
            if useAbsVals:
                overlay = np.abs(overlay)
            keepVerteces = sp.fileops.loadVector(maskPath, drop=2)

            # Construct a graph to represent the surface
            graph, numberVerteces = sp.procops.buildGraph(surface,
                                                          weighted=True)
            # Truncate the graph based on the mask
            truncGraph = sp.procops.keepNodes(graph, keepVerteces)

            # For each radius, correlate the two values
            for radius in radii:
                # Generate the distance dictionary for the current radius
                distanceDict = sp.procops.buildNeighbors(truncGraph, radius)
                vertVec = sp.procops.slideRoiValues(numberVerteces, keepVerteces,
                                                    distanceDict, gradient,
                                                    morphVec2=overlay, score=score)
                # Generate the output paths
                tempName = (outName % (subID, radius, hemi))
                saveName = (outName % (subID, radius, hemi))

                if doLabel:
                    # Get the label vector and take the average of the
                    # correlation map
                    #
                    # make a storage vector for the label processing
                    labelVec = np.zeros_like(vertVec)
                    for label in labelList:
                        # make label name
                        labelName = os.path.basename(label)
                        # read the label
                        labVec = nfs.read_label(label)
                        # use the indices to take a slice out of the overlay
                        sliceVec = vertVec[labVec]
                        # take the average of that slice
                        avgSlice = np.mean(sliceVec)
                        # and write it back into the appropriate verteces
                        labelVec[labVec] = avgSlice

                    # Adjust the names for the save files
                    tempName = ('%s_label' % tempName)
                    saveName = ('%s_label' % outName)

                    outVec = labelVec
                else:
                    # If we are not using label computation, just write the
                    # vertex-vise vector
                    outVec = vertVec

                # Generate the paths for the output
                tempOut = os.path.join(tempDir, tempName)
                saveOut = os.path.join(subOutDir, saveName)

                # Generate the output files
                outStr = sp.fileops.writeVector(surface, outVec, mode='ascii')
                savePath = sp.fileops.saveTxt(tempOut, outStr, 'asc',
                                              hemi=hemi)
                sp.fileops.convertMorphAsciiMgh(savePath, surfacePath,
                                                outType='mgh',
                                                outPath=saveOut)