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