Beispiel #1
0
 def test_bet2(self, mock_setenv):
     """ Test the FSL 'bet2' command wrapping.
     """
     expected_files = ("/my/path/mock_output.nii.gz",
                       "/my/path/mock_output_mask.nii.gz",
                       "/my/path/mock_output_mesh.vtk", None,
                       "/my/path/mock_output_inskull_mask.nii.gz",
                       "/my/path/mock_output_inskull_mesh.nii.gz",
                       "/my/path/mock_output_outskull_mask.nii.gz",
                       "/my/path/mock_output_outskull_mesh.nii.gz",
                       "/my/path/mock_output_outskin_mask.nii.gz",
                       "/my/path/mock_output_outskin_mesh.nii.gz",
                       "/my/path/mock_output_skull_mask.nii.gz")
     mock_setenv.return_value = self.mock_fslenv
     mock_input = "/my/path/mock_input.nii.gz"
     mock_output = "/my/path/mock_output"
     output_files = bet2(mock_input,
                         mock_output,
                         f=0.5,
                         m=True,
                         shfile="mock.sh",
                         s=True,
                         e=True)
     self.assertTrue(self.mock_popen.called)
     self.assertTrue(output_files == expected_files)
 def test_bet2(self, mock_setenv):
     """ Test the FSL 'bet2' command wrapping.
     """
     expected_files = (
         "/my/path/mock_output.nii.gz",
         "/my/path/mock_output_mask.nii.gz",
         "/my/path/mock_output_mesh.vtk",
         None,
         "/my/path/mock_output_inskull_mask.nii.gz",
         "/my/path/mock_output_inskull_mesh.nii.gz",
         "/my/path/mock_output_outskull_mask.nii.gz",
         "/my/path/mock_output_outskull_mesh.nii.gz",
         "/my/path/mock_output_outskin_mask.nii.gz",
         "/my/path/mock_output_outskin_mesh.nii.gz",
         "/my/path/mock_output_skull_mask.nii.gz",
     )
     mock_setenv.return_value = self.mock_fslenv
     mock_input = "/my/path/mock_input.nii.gz"
     mock_output = "/my/path/mock_output"
     output_files = bet2(mock_input, mock_output, f=0.5, m=True, shfile="mock.sh", s=True, e=True)
     self.assertTrue(self.mock_popen.called)
     self.assertTrue(output_files == expected_files)
# create a pdf snap of the b0 image
if args.graphics:
    snap_file = os.path.join(qcdir, "nodif.pdf")
    plot_image(b0_file, snap_file=snap_file, name="nodif")

# generate a brain mask on the corrected b0 data
b0_brain_file = os.path.join(subjdir, "nodif_brain")
bet_files = glob.glob(b0_brain_file + "*")
if len(bet_files) == 0:
    (output, mask_file, mesh_file, outline_file,
     inskull_mask_file, inskull_mesh_file,
     outskull_mask_file, outskull_mesh_file, outskin_mask_file,
     outskin_mesh_file, skull_mask_file) = bet2(
        b0_file,
        b0_brain_file,
        m=True,
        f=0.25,
        shfile=args.fslconfig)
else:
    mask_file = sorted(bet_files)[0]
    if not os.path.isfile(mask_file):
        raise IOError("FileDoesNotExist: '{0}'.".format(mask_file))

# create a pdf snap of the brain mask
if args.graphics:
    snap_file = os.path.join(qcdir, "bet.pdf")
    plot_image(b0_file, contour_file=mask_file, snap_file=snap_file, name="bet")


"""
Generating PDFs
Beispiel #4
0
def bet2_nodif_brain(outdir, dwi, bval, subdir="bet2_nodif_brain", qc=True):
    """
    Extract brain from b0 volume, i.e. in DW data for a volume where bvalue=0.

    Parameters
    ----------
    outdir: Str, path to directory where to output.
    dwi:    Str, path to DW data in which at least one volume was acquired
            with bvalue=0.
    bval:   Str, path to .bval file associated to the DW data.
    subdir: Str, if you want the result files to be written in a subdirectory,
            specify the name, by default "bet2_nodif_brain".

    Return
    ------
    nodif_brain:      Str, path to the brain only volume.
    nodif_brain_mask: Str, path to the brain-only binary mask.

    <unit>
        <output name="nodif_brain"      type="File"      />
        <output name="nodif_brain_mask" type="File"      />

        <input name="outdir"            type="Directory" />
        <input name="dwi"               type="File"      />
        <input name="bval"              type="File"      />
        <input name="subdir"            type="Str"       />
        <input name="qc"                type="Bool"      />
    </unit>
    """
    if subdir:
        outdir = os.path.join(outdir, subdir)

    # Create outdir if it does not exist
    if not os.path.isdir(outdir):
        os.makedirs(outdir)

    # Get a/the volume with bvalue=0.
    nodif_volume = extract_nodif_volume(outdir, dwi, bval)

    # Set output path with desired prefix name
    output_prefix = os.path.join(outdir, "nodif_brain")

    # Run FSL bet2
    bet2(nodif_volume, output_prefix, f=0.25, m=True)

    # Output paths
    nodif_brain      = output_prefix + ".nii.gz"
    nodif_brain_mask = output_prefix + "_mask.nii.gz"

    # Check existence of resulting files
    if not (os.path.isfile(nodif_brain) and os.path.isfile(nodif_brain_mask)):
        raise Exception("bet2: output file(s) missing: %s or/and %s ."
                        % (nodif_brain, nodif_brain_mask))

    # If Quality Check, generate a PNG snapshot
    if qc:
        # Snap shot of brain-only contour on T2 image
        brain_contour_png = os.path.join(outdir, "nodif_brain_mask.png")
        plot_image(nodif_volume, contour_file=nodif_brain_mask,
                   snap_file=brain_contour_png, name="nodif_brain_mask")

    return nodif_brain, nodif_brain_mask
Beispiel #5
0
bvals = numpy.loadtxt(bvals_file).tolist()
b0_index = bvals.index(0)
b0_file = os.path.join(outdir, "nodif.nii.gz")
if not os.path.isfile(b0_file):
    extract_image(diffusion_file, index=b0_index, out_file=b0_file)

snap_file = os.path.join(qcdir, "nodif.pdf")
plot_image(b0_file, snap_file=snap_file, name="nodif")

b0_brain_file = os.path.join(outdir, "nodif_brain")
bet_files = glob.glob(b0_brain_file + "*")
if len(bet_files) == 0:
    (output, mask_file, mesh_file, outline_file, inskull_mask_file,
     inskull_mesh_file, outskull_mask_file, outskull_mesh_file,
     outskin_mask_file, outskin_mesh_file,
     skull_mask_file) = bet2(b0_file, b0_brain_file, m=True, f=0.25)
else:
    mask_file = sorted(bet_files)[0]
    if not os.path.isfile(mask_file):
        raise IOError("FileDoesNotExist: '{0}'.".format(mask_file))

snap_file = os.path.join(qcdir, "bet.pdf")
plot_image(b0_file, contour_file=mask_file, snap_file=snap_file, name="bet")
"""
Generating the FA image
-----------------------

There are much better ways to create an FA image than this method, but we're
only using this image for registration purposes. It is probably not a good
idear to use this image in a whole-brain FA analysis.
"""
Beispiel #6
0
        index=b0_index,
        out_file=b0_file)

snap_file = os.path.join(qcdir, "nodif.pdf")
plot_image(b0_file, snap_file=snap_file, name="nodif")


b0_brain_file = os.path.join(outdir, "nodif_brain")
bet_files = glob.glob(b0_brain_file + "*")
if len(bet_files) == 0:
    (output, mask_file, mesh_file, outline_file,
     inskull_mask_file, inskull_mesh_file,
     outskull_mask_file, outskull_mesh_file, outskin_mask_file,
     outskin_mesh_file, skull_mask_file) = bet2(
        b0_file,
        b0_brain_file,
        m=True,
        f=0.25)
else:
    mask_file = sorted(bet_files)[0]
    if not os.path.isfile(mask_file):
        raise IOError("FileDoesNotExist: '{0}'.".format(mask_file))

snap_file = os.path.join(qcdir, "bet.pdf")
plot_image(b0_file, contour_file=mask_file, snap_file=snap_file, name="bet")

"""
Generating the FA image
-----------------------

There are much better ways to create an FA image than this method, but we're
def brainsuite_susceptibility_correction(outdir,
                                         dwi,
                                         bval,
                                         bvec,
                                         subject_id,
                                         phase_enc_dir,
                                         subjects_dir=None,
                                         qc_dir=None,
                                         bdp_nthread=4):
    """
    Assuming the beginning of the preprocessing was done with Connectomist
    up to Eddy current and motion correction, we now want to make susceptbility
    distortion correction using Brainsuite.

    Parameters
    ----------
    outdir: str
        Path to directory where to output.
    dwi: str
        Path to the preprocessed diffusion-weighted Nifti.
    bval: str
        Path to the bval file associated to the Nifti.
    bvec: str
        Path to the bvec file associated to the Nifti.
    subject_id: str
        Subject identifier used in Freesurfer.
    phase_enc_dir: str
        In plane phase encoding direction, "y", "y-", "x" or "x-".
    subjects_dir: str, default None
        If the Freesurfer $SUBJECTS_DIR environment variable is not set, or to
        bypass it, pass the path.
    qc_dir: str, default None
        Path to directory where to output snapshots for QC. By default in
        outdir.
    bdp_nthread: int, default 4
        Number of threads for bdp (see bdp.sh --thread flag)
    """

    # Freesurfer 'subjects_dir' has to be passed or set as environment variable
    subjects_dir = get_or_check_freesurfer_subjects_dir(subjects_dir)

    # Check in plane phase encoding direction
    # The sign of the phase encoding direction has no impact in this strategy
    # e.g. for "+y" or "-y" use "y"
    possible_phase_enc_dirs = {"y", "x"}
    if phase_enc_dir not in possible_phase_enc_dirs:
        raise ValueError(
            "Bad argument 'phase_enc_dir': {}, should be in {}.".format(
                phase_enc_dir, possible_phase_enc_dirs))

    # Set and check path to T1 brain-only volume from Freesurfer (mgz format)
    t1_brain_mgz = os.path.join(subjects_dir, subject_id, "mri/brain.mgz")
    if not os.path.isfile(t1_brain_mgz):
        raise Exception("Missing file: {}".format(t1_brain_mgz))

    # Convert Freesurfer T1 to Nifti with reorientation to RAS (to be in the
    # same orientation as the diffusion data)
    t1_brain_RAS_nii = os.path.join(outdir, "t1_brain.nii.gz")
    cmd = [
        "mri_convert", t1_brain_mgz, t1_brain_RAS_nii, "--out_orientation",
        "RAS"
    ]
    run_freesurfer_cmd(cmd, subjects_dir=subjects_dir)

    # Run bfc (bias correction: required by BrainSuite)
    t1_bfc = os.path.join(outdir, "t1_brain.bfc.nii.gz")
    cmd = ["bfc", "-i", t1_brain_RAS_nii, "-o", t1_bfc]
    subprocess.check_call(cmd)

    # Extract brain from the nodif volume with FSL bet2
    nodif_brain = os.path.join(outdir, "nodif_brain.nii.gz")
    bet2(dwi, nodif_brain, f=0.25, m=False)

    # Run bdp.sh: registration + diffusion model
    cmd = [
        "bdp.sh", t1_bfc, "--nii", dwi, "--bval", bval, "--bvec", bvec,
        "--dwi-mask", nodif_brain,
        "--dir=%s" % phase_enc_dir,
        "--threads=%i" % bdp_nthread
    ]
    subprocess.check_call(cmd)

    # Path to files of interest, created by BrainSuite bdp.sh
    dwi_wo_susceptibility = os.path.join(outdir,
                                         "t1_brain.dwi.RAS.correct.nii.gz")

    ###############
    # Quality check: create snapshots to visually assert the registration
    # quality

    if qc_dir is None:
        qc_dir = outdir

    # The snapshots won't contain all slices, half of them
    nb_slices_in_z = nibabel.load(nodif_brain).get_shape()[2]

    # Path to registered T1
    t1_to_dif = os.path.join(outdir, "t1_brain.D_coord.nii.gz")

    # First png: T1 registered in diffusion with nodif edges
    t1_with_nodif_edges_png = os.path.join(qc_dir, "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(qc_dir, "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)

    return dwi_wo_susceptibility, bval, bvec
def complete_preproc_wo_fieldmap(outdir,
                                 dwi,
                                 bval,
                                 bvec,
                                 phase_enc_dir,
                                 subject_id,
                                 subjects_dir=None,
                                 invertX=True,
                                 invertY=False,
                                 invertZ=False,
                                 delete_steps=False):
    """
    Function that runs all preprocessing steps using Connectomist but
    with BrainSuite for the correction of susceptibility distortions.

    Parameters
    ----------
    outdir: str
        Path to directory where all the preprocessing will be done.
    dwi: str
        path to input diffusion-weighted Nifti data.
    bval: str
        Path to the Nifti's associated .bval file.
    bvec: str
        Ppath to Nifti's associated .bval file.
    phase_enc_dir: str
        In plane phase encoding direction, "y", "y-", "x" or "x-".
    subject_id: str
        Subject identifier used in Freesurfer.
    subjects_dir: Str, default None
        If the Freesurfer $SUBJECTS_DIR environment variable is not set, or to
        bypass it, pass the path.
    invertX: bool, default True
        If True invert x-axis in diffusion model.
    invertY: bool, default False
        Same as invertX but for y-axis.
    invertZ: bool, default False
        Same as invertX but for z-axis.
    delete_steps: bool
        If True remove all intermediate files and directories at the end of
        preprocessing, to keep only selected files:
        - preprocessed Nifti + bval + bvec + outliers.py + nodif_brain*.nii.gz

    Returns
    -------
    outdir: str,
        Path to directory with the preprocessed files.

    <unit>
        <output name="preproc_dwi"  type="File"      />
        <output name="preproc_bval" type="File"      />
        <output name="preproc_bvec" type="File"      />

        <input name="outdir"        type="Directory" />
        <input name="dwi"           type="File"      />
        <input name="bval"          type="File"      />
        <input name="bvec"          type="File"      />
        <input name="phase_enc_dir" type="Str"       />
        <input name="subject_id"    type="Str"       />
        <input name="subjects_dir"  type="Str"       />
        <input name="invertX"       type="Bool"      />
        <input name="invertY"       type="Bool"      />
        <input name="invertZ"       type="Bool"      />
        <input name="delete_steps"  type="Bool"      />
    </unit>
    """

    # Step 0 - Initialization

    # Freesurfer 'subjects_dir' has to be passed or set as environment variable
    subjects_dir = get_or_check_freesurfer_subjects_dir(subjects_dir)

    # Raise an Exception if BrainsuiteCheck is not installed
    check_brainsuite_installation()

    # Create the preprocessing output directory if not existing
    if not os.path.isdir(outdir):
        os.makedirs(outdir)

    # Step 1 - Import files to Connectomist and choose q-space model
    raw_dwi_dir = os.path.join(outdir, "01-Import_and_qspace_model")
    # The manufacturer option is unused (use brainsuite for susceptibility
    # correction) but required
    dwi_data_import_and_qspace_sampling(raw_dwi_dir,
                                        dwi=dwi,
                                        bval=bval,
                                        bvec=bvec,
                                        manufacturer="Siemens",
                                        invertX=invertX,
                                        invertY=invertY,
                                        invertZ=invertZ,
                                        subject_id=subject_id)

    # Step 2 - Create a brain mask
    rough_mask_dir = os.path.join(outdir, "02-Rough_mask")
    dwi_rough_mask_extraction(rough_mask_dir, raw_dwi_dir)

    # Step 3 - Detect and correct outlying diffusion slices
    outliers_dir = os.path.join(outdir, "03-Outliers")
    dwi_outlier_detection(outliers_dir, raw_dwi_dir, rough_mask_dir)

    # Export outliers.py
    path_outliers_py = os.path.join(outliers_dir, "outliers.py")
    shutil.copy(path_outliers_py, outdir)

    # Step 4 - Eddy current and motion correction
    eddy_motion_dir = os.path.join(outdir, "04-Eddy_current_and_motion")
    dwi_eddy_current_and_motion_correction(eddy_motion_dir, raw_dwi_dir,
                                           rough_mask_dir, outliers_dir)

    # Step 5 - Convert Connectomist result to Nifti with bval/bvec
    dwi, bval, bvec = export_eddy_motion_results_to_nifti(eddy_motion_dir,
                                                          filename="dwi_ecc")

    # Step 6 - Susceptibility correction using BrainSuite
    brainsuite_dir = os.path.join(outdir, "05-Suceptibility_BrainSuite")
    if not os.path.isdir(brainsuite_dir):
        os.mkdir(brainsuite_dir)

    dwi_wo_susceptibility, bval, bvec = \
        brainsuite_susceptibility_correction(outdir=brainsuite_dir,
                                             dwi=dwi,
                                             bval=bval,
                                             bvec=bvec,
                                             phase_enc_dir=phase_enc_dir,
                                             subject_id=subject_id,
                                             subjects_dir=subjects_dir,
                                             qc_dir=outdir)

    # Step 7 - move corrected diffusion to outdir
    dwi_preproc = os.path.join(outdir, "dwi.nii.gz")
    bval_preproc = os.path.join(outdir, "dwi.bval")
    bvec_preproc = os.path.join(outdir, "dwi.bvec")
    shutil.copyfile(dwi_wo_susceptibility, dwi_preproc)
    shutil.copyfile(bval, bval_preproc)
    shutil.copyfile(bvec, bvec_preproc)

    # Step 8 - Create a T2 brain mask of preprocessed DWI data
    bet2_prefix = os.path.join(outdir, "nodif_brain")
    nodif_brain = os.path.join(bet2_prefix + ".nii.gz")
    nodif_brain_mask = os.path.join(bet2_prefix + "_mask.nii.gz")
    bet2(dwi, bet2_prefix, f=0.25, m=True)

    # Step 9 - clean intermediate directories if requested
    if delete_steps:
        intermediate_directories = [
            raw_dwi_dir, rough_mask_dir, outliers_dir, eddy_motion_dir,
            brainsuite_dir
        ]
        for directory in intermediate_directories:
            shutil.rmtree(directory)

    return (outdir, dwi_preproc, bval_preproc, bvec_preproc, nodif_brain,
            nodif_brain_mask)
Beispiel #9
0
b0_brain_file = os.path.join(subjdir, "nodif_brain")
bet_files = glob.glob(b0_brain_file + "*")
if len(bet_files) == 0:
    (
        output,
        mask_file,
        mesh_file,
        outline_file,
        inskull_mask_file,
        inskull_mesh_file,
        outskull_mask_file,
        outskull_mesh_file,
        outskin_mask_file,
        outskin_mesh_file,
        skull_mask_file,
    ) = bet2(b0_file, b0_brain_file, m=True, f=args.thresh, shfile=args.fslconfig)
else:
    mask_file = sorted(bet_files)[0]
    if not os.path.isfile(mask_file):
        raise IOError("FileDoesNotExist: '{0}'.".format(mask_file))

# create a pdf snap of the brain mask
if args.graphics:
    snap_file = os.path.join(qcdir, "bet.pdf")
    plot_image(b0_file, contour_file=mask_file, snap_file=snap_file, name="bet")


"""
Generating PDFs
---------------
Beispiel #10
0
# create a pdf snap of the b0 image
if args.graphics:
    snap_file = os.path.join(qcdir, "nodif.pdf")
    plot_image(b0_file, snap_file=snap_file, name="nodif")

# generate a brain mask on the corrected b0 data
b0_brain_file = os.path.join(subjdir, "nodif_brain")
bet_files = glob.glob(b0_brain_file + "*")
if len(bet_files) == 0:
    (output, mask_file, mesh_file, outline_file, inskull_mask_file,
     inskull_mesh_file, outskull_mask_file, outskull_mesh_file,
     outskin_mask_file, outskin_mesh_file,
     skull_mask_file) = bet2(b0_file,
                             b0_brain_file,
                             m=True,
                             f=args.thresh,
                             shfile=args.fslconfig)
else:
    mask_file = sorted(bet_files)[0]
    if not os.path.isfile(mask_file):
        raise IOError("FileDoesNotExist: '{0}'.".format(mask_file))

# create a pdf snap of the brain mask
if args.graphics:
    snap_file = os.path.join(qcdir, "bet.pdf")
    plot_image(b0_file,
               contour_file=mask_file,
               snap_file=snap_file,
               name="bet")
"""
def brainsuite_susceptibility_correction(outdir,
                                         dwi,
                                         bval,
                                         bvec,
                                         subject_id,
                                         fs_subjects_dir = None,
                                         qc_dir          = None,
                                         bdp_nthread     = 8):
    """
    Assuming the beginning of the preprocessing was done with Connectomist
    up to Eddy current and motion correction, we now want to make susceptbility
    distortion correction using Brainsuite.

    Parameters
    ----------
    outdir:          Str, path to directory where to output.
    dwi
    bval
    bvec
    subject_id:      Str, subject identifier used in Freesurfer.
    fs_subjects_dir: If the Freesurfer $SUBJECTS_DIR environment variable is
                     not set, or to bypass it, pass the path.
    qc_dir:          Str, path to directory where to output snapshots for QC.
    bdp_nthread:     Int, nb of threads for bdp (see bdp.sh --thread flag)
    """

    # If Freesurfer SUBJECTS_DIR is not passed, it should be set as environment variable
    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.")

    # Set and check path to T1 brain-only volume from Freesurfer (mgz format)
    t1_brain_mgz = os.path.join(fs_subjects_dir, subject_id, "mri/brain.mgz")
    if not os.path.isfile(t1_brain_mgz):
        raise Exception("Missing file: {}".format(t1_brain_mgz))

    # Convert Freesurfer T1 to Nifti with reorientation to RAS (to be in the
    # same orientation as the diffusion data)
    t1_brain_RAS_nii = os.path.join(outdir, "t1_brain.nii.gz")
    cmd = ["mri_convert", t1_brain_mgz, t1_brain_RAS_nii,
           "--out_orientation", "RAS"]
    fsprocess = FSWrapper(cmd)
    fsprocess()  # Run
    if fsprocess.exitcode != 0:
        raise FreeSurferRuntimeError(cmd[0], " ".join(cmd[1:]))

    # Run bfc (bias correction: required by BrainSuite)
    t1_bfc = os.path.join(outdir, "t1_brain.bfc.nii.gz")
    cmd    = ["bfc", "-i", t1_brain_RAS_nii, "-o", t1_bfc]
    subprocess.check_call(cmd)

    # Extract brain from the nodif volume with FSL bet2
    nodif_brain = os.path.join(outdir, "nodif_brain.nii.gz")
    bet2(dwi, nodif_brain, f=0.25, m=False)

    # Run bdp.sh: registration + diffusion model
    cmd = ["bdp.sh", t1_bfc, "--nii", dwi, "--bval", bval, "--bvec", bvec,
           "--dwi-mask", nodif_brain, "--threads=%i" % bdp_nthread]
    subprocess.check_call(cmd)

    # Path to files of interest, created by BrainSuite bdp.sh
    dwi_wo_susceptibility = os.path.join(outdir, "t1_brain.dwi.RAS.correct.nii.gz")

    ###############
    # Quality check: create snapshots to visually assert the registration quality

    if qc_dir is None:
        qc_dir = outdir

    # The snapshots won't contain all slices, half of them
    nb_slices_in_z = nibabel.load(nodif_brain).get_shape()[2]

    # Path to registered T1
    t1_to_dif = os.path.join(outdir, "t1_brain.D_coord.nii.gz")

    # First png: T1 registered in diffusion with nodif edges
    t1_with_nodif_edges_png = os.path.join(qc_dir, "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(qc_dir, "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)

    return dwi_wo_susceptibility, bval, bvec
def complete_preproc_wo_fieldmap(outdir,
                                 dwi,
                                 bval,
                                 bvec,
                                 subject_id,
                                 fs_subjects_dir = None,
                                 invertX         = True,
                                 invertY         = False,
                                 invertZ         = False,
                                 delete_steps    = False):
    """
    Function that runs all preprocessing steps using Connectomist but
    with BrainSuite for the correction of susceptibility distortions.

    Parameters
    ----------
    outdir:          Str, path to folder where all the preprocessing will be done.
    dwi              Str, path to input Nifti DW data.
    bval:            Str, path to Nifti's associated .bval file.
    bvec:            Str, path to Nifti's associated .bval file.
    subject_id:      Str, subject identifier used in Freesurfer.
    fs_subjects_dir: If the Freesurfer $SUBJECTS_DIR environment variable is
                     not set, or to bypass it, pass the path.
    invertX:         Bool, if True invert x-axis in diffusion model.
    invertY:         Bool, same as invertX but for y-axis.
    invertZ:         Bool, same as invertX but for z-axis.
    delete_steps:    Bool, if True remove all intermediate files and
                     directories at the end of preprocessing, to keep only
                     selected files:
                     preprocessed Nifti + bval + bvec + outliers.py + nodif_brain.nii.gz

    Returns
    -------
    outdir: Directory with the preprocessed files.

    <unit>
        <output name="preproc_dwi"    type="File"      />
        <output name="preproc_bval"   type="File"      />
        <output name="preproc_bvec"   type="File"      />

        <input name="outdir"          type="Directory" />
        <input name="dwi"             type="File"      />
        <input name="bval"            type="File"      />
        <input name="bvec"            type="File"      />
        <input name="subject_id"      type="Str"       />
        <input name="fs_subjects_dir" type="Str"       />
        <input name="invertX"         type="Bool"      />
        <input name="invertY"         type="Bool"      />
        <input name="invertZ"         type="Bool"      />
        <input name="delete_steps"    type="Bool"      />
    </unit>
    """

    ### Step 0 - Initialization

    # If Freesurfer SUBJECTS_DIR is not passed, it should be set as environment variable
    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.")

    # Raise an Exception if BrainsuiteCheck is not installed
    check_brainsuite_installation()

    # Create the preprocessing output directory if not existing
    if not os.path.isdir(outdir):
        os.makedirs(outdir)

    ### Step 1 - Import files to Connectomist and choose q-space model
    raw_dwi_dir = os.path.join(outdir, "01-Import_and_qspace_model")
    dwi_data_import_and_qspace_sampling(raw_dwi_dir,
                                        dwi          = dwi,
                                        bval         = bval,
                                        bvec         = bvec,
                                        manufacturer = "Siemens",  # unused but required
                                        invertX      = invertX,
                                        invertY      = invertY,
                                        invertZ      = invertZ,
                                        subject_id   = subject_id)

    ### Step 2 --- Create a brain mask
    rough_mask_dir = os.path.join(outdir, "02-Rough_mask")
    dwi_rough_mask_extraction(rough_mask_dir, raw_dwi_dir)

    ### Step 3 - Detect and correct outlying diffusion slices
    outliers_dir = os.path.join(outdir, "03-Outliers")
    dwi_outlier_detection(outliers_dir, raw_dwi_dir, rough_mask_dir)

    # Export outliers.py
    path_outliers_py = os.path.join(outliers_dir, "outliers.py")
    shutil.copy(path_outliers_py, outdir)

    ### Step 4 - Eddy current and motion correction
    eddy_motion_dir = os.path.join(outdir, "04-Eddy_current_and_motion")
    dwi_eddy_current_and_motion_correction(eddy_motion_dir,
                                           raw_dwi_dir,
                                           rough_mask_dir,
                                           outliers_dir)

    ### Step 5 - Convert Connectomist result to Nifti with bval/bvec
    dwi, bval, bvec = export_eddy_motion_results_to_nifti(eddy_motion_dir,
                                                          filename = "dwi_ecc")

    ### Step 6 - Susceptibility correction using BrainSuite
    brainsuite_dir = os.path.join(outdir, "05-Suceptibility_BrainSuite")
    if not os.path.isdir(brainsuite_dir):
        os.mkdir(brainsuite_dir)

    dwi_wo_susceptibility, bval, bvec = \
        brainsuite_susceptibility_correction(outdir          = brainsuite_dir,
                                             dwi             = dwi,
                                             bval            = bval,
                                             bvec            = bvec,
                                             subject_id      = subject_id,
                                             fs_subjects_dir = fs_subjects_dir,
                                             qc_dir          = outdir)

    ### Step 7 - move corrected diffusion to outdir
    dwi_preproc  = os.path.join(outdir, "dwi.nii.gz")
    bval_preproc = os.path.join(outdir, "dwi.bval")
    bvec_preproc = os.path.join(outdir, "dwi.bvec")
    shutil.copyfile(dwi_wo_susceptibility, dwi_preproc)
    shutil.copyfile(bval, bval_preproc)
    shutil.copyfile(bvec, bvec_preproc)

    ### Step 8 - Create a T2 brain mask of preprocessed DWI data
    bet2_prefix      = os.path.join(outdir, "nodif_brain")
    nodif_brain      = os.path.join(bet2_prefix + ".nii.gz")
    nodif_brain_mask = os.path.join(bet2_prefix + "_mask.nii.gz")
    bet2(dwi, bet2_prefix, f=0.25, m=True)

    ### Step 9 - clean intermediate directories if requested
    if delete_steps:
        intermediate_directories = [raw_dwi_dir,
                                    rough_mask_dir,
                                    outliers_dir,
                                    eddy_motion_dir,
                                    brainsuite_dir]
        for directory in intermediate_directories:
            shutil.rmtree(directory)

    return outdir, dwi_preproc, bval_preproc, bvec_preproc, nodif_brain, nodif_brain_mask
def brainsuite_susceptibility_correction(outdir,
                                         dwi,
                                         bval,
                                         bvec,
                                         subject_id,
                                         phase_enc_dir,
                                         subjects_dir=None,
                                         qc_dir=None,
                                         bdp_nthread=4):
    """
    Assuming the beginning of the preprocessing was done with Connectomist
    up to Eddy current and motion correction, we now want to make susceptbility
    distortion correction using Brainsuite.

    Parameters
    ----------
    outdir: str
        Path to directory where to output.
    dwi: str
        Path to the preprocessed diffusion-weighted Nifti.
    bval: str
        Path to the bval file associated to the Nifti.
    bvec: str
        Path to the bvec file associated to the Nifti.
    subject_id: str
        Subject identifier used in Freesurfer.
    phase_enc_dir: str
        In plane phase encoding direction, "y", "y-", "x" or "x-".
    subjects_dir: str, default None
        If the Freesurfer $SUBJECTS_DIR environment variable is not set, or to
        bypass it, pass the path.
    qc_dir: str, default None
        Path to directory where to output snapshots for QC. By default in
        outdir.
    bdp_nthread: int, default 4
        Number of threads for bdp (see bdp.sh --thread flag)
    """

    # Freesurfer 'subjects_dir' has to be passed or set as environment variable
    subjects_dir = get_or_check_freesurfer_subjects_dir(subjects_dir)

    # Check in plane phase encoding direction
    # The sign of the phase encoding direction has no impact in this strategy
    # e.g. for "+y" or "-y" use "y"
    possible_phase_enc_dirs = {"y", "x"}
    if phase_enc_dir not in possible_phase_enc_dirs:
        raise ValueError("Bad argument 'phase_enc_dir': {}, should be in {}."
                         .format(phase_enc_dir, possible_phase_enc_dirs))

    # Set and check path to T1 brain-only volume from Freesurfer (mgz format)
    t1_brain_mgz = os.path.join(subjects_dir, subject_id, "mri/brain.mgz")
    if not os.path.isfile(t1_brain_mgz):
        raise Exception("Missing file: {}".format(t1_brain_mgz))

    # Convert Freesurfer T1 to Nifti with reorientation to RAS (to be in the
    # same orientation as the diffusion data)
    t1_brain_RAS_nii = os.path.join(outdir, "t1_brain.nii.gz")
    cmd = ["mri_convert", t1_brain_mgz, t1_brain_RAS_nii,
           "--out_orientation", "RAS"]
    run_freesurfer_cmd(cmd, subjects_dir=subjects_dir)

    # Run bfc (bias correction: required by BrainSuite)
    t1_bfc = os.path.join(outdir, "t1_brain.bfc.nii.gz")
    cmd = ["bfc", "-i", t1_brain_RAS_nii, "-o", t1_bfc]
    subprocess.check_call(cmd)

    # Extract brain from the nodif volume with FSL bet2
    nodif_brain = os.path.join(outdir, "nodif_brain.nii.gz")
    bet2(dwi, nodif_brain, f=0.25, m=False)

    # Run bdp.sh: registration + diffusion model
    cmd = ["bdp.sh", t1_bfc, "--nii", dwi, "--bval", bval, "--bvec", bvec,
           "--dwi-mask", nodif_brain, "--dir=%s" % phase_enc_dir,
           "--threads=%i" % bdp_nthread]
    subprocess.check_call(cmd)

    # Path to files of interest, created by BrainSuite bdp.sh
    dwi_wo_susceptibility = os.path.join(
        outdir, "t1_brain.dwi.RAS.correct.nii.gz")

    ###############
    # Quality check: create snapshots to visually assert the registration
    # quality

    if qc_dir is None:
        qc_dir = outdir

    # The snapshots won't contain all slices, half of them
    nb_slices_in_z = nibabel.load(nodif_brain).get_shape()[2]

    # Path to registered T1
    t1_to_dif = os.path.join(outdir, "t1_brain.D_coord.nii.gz")

    # First png: T1 registered in diffusion with nodif edges
    t1_with_nodif_edges_png = os.path.join(qc_dir, "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(qc_dir, "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)

    return dwi_wo_susceptibility, bval, bvec
def complete_preproc_wo_fieldmap(outdir,
                                 dwi,
                                 bval,
                                 bvec,
                                 phase_enc_dir,
                                 subject_id,
                                 subjects_dir=None,
                                 invertX=True,
                                 invertY=False,
                                 invertZ=False,
                                 delete_steps=False):
    """
    Function that runs all preprocessing steps using Connectomist but
    with BrainSuite for the correction of susceptibility distortions.

    Parameters
    ----------
    outdir: str
        Path to directory where all the preprocessing will be done.
    dwi: str
        path to input diffusion-weighted Nifti data.
    bval: str
        Path to the Nifti's associated .bval file.
    bvec: str
        Ppath to Nifti's associated .bval file.
    phase_enc_dir: str
        In plane phase encoding direction, "y", "y-", "x" or "x-".
    subject_id: str
        Subject identifier used in Freesurfer.
    subjects_dir: Str, default None
        If the Freesurfer $SUBJECTS_DIR environment variable is not set, or to
        bypass it, pass the path.
    invertX: bool, default True
        If True invert x-axis in diffusion model.
    invertY: bool, default False
        Same as invertX but for y-axis.
    invertZ: bool, default False
        Same as invertX but for z-axis.
    delete_steps: bool
        If True remove all intermediate files and directories at the end of
        preprocessing, to keep only selected files:
        - preprocessed Nifti + bval + bvec + outliers.py + nodif_brain*.nii.gz

    Returns
    -------
    outdir: str,
        Path to directory with the preprocessed files.

    <unit>
        <output name="preproc_dwi"  type="File"      />
        <output name="preproc_bval" type="File"      />
        <output name="preproc_bvec" type="File"      />

        <input name="outdir"        type="Directory" />
        <input name="dwi"           type="File"      />
        <input name="bval"          type="File"      />
        <input name="bvec"          type="File"      />
        <input name="phase_enc_dir" type="Str"       />
        <input name="subject_id"    type="Str"       />
        <input name="subjects_dir"  type="Str"       />
        <input name="invertX"       type="Bool"      />
        <input name="invertY"       type="Bool"      />
        <input name="invertZ"       type="Bool"      />
        <input name="delete_steps"  type="Bool"      />
    </unit>
    """

    # Step 0 - Initialization

    # Freesurfer 'subjects_dir' has to be passed or set as environment variable
    subjects_dir = get_or_check_freesurfer_subjects_dir(subjects_dir)

    # Raise an Exception if BrainsuiteCheck is not installed
    check_brainsuite_installation()

    # Create the preprocessing output directory if not existing
    if not os.path.isdir(outdir):
        os.makedirs(outdir)

    # Step 1 - Import files to Connectomist and choose q-space model
    raw_dwi_dir = os.path.join(outdir, "01-Import_and_qspace_model")
    # The manufacturer option is unused (use brainsuite for susceptibility
    # correction) but required
    dwi_data_import_and_qspace_sampling(raw_dwi_dir,
                                        dwi=dwi,
                                        bval=bval,
                                        bvec=bvec,
                                        manufacturer="Siemens",
                                        invertX=invertX,
                                        invertY=invertY,
                                        invertZ=invertZ,
                                        subject_id=subject_id)

    # Step 2 - Create a brain mask
    rough_mask_dir = os.path.join(outdir, "02-Rough_mask")
    dwi_rough_mask_extraction(rough_mask_dir, raw_dwi_dir)

    # Step 3 - Detect and correct outlying diffusion slices
    outliers_dir = os.path.join(outdir, "03-Outliers")
    dwi_outlier_detection(outliers_dir, raw_dwi_dir, rough_mask_dir)

    # Export outliers.py
    path_outliers_py = os.path.join(outliers_dir, "outliers.py")
    shutil.copy(path_outliers_py, outdir)

    # Step 4 - Eddy current and motion correction
    eddy_motion_dir = os.path.join(outdir, "04-Eddy_current_and_motion")
    dwi_eddy_current_and_motion_correction(eddy_motion_dir,
                                           raw_dwi_dir,
                                           rough_mask_dir,
                                           outliers_dir)

    # Step 5 - Convert Connectomist result to Nifti with bval/bvec
    dwi, bval, bvec = export_eddy_motion_results_to_nifti(eddy_motion_dir,
                                                          filename="dwi_ecc")

    # Step 6 - Susceptibility correction using BrainSuite
    brainsuite_dir = os.path.join(outdir, "05-Suceptibility_BrainSuite")
    if not os.path.isdir(brainsuite_dir):
        os.mkdir(brainsuite_dir)

    dwi_wo_susceptibility, bval, bvec = \
        brainsuite_susceptibility_correction(outdir=brainsuite_dir,
                                             dwi=dwi,
                                             bval=bval,
                                             bvec=bvec,
                                             phase_enc_dir=phase_enc_dir,
                                             subject_id=subject_id,
                                             subjects_dir=subjects_dir,
                                             qc_dir=outdir)

    # Step 7 - move corrected diffusion to outdir
    dwi_preproc = os.path.join(outdir, "dwi.nii.gz")
    bval_preproc = os.path.join(outdir, "dwi.bval")
    bvec_preproc = os.path.join(outdir, "dwi.bvec")
    shutil.copyfile(dwi_wo_susceptibility, dwi_preproc)
    shutil.copyfile(bval, bval_preproc)
    shutil.copyfile(bvec, bvec_preproc)

    # Step 8 - Create a T2 brain mask of preprocessed DWI data
    bet2_prefix = os.path.join(outdir, "nodif_brain")
    nodif_brain = os.path.join(bet2_prefix + ".nii.gz")
    nodif_brain_mask = os.path.join(bet2_prefix + "_mask.nii.gz")
    bet2(dwi, bet2_prefix, f=0.25, m=True)

    # Step 9 - clean intermediate directories if requested
    if delete_steps:
        intermediate_directories = [raw_dwi_dir,
                                    rough_mask_dir,
                                    outliers_dir,
                                    eddy_motion_dir,
                                    brainsuite_dir]
        for directory in intermediate_directories:
            shutil.rmtree(directory)

    return (outdir, dwi_preproc, bval_preproc, bvec_preproc, nodif_brain,
            nodif_brain_mask)