コード例 #1
0
ファイル: reg_utils.py プロジェクト: CaseyWeiner/m2g
def segment_t1w(t1w, basename, opts=""):
    """Uses FSLs FAST to segment an anatomical image into GM, WM, and CSF probability maps.

    Parameters
    ----------
    t1w : str
        the path to the t1w image to be segmented
    basename : str
        the basename for outputs. Often it will be most convenient for this to be the dataset, followed by the subject,
        followed by the step of processing. Note that this anticipates a path as well;
        ie, /path/to/dataset_sub_nuis, with no extension.
    opts : str, optional
        additional options that can optionally be passed to fast. Desirable options might be -P, which will use
        prior probability maps if the input T1w MRI is in standard space, by default ""

    Returns
    -------
    dict
        dictionary of output files
    """

    # run FAST, with options -t for the image type and -n to
    # segment into CSF (pve_0), WM (pve_1), GM (pve_2)
    cmd = f"fast -t 1 {opts} -n 3 -o {basename} {t1w}"
    gen_utils.run(cmd)
    out = {}  # the outputs
    out["wm_prob"] = f"{basename}_pve_2.nii.gz"
    out["gm_prob"] = f"{basename}_pve_1.nii.gz"
    out["csf_prob"] = f"{basename}_pve_0.nii.gz"
    return out
コード例 #2
0
ファイル: reg_utils.py プロジェクト: CaseyWeiner/m2g
def t1w_skullstrip(t1w, out, skull=None):
    """Skull-strips the t1w image using AFNIs 3dSkullStrip algorithm, which is a modification of FSLs BET specialized to t1w images.
    Offers robust skull-stripping with no hyperparameters
    Note: renormalizes the intensities, call extract_t1w_brain instead if you want the original intensity values

    Parameters
    ----------
    t1w : str
        path for the input t1w image file
    out : str
        path for the output skull-stripped image file
    skull : str, optional
        skullstrip parameter pre-set. Default is "none".
    """
    if skull == "below":
        cmd = f"3dSkullStrip -prefix {out} -input {t1w} -shrink_fac_bot_lim 0.6 -ld 45"
    elif skull == "cerebelum":
        cmd = f"3dSkullStrip -prefix {out} -input {t1w} -shrink_fac_bot_lim 0.3 -ld 45"
    elif skull == "eye":
        cmd = f"3dSkullStrip -prefix {out} -input {t1w} -no_avoid_eyes -ld 45"
    elif skull == "general":
        cmd = f"3dSkullStrip -prefix {out} -input {t1w} -push_to_edge -ld 45"
    else:
        cmd = f"3dSkullStrip -prefix {out} -input {t1w} -ld 30"
    gen_utils.run(cmd)
コード例 #3
0
def get_atlas(atlas_dir, vox_size):
    """Given the desired location of atlases and the type of processing, ensure we have all the atlases and parcellations.

    Parameters
    ----------
    atlas_dir : str
        Path to directory containing atlases.
    vox_size : str
        t1w input image voxel dimensions, either 2mm or 1mm

    Returns
    -------
    tuple
        filepaths corresponding to the human parcellations, the atlas, and the atlas's mask. atals_brain and lv_mask is None if not fmri.

    Raises
    ------
    ValueError
        raised if dimensionality is wrong.
    NotImplementedError
        currently raised in lieu of atlas pulling capabilities.
    """
    if vox_size == "2mm":
        dims = "2x2x2"
    elif vox_size == "1mm":
        dims = "1x1x1"
    else:
        raise ValueError(
            "Voxel dimensions of input t1w image not currently supported by m2g."
        )

    # grab atlases if they don't exist
    if not os.path.exists(atlas_dir):
        # TODO : re-implement this pythonically with shutil and requests in python3.
        print("atlas directory not found. Cloning ...")
        clone = "https://github.com/neurodata/neuroparc.git"
        gen_utils.run(f"git lfs clone {clone} {atlas_dir}")

    atlas = os.path.join(
        atlas_dir,
        "atlases/reference_brains/MNI152NLin6_res-" + dims + "_T1w.nii.gz")
    atlas_mask = os.path.join(
        atlas_dir,
        "atlases/mask/MNI152NLin6_res-" + dims + "_T1w_descr-brainmask.nii.gz",
    )
    parcellations = [
        i for i in glob.glob(atlas_dir + "/atlases/label/Human/*.nii.gz")
        if dims in i
    ]
    parcellations = [
        os.path.join(atlas_dir, "label/Human/", l) for l in parcellations
    ]

    assert all(map(os.path.exists,
                   parcellations)), "Some parcellations do not exist."
    assert all(
        map(os.path.exists, [atlas, atlas_mask])
    ), "atlas or atlas_mask, does not exist. You may not have git-lfs -- if not, install it."
    return parcellations, atlas, atlas_mask
コード例 #4
0
def make_script(input_dir, output_dir, subject, session, data_config,
                pipeline_config, mem_gb, n_cpus):
    cpac_script = '/root/.m2g/cpac_script.sh'
    with open(cpac_script, 'w+', encoding='utf8') as script:
        script.write(f'''#! /bin/bash
        . /venv/bin/activate
        python /code/run.py --data_config_file {data_config} --pipeline_file {pipeline_config} --n_cpus {n_cpus} --mem_gb {mem_gb} {input_dir} {output_dir} participant
        ''')

    run(f'chmod +x {cpac_script}')

    return cpac_script
コード例 #5
0
ファイル: register.py プロジェクト: CaseyWeiner/m2g
    def gen_tissue(self):
        """Extracts the brain from the raw t1w image (as indicated by self.t1w), uses it to create WM, GM, and CSF masks,
        reslices all 4 files to the target voxel resolution and extracts the white matter edge. Each mask is saved to
        location indicated by self.map_path
        """
        # BET needed for this, as afni 3dautomask only works on 4d volumes
        print("Extracting brain from raw T1w image...")
        reg_utils.t1w_skullstrip(self.t1w, self.t1w_brain, self.skull)

        #  QA part of skull strip
        skullstrip_qa = Path(self.qa) / "skull_strip"
        if not os.path.exists(skullstrip_qa):
            skullstrip_qa.mkdir(parents=True, exist_ok=True)
        print('QA_skullstrip_path  ', skullstrip_qa)
        gen_overlay_pngs(self.t1w_brain, self.t1w, skullstrip_qa)

        # Segment the t1w brain into probability maps
        self.maps = reg_utils.segment_t1w(self.t1w_brain, self.map_path)
        self.wm_mask = self.maps["wm_prob"]
        self.gm_mask = self.maps["gm_prob"]
        self.csf_mask = self.maps["csf_prob"]

        # Generates quality analysis pictures of white matter, gray matter and cerebrospinal fluid
        qa_fast_png(self.csf_mask, self.gm_mask, self.wm_mask,
                    str(Path(self.qa_reg) / "qa_fast.png"))

        self.t1w_brain = gen_utils.match_target_vox_res(self.t1w_brain,
                                                        self.vox_size,
                                                        self.outdir,
                                                        sens="anat")
        self.wm_mask = gen_utils.match_target_vox_res(self.wm_mask,
                                                      self.vox_size,
                                                      self.outdir,
                                                      sens="anat")
        self.gm_mask = gen_utils.match_target_vox_res(self.gm_mask,
                                                      self.vox_size,
                                                      self.outdir,
                                                      sens="anat")
        self.csf_mask = gen_utils.match_target_vox_res(self.csf_mask,
                                                       self.vox_size,
                                                       self.outdir,
                                                       sens="anat")

        # Threshold WM to binary in dwi space
        self.t_img = load_img(self.wm_mask)
        self.mask = math_img("img > 0.2", img=self.t_img)
        self.mask.to_filename(self.wm_mask_thr)

        # Extract wm edge
        # TODO : this should be a function in reg_utils so that we can print it to the log
        cmd = f"fslmaths {self.wm_mask_thr} -edge -bin -mas {self.wm_mask_thr} {self.wm_edge}"
        print("Extracting white matter edge...")
        gen_utils.run(cmd)
コード例 #6
0
ファイル: reg_utils.py プロジェクト: CaseyWeiner/m2g
def combine_xfms(xfm1, xfm2, xfmout):
    """A function to combine two transformations and output the resulting transformation

    Parameters
    ----------
    xfm1 : str
        path to the first transformation
    xfm2 : str
        path to the second transformation
    xfmout : str
        path for the ouput transformation
    """
    cmd = f"convert_xfm -omat {xfmout} -concat {xfm1} {xfm2}"
    gen_utils.run(cmd)
コード例 #7
0
ファイル: reg_utils.py プロジェクト: CaseyWeiner/m2g
def normalize_t1w(inp, out):
    """
    A function that normalizes intensity values for anatomical
    T1w images. Makes brain extraction much more robust
    in the event that we have poor shading in our T1w image.

    **Positional Arguments:**

        - inp:
            - the input T1w image.
        - out:
            - the output intensity-normalized image.
    """
    cmd = f"3dUnifize -prefix {out} -input {inp}"
    gen_utils.run(cmd)
コード例 #8
0
ファイル: reg_utils.py プロジェクト: CaseyWeiner/m2g
def apply_mask(inp, mask, out):
    """A function to generate a brain-only mask for an input image using 3dcalc

    Parameters
    ----------
    inp : str
        path for the input image. If 4d, the mask should be 4d. If 3d, the mask should be 3d.
    mask : str
        path to the mask to apply to the data. Should be nonzero in mask region.
    out : str
        the path for the output skull-extracted image.
    """

    cmd = f'3dcalc -a {inp} -b {mask} -expr "a*step(b)" -prefix {out}'
    gen_utils.run(cmd)
コード例 #9
0
ファイル: preproc.py プロジェクト: CaseyWeiner/m2g
def eddy_correct(dwi, corrected_dwi, idx):
    """Performs eddy-correction (or self-alignment) of a stack of 3D images

    Parameters
    ----------
    dwi : str
        Path for the DTI image to be eddy-corrected
    corrected_dwi : str
        Path for the corrected and aligned DTI volume in a nifti file
    idx : str
        Index of the first B0 volume in the stack
    """

    cmd = f"eddy_correct {dwi} {corrected_dwi} {str(idx)}"
    gen_utils.run(cmd)
コード例 #10
0
ファイル: reg_utils.py プロジェクト: CaseyWeiner/m2g
def inverse_warp(ref, out, warp):
    """Takes a non-linear mapping and finds the inverse. Takes the file conaining warp-coefficients/fields specified in the
    variable warp (t1w -> mni) and creates its inverse (mni -> t1w) which is saved in the location determined by the variable out

    Parameters
    ----------
    ref : str
        path to a file in target space, which is a different target space than warp (a image that has not been mapped to mni)
    out : str
        path to the output file, containing warps that are now inverted
    warp : str
        path to the warp/shiftmap transform volume wanting to be inverted
    """

    cmd = "invwarp --warp=" + warp + " --out=" + out + " --ref=" + ref
    gen_utils.run(cmd)
コード例 #11
0
ファイル: reg_utils.py プロジェクト: CaseyWeiner/m2g
def resample_fsl(base, res, goal_res, interp="spline"):
    """
    A function to resample a base image in fsl to that of a template.

    **Positional Arguments:**

        base:
            - the path to the base image to resample.
        res:
            - the filename after resampling.
        goal_res:
            - the desired resolution.
        interp:
            - the interpolation strategy to use.
    """
    # resample using an isometric transform in fsl
    cmd = f"flirt -in {base} -ref {base} -out {res} -applyisoxfm {goal_res} -interp {interp}"
    gen_utils.run(cmd)
コード例 #12
0
ファイル: reg_utils.py プロジェクト: CaseyWeiner/m2g
def apply_warp(ref,
               inp,
               out,
               warp,
               xfm=None,
               mask=None,
               interp=None,
               sup=False):
    """Applies a warp from the structural to reference space in a single step using information about
    the structural -> ref mapping as well as the functional to structural mapping.

    Parameters
    ----------
    ref : str
        path of the reference image to be aligned to
    inp : str
        path of the input image to be aligned
    out : str
        path for the resulting warped output image
    warp : str
        path for the warp coefficent file to go from inp -> ref
    xfm : str, optional
        path of the affine transformation matrix file from inp -> ref, by default None
    mask : str, optional
        path of filename for mask image (in reference space), by default None
    interp : str, optional
        interpolation method {nn, trilinear, sinc, spline}, by default None
    sup : bool, optional
        whether to perform automatic intermediary supersampling, by default False
    """

    cmd = ("applywarp --ref=" + ref + " --in=" + inp + " --out=" + out +
           " --warp=" + warp)
    if xfm is not None:
        cmd += " --premat=" + xfm
    if mask is not None:
        cmd += " --mask=" + mask
    if interp is not None:
        cmd += " --interp=" + interp
    if sup is True:
        cmd += " --super --superlevel=a"
    gen_utils.run(cmd)
コード例 #13
0
ファイル: reg_utils.py プロジェクト: CaseyWeiner/m2g
def applyxfm(ref, inp, xfm, aligned, interp="trilinear", dof=6):
    """Aligns two images with a given transform using FSLs flirt command

    Parameters
    ----------
    ref : str
        path of reference image to be aligned to as a nifti image file
    inp : str
        path of input image to be aligned as a nifti image file
    xfm : str
        path to the transform matrix between the two images
    aligned : str
        path for the output aligned image
    interp : str, optional
        interpolation method, by default "trilinear"
    dof : int, optional
        degrees of freedom for the alignment, by default 6
    """

    cmd = f"flirt -in {inp} -ref {ref} -out {aligned} -init {xfm} -interp {interp} -dof {dof} -applyxfm"
    gen_utils.run(cmd)
コード例 #14
0
ファイル: reg_utils.py プロジェクト: CaseyWeiner/m2g
def align_nonlinear(inp,
                    ref,
                    xfm,
                    out,
                    warp,
                    ref_mask=None,
                    in_mask=None,
                    config=None):
    """Aligns two images using nonlinear methods and stores the transform between them using fnirt

    Parameters
    ----------
    inp : str
        path to the input image
    ref : str
        path to the reference image that the input will be aligned to
    xfm : str
        path to the file containing the affine transform matrix created by reg_utils.align()
    out : str
        path for the desired output image
    warp : str
        the path to store the output file containing the nonlinear warp coefficients/fields
    ref_mask : str, optional
        path to the reference image brain_mask, by default None
    in_mask : str, optional
        path for the file with mask in input image space, by default None
    config : str, optional
        path to the config file specifying command line arguments, by default None
    """

    cmd = f"fnirt --in={inp} --ref={ref} --aff={xfm} --iout={out} --cout={warp} --warpres=8,8,8"
    if ref_mask is not None:
        cmd += f" --refmask={ref_mask} --applyrefmask=1"
    if in_mask is not None:
        cmd += f" --inmask={in_mask} --applyinmask=1"
    if config is not None:
        cmd += f" --config={config}"
    gen_utils.run(cmd)
コード例 #15
0
ファイル: reg_utils.py プロジェクト: CaseyWeiner/m2g
def align_epi(epi, t1, brain, out):
    """
    Algins EPI images to T1w image
    """
    cmd = f"epi_reg --epi={epi} --t1={t1} --t1brain={brain} --out={out}"
    gen_utils.run(cmd)
コード例 #16
0
ファイル: register.py プロジェクト: CaseyWeiner/m2g
    def tissue2dwi_align(self):
        """alignment of ventricle and CC ROI's from MNI space --> dwi and CC and CSF from T1w space --> dwi
        A function to generate and perform dwi space alignment of avoidance/waypoint masks for tractography.
        First creates ventricle and CC ROI. Then creates transforms from stock MNI template to dwi space.
        NOTE: for this to work, must first have called both t1w2dwi_align and atlas2t1w2dwi_align.
        Raises
        ------
        ValueError
            Raised if FSL atlas for ventricle reference not found
        """

        # Create MNI-space ventricle mask
        print("Creating MNI-space ventricle ROI...")
        if not os.path.isfile(self.mni_atlas):
            raise ValueError("FSL atlas for ventricle reference not found!")
        cmd = f"fslmaths {self.mni_vent_loc} -thr 0.1 -bin {self.mni_vent_loc}"
        gen_utils.run(cmd)

        cmd = f"fslmaths {self.corpuscallosum} -bin {self.corpuscallosum}"
        gen_utils.run(cmd)

        cmd = f"fslmaths {self.corpuscallosum} -sub {self.mni_vent_loc} -bin {self.corpuscallosum}"
        gen_utils.run(cmd)

        # Create a transform from the atlas onto T1w. This will be used to transform the ventricles to dwi space.
        reg_utils.align(
            self.mni_atlas,
            self.input_mni,
            xfm=self.xfm_roi2mni_init,
            init=None,
            bins=None,
            dof=6,
            cost="mutualinfo",
            searchrad=True,
            interp="spline",
            out=None,
        )

        # Create transform to align roi to mni and T1w using flirt
        reg_utils.applyxfm(self.input_mni, self.mni_vent_loc,
                           self.xfm_roi2mni_init, self.vent_mask_mni)

        if self.simple is False:
            # Apply warp resulting from the inverse MNI->T1w created earlier
            reg_utils.apply_warp(
                self.t1w_brain,
                self.vent_mask_mni,
                self.vent_mask_t1w,
                warp=self.mni2t1w_warp,
                interp="nn",
                sup=True,
            )

            # Apply warp resulting from the inverse MNI->T1w created earlier
            reg_utils.apply_warp(
                self.t1w_brain,
                self.corpuscallosum,
                self.corpuscallosum_mask_t1w,
                warp=self.mni2t1w_warp,
                interp="nn",
                sup=True,
            )

        # Applyxfm tissue maps to dwi space
        reg_utils.applyxfm(
            self.nodif_B0,
            self.vent_mask_t1w,
            self.t1wtissue2dwi_xfm,
            self.vent_mask_dwi,
        )
        reg_mri_pngs(self.vent_mask_dwi, self.nodif_B0, self.qa_reg)
        reg_utils.applyxfm(
            self.nodif_B0,
            self.corpuscallosum_mask_t1w,
            self.t1wtissue2dwi_xfm,
            self.corpuscallosum_dwi,
        )
        reg_mri_pngs(self.corpuscallosum_dwi, self.nodif_B0, self.qa_reg)
        reg_utils.applyxfm(self.nodif_B0, self.csf_mask,
                           self.t1wtissue2dwi_xfm, self.csf_mask_dwi)
        reg_mri_pngs(self.csf_mask_dwi, self.nodif_B0, self.qa_reg)
        reg_utils.applyxfm(self.nodif_B0, self.gm_mask, self.t1wtissue2dwi_xfm,
                           self.gm_in_dwi)
        reg_mri_pngs(self.gm_in_dwi, self.nodif_B0, self.qa_reg)
        reg_utils.applyxfm(self.nodif_B0, self.wm_mask, self.t1wtissue2dwi_xfm,
                           self.wm_in_dwi)
        reg_mri_pngs(self.wm_in_dwi, self.nodif_B0, self.qa_reg)

        # Threshold WM to binary in dwi space
        thr_img = nib.load(self.wm_in_dwi)
        thr_img.get_data()[thr_img.get_data() < 0.15] = 0
        nib.save(thr_img, self.wm_in_dwi_bin)

        # Threshold GM to binary in dwi space
        thr_img = nib.load(self.gm_in_dwi)
        thr_img.get_data()[thr_img.get_data() < 0.15] = 0
        nib.save(thr_img, self.gm_in_dwi_bin)

        # Threshold CSF to binary in dwi space
        thr_img = nib.load(self.csf_mask_dwi)
        thr_img.get_data()[thr_img.get_data() < 0.99] = 0
        nib.save(thr_img, self.csf_mask_dwi)

        # Threshold WM to binary in dwi space
        self.t_img = load_img(self.wm_in_dwi_bin)
        self.mask = math_img("img > 0", img=self.t_img)
        self.mask.to_filename(self.wm_in_dwi_bin)

        # Threshold GM to binary in dwi space
        self.t_img = load_img(self.gm_in_dwi_bin)
        self.mask = math_img("img > 0", img=self.t_img)
        self.mask.to_filename(self.gm_in_dwi_bin)

        # Threshold CSF to binary in dwi space
        self.t_img = load_img(self.csf_mask_dwi)
        self.mask = math_img("img > 0", img=self.t_img)
        self.mask.to_filename(self.csf_mask_dwi_bin)

        # Create ventricular CSF mask
        print("Creating ventricular CSF mask...")
        cmd = f"fslmaths {self.vent_mask_dwi} -kernel sphere 10 -ero -bin {self.vent_mask_dwi}"
        gen_utils.run(cmd)
        print("Creating Corpus Callosum mask...")
        cmd = f"fslmaths {self.corpuscallosum_dwi} -mas {self.wm_in_dwi_bin} -bin {self.corpuscallosum_dwi}"
        gen_utils.run(cmd)
        cmd = f"fslmaths {self.csf_mask_dwi} -add {self.vent_mask_dwi} -bin {self.vent_csf_in_dwi}"
        gen_utils.run(cmd)

        # Create gm-wm interface image
        cmd = (
            f"fslmaths {self.gm_in_dwi_bin} -mul {self.wm_in_dwi_bin} -add {self.corpuscallosum_dwi} "
            f"-sub {self.vent_csf_in_dwi} -mas {self.nodif_B0_mask} -bin {self.wm_gm_int_in_dwi}"
        )
        gen_utils.run(cmd)
コード例 #17
0
ファイル: reg_utils.py プロジェクト: CaseyWeiner/m2g
def align(
    inp,
    ref,
    xfm=None,
    out=None,
    dof=12,
    searchrad=True,
    bins=256,
    interp=None,
    cost="mutualinfo",
    sch=None,
    wmseg=None,
    init=None,
    finesearch=None,
):
    """Aligns two images using FSLs flirt function and stores the transform between them

    Parameters
    ----------
    inp : str
        path to input image being altered to align with the reference image as a nifti image file
    ref : str
        path to reference image being aligned to as a nifti image file
    xfm : str, optional
        where to save the 4x4 affine matrix containing the transform between two images, by default None
    out : str, optional
        determines whether the image will be automatically aligned and where the resulting image will be saved, by default None
    dof : int, optional
        the number of degrees of free dome of the alignment, by default 12
    searchrad : bool, optional
        whether to use the predefined searchradius parameter (180 degree sweep in x, y, and z), by default True
    bins : int, optional
        number of histogram bins, by default 256
    interp : str, optional
        interpolation method to be used (trilinear,nearestneighbour,sinc,spline), by default None
    cost : str, optional
        cost function to be used in alignment (mutualinfo, corratio, normcorr, normmi, leastsq, labeldiff, or bbr), by default "mutualinfo"
    sch : str, optional
        the optional FLIRT schedule, by default None
    wmseg : str, optional
        an optional white-matter segmentation for bbr, by default None
    init : str, optional
        an initial guess of an alignment in the form of the path to a matrix file, by default None
    finesearch : int, optional
        angle in degrees, by default None
    """

    cmd = f"flirt -in {inp} -ref {ref}"
    if xfm is not None:
        cmd += f" -omat {xfm}"
    if out is not None:
        cmd += f" -out {out}"
    if dof is not None:
        cmd += f" -dof {dof}"
    if bins is not None:
        cmd += f" -bins {bins}"
    if interp is not None:
        cmd += f" -interp {interp}"
    if cost is not None:
        cmd += f" -cost {cost}"
    if searchrad is not None:
        cmd += " -searchrx -180 180 -searchry -180 180 " + "-searchrz -180 180"
    if sch is not None:
        cmd += f" -schedule {sch}"
    if wmseg is not None:
        cmd += f" -wmseg {wmseg}"
    if init is not None:
        cmd += f" -init {init}"
    gen_utils.run(cmd)
コード例 #18
0
ファイル: register.py プロジェクト: CaseyWeiner/m2g
    def t1w2dwi_align(self):
        """Alignment from t1w to mni, making t1w_mni, and t1w_mni to dwi. A function to perform self alignment. Uses a local optimisation cost function to get the
        two images close, and then uses bbr to obtain a good alignment of brain boundaries. Assumes input dwi is already preprocessed and brain extracted.
        """

        # Create linear transform/ initializer T1w-->MNI
        reg_utils.align(
            self.t1w_brain,
            self.input_mni,
            xfm=self.t12mni_xfm_init,
            bins=None,
            interp="spline",
            out=None,
            dof=12,
            cost="mutualinfo",
            searchrad=True,
        )

        # Attempt non-linear registration of T1 to MNI template
        if self.simple is False:
            try:
                print("Running non-linear registration: T1w-->MNI ...")
                # Use FNIRT to nonlinearly align T1 to MNI template
                reg_utils.align_nonlinear(
                    self.t1w_brain,
                    self.input_mni,
                    xfm=self.t12mni_xfm_init,
                    out=self.t1_aligned_mni,
                    warp=self.warp_t1w2mni,
                    ref_mask=self.input_mni_mask,
                    config=self.input_mni_sched,
                )

                # Get warp from MNI -> T1
                reg_utils.inverse_warp(self.t1w_brain, self.mni2t1w_warp,
                                       self.warp_t1w2mni)

                # Get mat from MNI -> T1
                cmd = f"convert_xfm -omat {self.mni2t1_xfm_init} -inverse {self.t12mni_xfm_init}"
                print(cmd)
                gen_utils.run(cmd)

            except RuntimeError("Error: FNIRT failed!"):
                pass
        else:
            # Falling back to linear registration
            reg_utils.align(
                self.t1w_brain,
                self.input_mni,
                xfm=self.t12mni_xfm,
                init=self.t12mni_xfm_init,
                bins=None,
                dof=12,
                cost="mutualinfo",
                searchrad=True,
                interp="spline",
                out=self.t1_aligned_mni,
                sch=None,
            )
        reg_mri_pngs(self.t1_aligned_mni, self.input_mni, self.qa_reg)

        # Align T1w-->DWI
        reg_utils.align(
            self.nodif_B0,
            self.t1w_brain,
            xfm=self.t1w2dwi_xfm,
            bins=None,
            interp="spline",
            dof=6,
            cost="mutualinfo",
            out=None,
            searchrad=True,
            sch=None,
        )
        cmd = f"convert_xfm -omat {self.dwi2t1w_xfm} -inverse {self.t1w2dwi_xfm}"
        print(cmd)
        gen_utils.run(cmd)

        if self.simple is False:
            # Flirt bbr
            try:
                print("Running FLIRT BBR registration: T1w-->DWI ...")
                reg_utils.align(
                    self.nodif_B0,
                    self.t1w_brain,
                    wmseg=self.wm_edge,
                    xfm=self.dwi2t1w_bbr_xfm,
                    init=self.dwi2t1w_xfm,
                    bins=256,
                    dof=7,
                    searchrad=True,
                    interp="spline",
                    out=None,
                    cost="bbr",
                    finesearch=5,
                    sch="${FSLDIR}/etc/flirtsch/bbr.sch",
                )
                cmd = f"convert_xfm -omat {self.t1w2dwi_bbr_xfm} -inverse {self.dwi2t1w_bbr_xfm}"
                gen_utils.run(cmd)

                # Apply the alignment
                reg_utils.align(
                    self.t1w_brain,
                    self.nodif_B0,
                    init=self.t1w2dwi_bbr_xfm,
                    xfm=self.t1wtissue2dwi_xfm,
                    bins=None,
                    interp="spline",
                    dof=7,
                    cost="mutualinfo",
                    out=self.t1w2dwi,
                    searchrad=True,
                    sch=None,
                )
            except RuntimeError("Error: FLIRT BBR failed!"):
                pass
        else:
            # Apply the alignment
            reg_utils.align(
                self.t1w_brain,
                self.nodif_B0,
                init=self.t1w2dwi_xfm,
                xfm=self.t1wtissue2dwi_xfm,
                bins=None,
                interp="spline",
                dof=6,
                cost="mutualinfo",
                out=self.t1w2dwi,
                searchrad=True,
                sch=None,
            )
        reg_mri_pngs(self.t1w2dwi, self.nodif_B0, self.qa_reg)