示例#1
0
def qc_tractography_masks(outdir,
                          nodif_brain,
                          tracto_mask,
                          seed_masks,
                          subject_id,
                          cortical_atlas  = "Desikan",
                          fs_subjects_dir = None,
                          subdir          = "qc"):
    """
    Function meant to help quality check (qc) the masks created by the
    create_masks_for_tractography function.
    It creates snap shots to visualize the quality of the registration
    of the tractography mask (white matter) and seed masks in the diffusion space.

    The snap shots are saved in <outdir>/<subdir>/<snap shot>. By default
    <subdir> is "qc". To write in outdir directly, set subdir to anything that
    evaluates to False (empty string or None).
    Directories are automatically created if they don't exist.

    <unit>
        <input name="outdir"          type="Directory"           />
        <input name="nodif_brain"     type="File"                />
        <input name="tracto_mask"     type="File"                />
        <input name="seed_masks"      type="List" content="File" />
        <input name="subject_id"      type="Str"                 />
        <input name="cortical_atlas"  type="Str"                 />
        <input name="fs_subjects_dir" type="Directory"           />
        <input name="subdir"          type="Str"                 />

        <output name="qc_dir"         type="Directory"           />
    </unit>
    """

    if fs_subjects_dir is None:
        if "SUBJECTS_DIR" in os.environ:
            fs_subjects_dir = os.environ["SUBJECTS_DIR"]
        else:
            raise ValueError("Missing <SUBJECTS_DIR>: set the $SUBJECTS_DIR "
                             "environment variable for Freesurfer or pass it "
                             "as an argument.")

    # If requested use a subdirectory in outdir
    if subdir:
        outdir = os.path.join(outdir, subdir)

    # If outdir does not exist, create it
    if not os.path.isdir(outdir):
        os.makedirs(outdir)

    nb_slices_in_z = nibabel.load(nodif_brain).get_shape()[2]

    # Snap shot for registration and white matter mask checking
    wm_mask_to_dif_png = os.path.join(outdir, "tracto_mask.png")
    plot_image(nodif_brain,
               overlay_file = tracto_mask,
               snap_file    = wm_mask_to_dif_png,
               name         = "White matter mask in diffusion",
               cut_coords   = nb_slices_in_z/2)

    # Gif of white matter mask in diffusion
    animate_image(nodif_brain, overlay_file=tracto_mask, outdir=outdir,
                  name="tracto_mask", cut_coords=nb_slices_in_z/2,
                  clean=True)

    # Return something for Capsul
    qc_dir = outdir
    return qc_dir
示例#2
0
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
示例#3
0
def qc_dif2anat_registration(outdir,
                             nodif_brain,
                             dif2anat_dat,
                             subject_id,
                             fs_subjects_dir = None,
                             subdir          = "qc"):
    """
    Function meant to help quality check (qc) the registration between
    the diffusion and the anatomy (T1 from Freesurfer recon-all).
    It creates snap shots to help with the visualization:
        - T1 brain registered in diffusion + contour of nodif brain volume.

    The snap shot is saved in <outdir>/<subdir>/"t1_to_diff.pdf". By default
    <subdir> is "qc". To write in outdir directly, set subdir to anything that
    evaluates to False (empty string or None).
    Directories are automatically created if they don't exist.

    <unit>
        <input name="outdir"          type="Directory" />
        <input name="nodif_brain"     type="File"      />
        <input name="dif2anat_dat"    type="File"      />
        <input name="subject_id"      type="Str"       />
        <input name="fs_subjects_dir" type="Directory" />
        <input name="subdir"          type="Str"       />

        <output name="qc_dir"         type="Directory" />
    </unit>
    """

    if fs_subjects_dir is None:
        if "SUBJECTS_DIR" in os.environ:
            fs_subjects_dir = os.environ["SUBJECTS_DIR"]
        else:
            raise ValueError("Missing <SUBJECTS_DIR>: set the $SUBJECTS_DIR "
                             "environment variable for Freesurfer or pass it "
                             "as an argument.")

    # If requested use a subdirectory in outdir
    if subdir:
        outdir = os.path.join(outdir, subdir)

    # If outdir does not exist, create it
    if not os.path.isdir(outdir):
        os.makedirs(outdir)

    # Paths
    t1        = os.path.join(fs_subjects_dir, subject_id, "mri/brainmask.mgz")
    t1_to_dif = os.path.join(outdir, "t1_to_dif.nii.gz")

    # Project T1 in dif
    cmd = ["mri_vol2vol", "--mov", nodif_brain, "--targ", t1,
           "--inv", "--interp", "nearest", "--o", t1_to_dif,
           "--reg", dif2anat_dat, "--no-save-reg"]
    fsprocess = FSWrapper(cmd)
    fsprocess()  # Run
    if fsprocess.exitcode != 0:
        raise FreeSurferRuntimeError(cmd[0], " ".join(cmd[1:]))

    nb_slices_in_z = nibabel.load(nodif_brain).get_shape()[2]

    # Gif of the T1 in diffusion space with diffusion edges
    animate_image(t1_to_dif, edge_file=nodif_brain, outdir=outdir,
                  name="t1_to_dif", cut_coords=nb_slices_in_z/2, clean=True)

    # First png: T1 registered in diffusion with nodif edges
    t1_with_nodif_edges_png = os.path.join(outdir, "t1_with_nodif_edges.png")
    plot_image(t1_to_dif,
               edge_file  = nodif_brain,
               snap_file  = t1_with_nodif_edges_png,
               name       = "T1 in diffusion + edges of nodif",
               cut_coords = nb_slices_in_z/2)

    # Second png: nodif with edges of T1 registered in diffusion
    nodif_with_t1_edges_png = os.path.join(outdir, "nodif_with_t1_edges.png")
    plot_image(nodif_brain,
               edge_file  = t1_to_dif,
               snap_file  = nodif_with_t1_edges_png,
               name       = "nodif + edges of registered T1",
               cut_coords = nb_slices_in_z/2)

#    # Third png: nodif with WM edges (from T1 segmentation)
#    nodif_with_wm_edges_png = os.path.join(outdir, "nodif_with_wm_edges.png")
#    plot_image(nodif_brain,
#               edge_file  = t1_to_dif,
#               snap_file  = nodif_with_t1_edges_png,
#               name       = "nodif + edges of registered T1",
#               cut_coords = nb_slices_in_z/2)

    # Return something for Capsul
    qc_dir = outdir

    return qc_dir
示例#4
0
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