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))
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
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
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
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}
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
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)