def surf_convert(fsdir, t1files, surffiles, output_directory=None, rm_orig=False, fsconfig="/i2bm/local/freesurfer/SetUpFreeSurfer.sh"): """ Export FreeSurfer surfaces to the native space. Note that all the vetices are given in the index coordinate system. The subjecy id in the t1 and surf files must appear in the -3 position: xxx/subject_id/convert/t1.nii.gz <unit> <input name="fsdir" type="Directory" description="The freesurfer working directory with all the subjects."/> <input name="output_directory" type="Directory" description="The conversion destination folder."/> <input name="t1files" type="List_File" description="The t1 nifti files."/> <input name="surffiles" type="List_File" description="The surface to be converted."/> <input name="rm_orig" type="Bool" description="If true remove the input surfaces."/> <input name="fsconfig" type="File" description="The freesurfer configuration batch."/> <output name="csurffiles" type="List_File" description="The converted surfaces in the native space."/> </unit> """ # Create a t1 subject map t1map = {} for fname in t1files: subject_id = fname.split("/")[-3] if subject_id in t1map: raise ("Can't map two t1 for subject '{0}'.".format(subject_id)) t1map[subject_id] = fname # Convert all the surfaces csurffiles = [] for fname in surffiles: # Get the t1 reference image subject_id = fname.split("/")[-3] t1file = t1map[subject_id] t1_image = nibabel.load(t1file) # Compute the conformed space to the native anatomical deformation asegfile = os.path.join(fsdir, subject_id, "mri", "aseg.mgz") physical_to_index = numpy.linalg.inv(t1_image.get_affine()) translation = tkregister_translation(asegfile, fsconfig) deformation = numpy.dot(physical_to_index, translation) # Load and warp the mesh # The mesh: a 2-uplet with vertex (x, y, z) coordinates and # mesh triangles mesh = freesurfer.read_geometry(fname) surf = TriSurface(vertices=apply_affine_on_mesh(mesh[0], deformation), triangles=mesh[1]) # Save the mesh in the native space outputfile = fname + ".native" surf.save(os.path.dirname(outputfile), os.path.basename(outputfile)) csurffiles.append(outputfile) # Clean input surface if specified if rm_orig: os.remove(fname) return csurffiles
def qc(t1files, wmfiles, asegfiles, whitefiles, pialfiles, annotfiles, actor_ang=[0., 0., 0.], output_directory=None, fsconfig="/i2bm/local/freesurfer/SetUpFreeSurfer.sh"): """ Compute some quality check plots on the converted FrreSurfer outputs. The subjecy id in the input files must appear in the -3 position: xxx/subject_id/convert/t1.nii.gz Steps: * t1-images overlays * 3d surface segmentation snaps * t1-surfaces overlays actor_ang: float (optional, default 0) the actor rotation in the z direction. <unit> <input name="t1files" type="List_File" description="The t1 subject files."/> <input name="wmfiles" type="List_File" description="The white matter subject files."/> <input name="asegfiles" type="List_File" description="The subcortical segmentation subject files."/> <input name="output_directory" type="Directory" description="The conversion destination folder."/> <input name="whitefiles" type="List_File" description="The subject cortex surfaces."/> <input name="pialfiles" type="List_File" description="The subject pial surfaces."/> <input name="annotfiles" type="List_File" description="The pial/white surface annotations."/> <input name="actor_ang" type="List_Float" description="The actor x, y, z position (in degrees)."/> <input name="fsconfig" type="File" description="The freesurfer configuration batch."/> <output name="qcfiles" type="List_File" description="The quality check snaps."/> </unit> """ import clindmri.plot.pvtk as pvtk from clindmri.plot.slicer import plot_image # Create a t1 subject map t1map = {} for fname in t1files: subject_id = fname.split("/")[-3] if subject_id in t1map: raise Exception("Can't map two t1 for subject '{0}'" ".".format(subject_id)) t1map[subject_id] = fname # Create the output list that will contain all the qc files qcfiles = [] # Construct the t1-surfaces overlays and the 3d surface segmentation snaps ren = pvtk.ren() for name, files in [("white", whitefiles), ("pial", pialfiles)]: for fname in files: # Get the t1 reference image subject_id = fname.split("/")[-3] t1file = t1map[subject_id] t1_image = nibabel.load(t1file) # Get the qc output directory qcdir = os.path.join(os.path.dirname(fname), "qc") qcname = os.path.basename(fname) if not os.path.isdir(qcdir): os.makedirs(qcdir) # Get the triangular mesh basename = os.path.basename(fname).replace( name, "aparc.annot").replace(".native", "") annotfile = os.path.join(os.path.dirname(fname), basename) if annotfile not in annotfiles: raise ValueError( "Annotation file '{0}' can't be found.".format(annotfile)) surface = TriSurface.load(fname, annotfile=annotfile) # Construct the surfaces binarized volume binarizedfile = os.path.join(qcdir, qcname + ".nii.gz") overlay = numpy.zeros(t1_image.shape, dtype=numpy.uint) indices = numpy.round(surface.vertices).astype(int).T indices[0, numpy.where(indices[0] >= t1_image.shape[0])] = 0 indices[1, numpy.where(indices[1] >= t1_image.shape[1])] = 0 indices[2, numpy.where(indices[2] >= t1_image.shape[2])] = 0 overlay[indices.tolist()] = 1 overlay_image = nibabel.Nifti1Image(overlay, t1_image.get_affine()) nibabel.save(overlay_image, binarizedfile) snap_file = os.path.join(qcdir, qcname + ".png") plot_image(t1file, overlay_file=binarizedfile, snap_file=snap_file, name=qcname, overlay_cmap="cold_hot") qcfiles.append(snap_file) # Create a vtk surface actor of the cortex surface with the # associated labels ctab = [item["color"] for _, item in surface.metadata.items()] actor = pvtk.surface( surface.vertices, surface.triangles, surface.labels, ctab) actor.RotateX(actor_ang[0]) actor.RotateY(actor_ang[1]) actor.RotateZ(actor_ang[2]) # Create a 3d surface segmentation snap pvtk.add(ren, actor) snaps = pvtk.record(ren, qcdir, qcname, n_frames=36, az_ang=10, animate=True, delay=50) qcfiles.append(snaps[0]) snaps = pvtk.record(ren, qcdir, qcname + ".3d", n_frames=1) qcfiles.append(snaps[0]) pvtk.clear(ren) # Get the FreeSurfer lookup table fs_lut_names, fs_lut_colors = parse_fs_lut(os.path.join( os.path.dirname(fsconfig), "FreeSurferColorLUT.txt")) cmap = [] nb_values = numpy.asarray(fs_lut_colors.keys()).max() cmap = numpy.zeros((nb_values, 4), dtype=numpy.single) for key, color in fs_lut_colors.items(): if key > 0: cmap[key - 1, :3] = color cmap[:, 3] = 200. cmap /= 255. # Compute t1-images overlays for name, files in [("aseg", asegfiles), ("wm", wmfiles)]: for fname in files: # Get the t1 reference image subject_id = fname.split("/")[-3] t1file = t1map[subject_id] t1_image = nibabel.load(t1file) # Get the qc output directory qcdir = os.path.join(os.path.dirname(fname), "qc") if not os.path.isdir(qcdir): os.makedirs(qcdir) # Troncate the color map based on the label max array = nibabel.load(fname).get_data() order = sorted(set(array.flatten())) ccmap = cmap[order[1]: order[-1] + 1] # Overlay the current image with the t1 image qcname = "t1-{0}".format(name) snap_file = os.path.join(qcdir, qcname + ".png") plot_image(t1file, overlay_file=fname, snap_file=snap_file, name=qcname, overlay_cmap=ccmap, cut_coords=(0, 0, 0)) qcfiles.append(snap_file) return qcfiles
def qc_profile(nodif_file, proba_file, proba_texture, ico_order, fsdir, sid, outdir, fsconfig, actor_ang=(0., 0., 0.)): """ Connectivity profile QC. Generates views of: - the superposition of the nodif image with tractography result volume. - the connected points on the cortical surface Resample cortical meshes if needed. Results output are available as gif and png. Parameters ---------- nodif_file: str (mandatory) file for probtrackx2 containing the no diffusion volume and associated space information. proba_file: str (mandatory) the protrackx2 output seeding probabilistic path volume. proba_texture: dict (mandatory) the FreeSurfer mri_vol2surf '.mgz' 'lh' and 'rh' textrue that contains the cortiacal connection strength. ico_order: int (mandatory) icosahedron order in [0, 7] that will be used to generate the cortical surface texture at a specific tessalation (the corresponding cortical surface can be resampled using the 'clindmri.segmentation.freesurfer.resample_cortical_surface' function). fsdir: str (mandatory) FreeSurfer subjects directory 'SUBJECTS_DIR'. sid: str (mandatory) FreeSurfer subject identifier. outdir: str (mandatory) The QC output directory. fsconfig: str (mandatory) the FreeSurfer '.sh' config file. actor_ang: 3-uplet (optinal, default (0, 0, 0)) the actor x, y, z position (in degrees). Returns ------- snaps: list of str two gifs images, one showing the connection profile as a texture on the cortical surface, the other a volumic representation of the deterministic tractography. """ import clindmri.plot.pvtk as pvtk from clindmri.plot.slicer import animate_image # Construct/check the subject directory subjectdir = os.path.join(fsdir, sid) if not os.path.isdir(subjectdir): raise ValueError( "'{0}' is not a FreeSurfer subject directory.".format(subjectdir)) # Check that the output QC directory exists if not os.path.isdir(outdir): os.makedirs(outdir) # Superpose the nodif and probabilistic tractography volumes proba_shape = nibabel.load(proba_file).shape snaps = [] snaps.append( animate_image(nodif_file, overlay_file=proba_file, clean=True, overlay_cmap="Spectral", cut_coords=proba_shape[2], outdir=outdir)) # Define a renderer ren = pvtk.ren() # For each hemisphere for hemi in ["lh", "rh"]: # Get the the white mesh on the desired icosphere meshfile = os.path.join(subjectdir, "convert", "{0}.white.{1}.native".format(hemi, ico_order)) if not os.path.isfile(meshfile): raise ValueError( "'{0}' is not a valid white mesh. Generate it through the " "'clindmri.scripts.freesurfer_conversion' script.".format( meshfile)) # Check texture has the expected extension, size texture_file = proba_texture[hemi] if not texture_file.endswith(".mgz"): raise ValueError("'{0}' is not a '.mgz' file. Format not " "supported.".format(texture_file)) profile_array = nibabel.load(texture_file).get_data() profile_dim = profile_array.ndim profile_shape = profile_array.shape if profile_dim != 3: raise ValueError( "Expected profile texture array of dimension 3 not " "'{0}'".format(profile_dim)) if (profile_shape[1] != 1) or (profile_shape[2] != 1): raise ValueError( "Expected profile texture array of shape (*, 1, 1) not " "'{0}'.".format(profile_shape)) # Flatten the profile texture array texture = profile_array.ravel() # Load the white mesh surface = TriSurface.load(meshfile) # Define a textured surface actor actor = pvtk.surface(surface.vertices, surface.triangles, texture) actor.RotateX(actor_ang[0]) actor.RotateY(actor_ang[1]) actor.RotateZ(actor_ang[2]) pvtk.add(ren, actor) # Create a animaton with the generated surface qcname = "profile_as_texture" snaps.extend( pvtk.record(ren, outdir, qcname, n_frames=36, az_ang=10, animate=True, delay=10)) return snaps
mesharray = numpy.zeros(t1shape, dtype=numpy.uint) for basename in surf: # > construc path fpath = os.path.join(mripath, basename) if not os.path.isfile(fpath): raise ValueError("'{0}' is not a valid file name.".format(fpath)) surf[basename] = fpath # > load mesh name = basename.split(".")[1] annot_basename = basename.replace( name, "aparc.annot").replace(".native", "") annotfile = os.path.join(mripath, annot_basename) if not os.path.isfile(fpath): raise ValueError("'{0}' is not a valid file name.".format(fpath)) surface = TriSurface.load(fpath, annotfile=annotfile) # > binarize mesh indices = numpy.round(surface.vertices).astype(int).T indices[0, numpy.where(indices[0] >= t1shape[0])] = 0 indices[1, numpy.where(indices[1] >= t1shape[1])] = 0 indices[2, numpy.where(indices[2] >= t1shape[2])] = 0 mesharray[indices.tolist()] = colors[basename] # Save the mesh volume meshim = nibabel.Nifti1Image(mesharray, t1affine) nibabel.save(meshim, meshfile) # Need to reorient the image to MNI standard space reomeshfile = os.path.join(qcdir, "reo." + os.path.basename(meshfile)) fslreorient2std(meshfile, reomeshfile, shfile=fslconfig)
def qc(t1files, wmfiles, asegfiles, whitefiles, pialfiles, annotfiles, actor_ang=[0., 0., 0.], output_directory=None, fsconfig="/i2bm/local/freesurfer/SetUpFreeSurfer.sh"): """ Compute some quality check plots on the converted FrreSurfer outputs. The subjecy id in the input files must appear in the -3 position: xxx/subject_id/convert/t1.nii.gz Steps: * t1-images overlays * 3d surface segmentation snaps * t1-surfaces overlays actor_ang: float (optional, default 0) the actor rotation in the z direction. <unit> <input name="t1files" type="List_File" description="The t1 subject files."/> <input name="wmfiles" type="List_File" description="The white matter subject files."/> <input name="asegfiles" type="List_File" description="The subcortical segmentation subject files."/> <input name="output_directory" type="Directory" description="The conversion destination folder."/> <input name="whitefiles" type="List_File" description="The subject cortex surfaces."/> <input name="pialfiles" type="List_File" description="The subject pial surfaces."/> <input name="annotfiles" type="List_File" description="The pial/white surface annotations."/> <input name="actor_ang" type="List_Float" description="The actor x, y, z position (in degrees)."/> <input name="fsconfig" type="File" description="The freesurfer configuration batch."/> <output name="qcfiles" type="List_File" description="The quality check snaps."/> </unit> """ import clindmri.plot.pvtk as pvtk from clindmri.plot.slicer import plot_image # Create a t1 subject map t1map = {} for fname in t1files: subject_id = fname.split("/")[-3] if subject_id in t1map: raise Exception("Can't map two t1 for subject '{0}'" ".".format(subject_id)) t1map[subject_id] = fname # Create the output list that will contain all the qc files qcfiles = [] # Construct the t1-surfaces overlays and the 3d surface segmentation snaps ren = pvtk.ren() for name, files in [("white", whitefiles), ("pial", pialfiles)]: for fname in files: # Get the t1 reference image subject_id = fname.split("/")[-3] t1file = t1map[subject_id] t1_image = nibabel.load(t1file) # Get the qc output directory qcdir = os.path.join(os.path.dirname(fname), "qc") qcname = os.path.basename(fname) if not os.path.isdir(qcdir): os.makedirs(qcdir) # Get the triangular mesh basename = os.path.basename(fname).replace(name, "aparc.annot").replace( ".native", "") annotfile = os.path.join(os.path.dirname(fname), basename) if annotfile not in annotfiles: raise ValueError( "Annotation file '{0}' can't be found.".format(annotfile)) surface = TriSurface.load(fname, annotfile=annotfile) # Construct the surfaces binarized volume binarizedfile = os.path.join(qcdir, qcname + ".nii.gz") overlay = numpy.zeros(t1_image.shape, dtype=numpy.uint) indices = numpy.round(surface.vertices).astype(int).T indices[0, numpy.where(indices[0] >= t1_image.shape[0])] = 0 indices[1, numpy.where(indices[1] >= t1_image.shape[1])] = 0 indices[2, numpy.where(indices[2] >= t1_image.shape[2])] = 0 overlay[indices.tolist()] = 1 overlay_image = nibabel.Nifti1Image(overlay, t1_image.get_affine()) nibabel.save(overlay_image, binarizedfile) snap_file = os.path.join(qcdir, qcname + ".png") plot_image(t1file, overlay_file=binarizedfile, snap_file=snap_file, name=qcname, overlay_cmap="cold_hot") qcfiles.append(snap_file) # Create a vtk surface actor of the cortex surface with the # associated labels ctab = [item["color"] for _, item in surface.metadata.items()] actor = pvtk.surface(surface.vertices, surface.triangles, surface.labels, ctab) actor.RotateX(actor_ang[0]) actor.RotateY(actor_ang[1]) actor.RotateZ(actor_ang[2]) # Create a 3d surface segmentation snap pvtk.add(ren, actor) snaps = pvtk.record(ren, qcdir, qcname, n_frames=36, az_ang=10, animate=True, delay=50) qcfiles.append(snaps[0]) snaps = pvtk.record(ren, qcdir, qcname + ".3d", n_frames=1) qcfiles.append(snaps[0]) pvtk.clear(ren) # Get the FreeSurfer lookup table fs_lut_names, fs_lut_colors = parse_fs_lut( os.path.join(os.path.dirname(fsconfig), "FreeSurferColorLUT.txt")) cmap = [] nb_values = numpy.asarray(fs_lut_colors.keys()).max() cmap = numpy.zeros((nb_values, 4), dtype=numpy.single) for key, color in fs_lut_colors.items(): if key > 0: cmap[key - 1, :3] = color cmap[:, 3] = 200. cmap /= 255. # Compute t1-images overlays for name, files in [("aseg", asegfiles), ("wm", wmfiles)]: for fname in files: # Get the t1 reference image subject_id = fname.split("/")[-3] t1file = t1map[subject_id] t1_image = nibabel.load(t1file) # Get the qc output directory qcdir = os.path.join(os.path.dirname(fname), "qc") if not os.path.isdir(qcdir): os.makedirs(qcdir) # Troncate the color map based on the label max array = nibabel.load(fname).get_data() order = sorted(set(array.flatten())) ccmap = cmap[order[1]:order[-1] + 1] # Overlay the current image with the t1 image qcname = "t1-{0}".format(name) snap_file = os.path.join(qcdir, qcname + ".png") plot_image(t1file, overlay_file=fname, snap_file=snap_file, name=qcname, overlay_cmap=ccmap, cut_coords=(0, 0, 0)) qcfiles.append(snap_file) return qcfiles
def display_folds(folds_file, labels, weights, white_file=None, interactive=True, snap=False, animate=False, outdir=None, name="folds", actor_ang=(0., 0., 0.)): """ Display the folds computed by morphologist. The scene supports one feature activated via the keystroke: * 'p': Pick the data at the current mouse point. This will pop-up a window with information on the current pick (ie. the fold name). Parameters ---------- folds_file: str( mandatory) the folds '.gii' file. labels: dict (mandatory) a mapping between a mesh id and its label. weights: dict (mandatory) a mapping between a mesh label and its wheight in [0, 1]. white_file: str (optional, default None) if specified the white surface will be displayed. interactive: bool (optional, default True) if True display the renderer. snap: bool (optional, default False) if True create a snap of the scene: need a valid outdir. animate: bool (optional, default False) if True create a gif 360 degrees animation of the scene: need a valid outdir. outdir: str (optional, default None) an existing directory. name: str (optional, default 'folds') the basename of the generated files. actor_ang: 3-uplet (optinal, default (0, 0, 0)) the actors x, y, z position (in degrees). """ # Load the folds file image = gio.read(folds_file) nb_of_surfs = len(image.darrays) if nb_of_surfs % 2 != 0: raise ValueError("Need an odd number of arrays (vertices, triangles).") # Create an actor for each fold ren = pvtk.ren() ren.SetBackground(1, 1, 1) for vertindex in range(0, nb_of_surfs, 2): vectices = image.darrays[vertindex].data triangles = image.darrays[vertindex + 1].data labelindex = image.darrays[vertindex].get_metadata()["Timestep"] if labelindex != image.darrays[vertindex + 1].get_metadata()["Timestep"]: raise ValueError("Gifti arrays '{0}' and '{1}' do not share the " "same label.".format(vertindex, vertindex + 1)) labelindex = int(labelindex) if labelindex in labels: label = labels[labelindex] if label in weights: weight = weights[label] * 256. else: weight = 0 else: label = "NC" weight = 0 surf = TriSurface(vectices, triangles, labels=None) actor = pvtk.surface(surf.vertices, surf.triangles, surf.labels + weight) actor.label = label actor.RotateX(actor_ang[0]) actor.RotateY(actor_ang[1]) actor.RotateZ(actor_ang[2]) pvtk.add(ren, actor) # Add the white surface if specified if white_file is not None: image = gio.read(white_file) nb_of_surfs = len(image.darrays) if nb_of_surfs != 2: raise ValueError("'{0}' does not a contain a valid white " "mesh.".format(white_file)) vectices = image.darrays[0].data triangles = image.darrays[1].data surf = TriSurface(vectices, triangles, labels=None) actor = pvtk.surface(surf.vertices, surf.triangles, surf.labels, opacity=1, set_lut=False) actor.label = "white" actor.RotateX(actor_ang[0]) actor.RotateY(actor_ang[1]) actor.RotateZ(actor_ang[2]) pvtk.add(ren, actor) # Show the renderer if interactive: actor = pvtk.text("!!!!", font_size=15, position=(10, 10), is_visible=False) pvtk.add(ren, actor) obs = LabelsOnPick(actor, static_position=True, to_keep_actors=["white"]) pvtk.show(ren, title="morphologist folds", observers=[obs]) # Create a snap if snap: if not os.path.isdir(outdir): raise ValueError("'{0}' is not a valid directory.".format(outdir)) pvtk.record(ren, outdir, name, n_frames=1) # Create an animation if animate: if not os.path.isdir(outdir): raise ValueError("'{0}' is not a valid directory.".format(outdir)) pvtk.record(ren, outdir, name, n_frames=36, az_ang=10, animate=True, delay=25)
def qc_profile(nodif_file, proba_file, proba_texture, ico_order, fsdir, sid, outdir, fsconfig, actor_ang=(0., 0., 0.)): """ Connectivity profile QC. Generates views of: - the superposition of the nodif image with tractography result volume. - the connected points on the cortical surface Resample cortical meshes if needed. Results output are available as gif and png. Parameters ---------- nodif_file: str (mandatory) file for probtrackx2 containing the no diffusion volume and associated space information. proba_file: str (mandatory) the protrackx2 output seeding probabilistic path volume. proba_texture: dict (mandatory) the FreeSurfer mri_vol2surf '.mgz' 'lh' and 'rh' textrue that contains the cortiacal connection strength. ico_order: int (mandatory) icosahedron order in [0, 7] that will be used to generate the cortical surface texture at a specific tessalation (the corresponding cortical surface can be resampled using the 'clindmri.segmentation.freesurfer.resample_cortical_surface' function). fsdir: str (mandatory) FreeSurfer subjects directory 'SUBJECTS_DIR'. sid: str (mandatory) FreeSurfer subject identifier. outdir: str (mandatory) The QC output directory. fsconfig: str (mandatory) the FreeSurfer '.sh' config file. actor_ang: 3-uplet (optinal, default (0, 0, 0)) the actor x, y, z position (in degrees). Returns ------- snaps: list of str two gifs images, one showing the connection profile as a texture on the cortical surface, the other a volumic representation of the deterministic tractography. """ import clindmri.plot.pvtk as pvtk from clindmri.plot.slicer import animate_image # Construct/check the subject directory subjectdir = os.path.join(fsdir, sid) if not os.path.isdir(subjectdir): raise ValueError( "'{0}' is not a FreeSurfer subject directory.".format(subjectdir)) # Check that the output QC directory exists if not os.path.isdir(outdir): os.makedirs(outdir) # Superpose the nodif and probabilistic tractography volumes proba_shape = nibabel.load(proba_file).shape snaps = [] snaps.append( animate_image(nodif_file, overlay_file=proba_file, clean=True, overlay_cmap="Spectral", cut_coords=proba_shape[2], outdir=outdir)) # Define a renderer ren = pvtk.ren() # For each hemisphere for hemi in ["lh", "rh"]: # Get the the white mesh on the desired icosphere meshfile = os.path.join( subjectdir, "convert", "{0}.white.{1}.native".format( hemi, ico_order)) if not os.path.isfile(meshfile): raise ValueError( "'{0}' is not a valid white mesh. Generate it through the " "'clindmri.scripts.freesurfer_conversion' script.".format( meshfile)) # Check texture has the expected extension, size texture_file = proba_texture[hemi] if not texture_file.endswith(".mgz"): raise ValueError("'{0}' is not a '.mgz' file. Format not " "supported.".format(texture_file)) profile_array = nibabel.load(texture_file).get_data() profile_dim = profile_array.ndim profile_shape = profile_array.shape if profile_dim != 3: raise ValueError( "Expected profile texture array of dimension 3 not " "'{0}'".format(profile_dim)) if (profile_shape[1] != 1) or (profile_shape[2] != 1): raise ValueError( "Expected profile texture array of shape (*, 1, 1) not " "'{0}'.".format(profile_shape)) # Flatten the profile texture array texture = profile_array.ravel() # Load the white mesh surface = TriSurface.load(meshfile) # Define a textured surface actor actor = pvtk.surface(surface.vertices, surface.triangles, texture) actor.RotateX(actor_ang[0]) actor.RotateY(actor_ang[1]) actor.RotateZ(actor_ang[2]) pvtk.add(ren, actor) # Create a animaton with the generated surface qcname = "profile_as_texture" snaps.extend( pvtk.record(ren, outdir, qcname, n_frames=36, az_ang=10, animate=True, delay=10)) return snaps
if trf_file is None: trf_file = os.path.join(connectdir, "dmri_to_t1.trf") reg_file = os.path.join(connectdir, "nodif_to_t1.nii.gz") flirt(nodif_file, t1_file, omat=trf_file, out=reg_file, usesqform=False, cost="normmi", dof=6) """ Launch the tractography on the requested point of the cortical surface on the selected hemisphere """ # Load the white mesh in the diffusion space surface = TriSurface.load(whitefile) voxel_diff_to_t1 = flirt2aff(trf_file, nodif_file, t1_file) voxel_t1_to_diff = numpy.linalg.inv(voxel_diff_to_t1) white_diff_vertices = apply_affine_on_mesh(surface.vertices, voxel_t1_to_diff) # Select the vertices of interest if vertices_indices is None: vertices_indices = range(len(surface.vertices)) # Go through all the hemisphere vertices textures = {} for index in vertices_indices: # Select the seeding vertex point = white_diff_vertices[index]
mesharray = numpy.zeros(t1shape, dtype=numpy.uint) for basename in surf: # > construc path fpath = os.path.join(mripath, basename) if not os.path.isfile(fpath): raise ValueError("'{0}' is not a valid file name.".format(fpath)) surf[basename] = fpath # > load mesh name = basename.split(".")[1] annot_basename = basename.replace(name, "aparc.annot").replace(".native", "") annotfile = os.path.join(mripath, annot_basename) if not os.path.isfile(fpath): raise ValueError("'{0}' is not a valid file name.".format(fpath)) surface = TriSurface.load(fpath, annotfile=annotfile) # > binarize mesh indices = numpy.round(surface.vertices).astype(int).T indices[0, numpy.where(indices[0] >= t1shape[0])] = 0 indices[1, numpy.where(indices[1] >= t1shape[1])] = 0 indices[2, numpy.where(indices[2] >= t1shape[2])] = 0 mesharray[indices.tolist()] = colors[basename] # Save the mesh volume meshim = nibabel.Nifti1Image(mesharray, t1affine) nibabel.save(meshim, meshfile) # Need to reorient the image to MNI standard space reomeshfile = os.path.join(qcdir, "reo." + os.path.basename(meshfile)) fslreorient2std(meshfile, reomeshfile, shfile=fslconfig)
If no '.trf' file is provided, register the nodif image on the t1 image to get it. """ if trf_file is None: trf_file = os.path.join(connectdir, "dmri_to_t1.trf") reg_file = os.path.join(connectdir, "nodif_to_t1.nii.gz") flirt(nodif_file, t1_file, omat=trf_file, out=reg_file, usesqform=False, cost="normmi", dof=6) """ Launch the tractography on the requested point of the cortical surface on the selected hemisphere """ # Load the white mesh in the diffusion space surface = TriSurface.load(whitefile) voxel_diff_to_t1 = flirt2aff(trf_file, nodif_file, t1_file) voxel_t1_to_diff = numpy.linalg.inv(voxel_diff_to_t1) white_diff_vertices = apply_affine_on_mesh(surface.vertices, voxel_t1_to_diff) # Select the vertices of interest if vertices_indices is None: vertices_indices = range(len(surface.vertices)) # Go through all the hemisphere vertices textures = {} for index in vertices_indices: # Select the seeding vertex point = white_diff_vertices[index]