Example #1
0
def correct_bias_field(in_file: Path, out_file: Path):
    """
    Perform DWI B1 field inhomogenity correction.

    Parameters
    ----------
    in_file : Path
        Path to SD-corrected DWI series
    out_file : Path
        Path to output B1 bias-field corrected DWI series
    """
    ants_flag = (
        subprocess.check_output(["N4BiasFieldCorrection", "--version"])
        .decode("utf-8")
        .lower()[:12]
    ) == "ants version"
    bias_correct = mrt.DWIBiasCorrect()
    if ants_flag:
        algorithm = "ANTs"
        bias_correct.inputs.use_ants = True
    else:
        algorithm = "FSL"
        bias_correct.inputs.use_fsl = True
    bias_correct.inputs.in_file = in_file
    bias_correct.inputs.out_file = out_file
    return bias_correct, algorithm
Example #2
0
def bias_correct(in_file: str, out_file: str):
    bs_correction = mrt.DWIBiasCorrect()
    bs_correction.inputs.in_file = in_file
    bs_correction.inputs.use_fsl = True
    bs_correction.inputs.out_file = out_file
    print(bs_correction.cmdline)
    bs_correction.run()
    return out_file
    def build_core_nodes(self):
        """Build and connect the core nodes of the pipeline."""
        import nipype.interfaces.ants as ants
        import nipype.interfaces.fsl as fsl
        import nipype.interfaces.mrtrix3 as mrtrix3
        import nipype.interfaces.utility as nutil
        import nipype.interfaces.utility as niu
        import nipype.pipeline.engine as npe
        from nipype.interfaces.fsl.epi import Eddy

        from clinica.utils.dwi import (
            compute_average_b0,
            generate_acq_file,
            generate_index_file,
        )

        from .dwi_preprocessing_using_phasediff_fmap_utils import (
            get_grad_fsl,
            init_input_node,
            print_end_pipeline,
        )
        from .dwi_preprocessing_using_phasediff_fmap_workflows import (
            prepare_phasediff_fmap, )

        # Step 0: Initialization
        # ======================
        # Initialize input parameters and print begin message
        init_node = npe.Node(
            interface=nutil.Function(
                input_names=self.get_input_fields(),
                output_names=[
                    "image_id",
                    "dwi",
                    "bvec",
                    "bval",
                    "total_readout_time",
                    "phase_encoding_direction",
                    "fmap_magnitude",
                    "fmap_phasediff",
                    "delta_echo_time",
                ],
                function=init_input_node,
            ),
            name="0-InitNode",
        )

        # Generate (bvec, bval) tuple for MRtrix interfaces
        get_grad_fsl = npe.Node(
            nutil.Function(
                input_names=["bval", "bvec"],
                output_names=["grad_fsl"],
                function=get_grad_fsl,
            ),
            name="0-GetFslGrad",
        )

        # Generate <image_id>_acq.txt for eddy
        gen_acq_txt = npe.Node(
            nutil.Function(
                input_names=[
                    "in_dwi",
                    "fsl_phase_encoding_direction",
                    "total_readout_time",
                    "image_id",
                ],
                output_names=["out_acq"],
                function=generate_acq_file,
            ),
            name="0-GenerateAcqFile",
        )

        # Generate <image_id>_index.txt for eddy
        gen_index_txt = npe.Node(
            nutil.Function(
                input_names=["in_bval", "low_bval", "image_id"],
                output_names=["out_index"],
                function=generate_index_file,
            ),
            name="0-GenerateIndexFile",
        )
        gen_index_txt.inputs.low_bval = self.parameters["low_bval"]

        # Step 1: Computation of the reference b0 (i.e. average b0 but with EPI distortions)
        # =======================================
        # Compute whole brain mask
        pre_mask_b0 = npe.Node(mrtrix3.BrainMask(), name="1a-PreMaskB0")
        pre_mask_b0.inputs.out_file = (
            "brainmask.nii.gz"  # On default, .mif file is generated
        )

        # Run eddy without calibrated fmap
        pre_eddy = npe.Node(name="1b-PreEddy", interface=Eddy())
        pre_eddy.inputs.repol = True
        pre_eddy.inputs.use_cuda = self.parameters["use_cuda"]
        pre_eddy.inputs.initrand = self.parameters["initrand"]

        # Compute the reference b0
        compute_ref_b0 = npe.Node(
            niu.Function(
                input_names=["in_dwi", "in_bval"],
                output_names=["out_b0_average"],
                function=compute_average_b0,
            ),
            name="1c-ComputeReferenceB0",
        )
        compute_ref_b0.inputs.low_bval = self.parameters["low_bval"]

        # Compute brain mask from reference b0
        mask_ref_b0 = npe.Node(fsl.BET(mask=True, robust=True),
                               name="1d-MaskReferenceB0")

        # Step 2: Calibrate and register FMap
        # ===================================
        # Bias field correction of the magnitude image
        bias_mag_fmap = npe.Node(ants.N4BiasFieldCorrection(dimension=3),
                                 name="2a-N4MagnitudeFmap")
        # Brain extraction of the magnitude image
        bet_mag_fmap = npe.Node(fsl.BET(frac=0.4, mask=True),
                                name="2b-BetN4MagnitudeFmap")

        # Calibrate FMap
        calibrate_fmap = prepare_phasediff_fmap(name="2c-CalibrateFMap")

        # Register the BET magnitude fmap onto the BET b0
        bet_mag_fmap2b0 = npe.Node(interface=fsl.FLIRT(),
                                   name="2d-RegistrationBetMagToB0")
        bet_mag_fmap2b0.inputs.dof = 6
        bet_mag_fmap2b0.inputs.output_type = "NIFTI_GZ"

        # Apply the transformation on the calibrated fmap
        fmap2b0 = npe.Node(interface=fsl.ApplyXFM(), name="2e-1-FMapToB0")
        fmap2b0.inputs.output_type = "NIFTI_GZ"

        # Apply the transformation on the magnitude image
        mag_fmap2b0 = fmap2b0.clone("2e-2-MagFMapToB0")

        # Smooth the registered (calibrated) fmap
        smoothing = npe.Node(interface=fsl.maths.IsotropicSmooth(),
                             name="2f-Smoothing")
        smoothing.inputs.sigma = 4.0

        # Step 3: Run FSL eddy
        # ====================
        eddy = pre_eddy.clone("3-Eddy")

        # Step 4: Bias correction
        # =======================
        # Use implementation detailed in (Jeurissen et al., 2014)
        bias = npe.Node(mrtrix3.DWIBiasCorrect(use_ants=True),
                        name="4-RemoveBias")

        # Step 5: Final brainmask
        # =======================
        # Compute average b0 on corrected dataset (for brain mask extraction)
        compute_avg_b0 = compute_ref_b0.clone("5a-ComputeB0Average")

        # Compute b0 mask on corrected avg b0
        mask_avg_b0 = mask_ref_b0.clone("5b-MaskB0")

        # Print end message
        print_end_message = npe.Node(
            interface=nutil.Function(input_names=["image_id", "final_file"],
                                     function=print_end_pipeline),
            name="99-WriteEndMessage",
        )

        # Connection
        # ==========
        # fmt: off
        self.connect([
            # Step 0: Initialization
            # ======================
            # Initialize input parameters and print begin message
            (self.input_node, init_node, [("dwi", "dwi"), ("bvec", "bvec"),
                                          ("bval", "bval"),
                                          ("dwi_json", "dwi_json"),
                                          ("fmap_magnitude", "fmap_magnitude"),
                                          ("fmap_phasediff", "fmap_phasediff"),
                                          ("fmap_phasediff_json",
                                           "fmap_phasediff_json")]),
            # Generate (bvec, bval) tuple for MRtrix interfaces
            (init_node, get_grad_fsl, [("bval", "bval"), ("bvec", "bvec")]),
            # Generate <image_id>_acq.txt for eddy
            (init_node, gen_acq_txt,
             [("dwi", "in_dwi"), ("total_readout_time", "total_readout_time"),
              ("phase_encoding_direction", "fsl_phase_encoding_direction"),
              ("image_id", "image_id")]),
            # Generate <image_id>_index.txt for eddy
            (init_node, gen_index_txt, [("bval", "in_bval"),
                                        ("image_id", "image_id")]),

            # Step 1: Computation of the reference b0 (i.e. average b0 but with EPI distortions)
            # =======================================
            # Compute whole brain mask
            (get_grad_fsl, pre_mask_b0, [("grad_fsl", "grad_fsl")]),
            (init_node, pre_mask_b0, [("dwi", "in_file")]),
            # Run eddy without calibrated fmap
            (init_node, pre_eddy, [("dwi", "in_file"), ("bval", "in_bval"),
                                   ("bvec", "in_bvec"),
                                   ("image_id", "out_base")]),
            (gen_acq_txt, pre_eddy, [("out_acq", "in_acqp")]),
            (gen_index_txt, pre_eddy, [("out_index", "in_index")]),
            (pre_mask_b0, pre_eddy, [("out_file", "in_mask")]),
            # Compute the reference b0
            (init_node, compute_ref_b0, [("bval", "in_bval")]),
            (pre_eddy, compute_ref_b0, [("out_corrected", "in_dwi")]),
            # Compute brain mask from reference b0
            (compute_ref_b0, mask_ref_b0, [("out_b0_average", "in_file")]),

            # Step 2: Calibrate and register FMap
            # ===================================
            # Bias field correction of the magnitude image
            (init_node, bias_mag_fmap, [("fmap_magnitude", "input_image")]),
            # Brain extraction of the magnitude image
            (bias_mag_fmap, bet_mag_fmap, [("output_image", "in_file")]),
            # Calibration of the FMap
            (bet_mag_fmap, calibrate_fmap,
             [("mask_file", "input_node.fmap_mask"),
              ("out_file", "input_node.fmap_magnitude")]),
            (init_node, calibrate_fmap,
             [("fmap_phasediff", "input_node.fmap_phasediff"),
              ("delta_echo_time", "input_node.delta_echo_time")]),
            # Register the BET magnitude fmap onto the BET b0
            (bet_mag_fmap, bet_mag_fmap2b0, [("out_file", "in_file")]),
            (mask_ref_b0, bet_mag_fmap2b0, [("out_file", "reference")]),
            # Apply the transformation on the magnitude image
            (bet_mag_fmap2b0, mag_fmap2b0, [("out_matrix_file",
                                             "in_matrix_file")]),
            (bias_mag_fmap, mag_fmap2b0, [("output_image", "in_file")]),
            (mask_ref_b0, mag_fmap2b0, [("out_file", "reference")]),
            # Apply the transformation on the calibrated fmap
            (bet_mag_fmap2b0, fmap2b0, [("out_matrix_file", "in_matrix_file")]
             ),
            (calibrate_fmap, fmap2b0, [("output_node.calibrated_fmap",
                                        "in_file")]),
            (mask_ref_b0, fmap2b0, [("out_file", "reference")]),
            # # Smooth the registered (calibrated) fmap
            (fmap2b0, smoothing, [("out_file", "in_file")]),

            # Step 3: Run FSL eddy
            # ====================
            (init_node, eddy, [("dwi", "in_file"), ("bval", "in_bval"),
                               ("bvec", "in_bvec"), ("image_id", "out_base")]),
            (gen_acq_txt, eddy, [("out_acq", "in_acqp")]),
            (gen_index_txt, eddy, [("out_index", "in_index")]),
            (smoothing, eddy, [("out_file", "field")]),
            (pre_mask_b0, eddy, [("out_file", "in_mask")]),

            # Step 4: Bias correction
            # =======================
            (init_node, bias, [("bval", "in_bval")]),
            (eddy, bias, [("out_rotated_bvecs", "in_bvec"),
                          ("out_corrected", "in_file")]),
            # Step 5: Final brainmask
            # =======================
            # Compute average b0 on corrected dataset (for brain mask extraction)
            (init_node, compute_avg_b0, [("bval", "in_bval")]),
            (bias, compute_avg_b0, [("out_file", "in_dwi")]),
            # Compute b0 mask on corrected avg b0
            (compute_avg_b0, mask_avg_b0, [("out_b0_average", "in_file")]),

            # Print end message
            (init_node, print_end_message, [("image_id", "image_id")]),
            (mask_avg_b0, print_end_message, [("mask_file", "final_file")]),

            # Output node
            (init_node, self.output_node, [("bval", "preproc_bval")]),
            (eddy, self.output_node, [("out_rotated_bvecs", "preproc_bvec")]),
            (bias, self.output_node, [("out_file", "preproc_dwi")]),
            (mask_avg_b0, self.output_node, [("mask_file", "b0_mask")]),
            (bet_mag_fmap2b0, self.output_node, [("out_file",
                                                  "magnitude_on_b0")]),
            (fmap2b0, self.output_node, [("out_file", "calibrated_fmap_on_b0")
                                         ]),
            (smoothing, self.output_node, [("out_file", "smoothed_fmap_on_b0")
                                           ]),
        ])
Example #4
0
    def preprocess_dwi_data(self,
                            data,
                            index,
                            acqp,
                            atlas2use,
                            ResponseSD_algorithm='tournier',
                            fod_algorithm='csd',
                            tract_algorithm='iFOD2',
                            streamlines_number='10M'):
        '''
        preprocessing of dwi data and connectome extraction

        Parameters
        ----------

        subjects_dir = path to the subjects' folders
        data: tuple |
            a tuple having the path to dwi, bvecs and bvals files. It is obtained
            using the function grab_data()
        index: str |
            Name of text file specifying the relationship between the images in
            --imain and the information in --acqp and --topup. E.g. index.txt
        acqp: str |
            Name of text file with information about the acquisition of the images
            in --imain
        atlas2use: str |
             The input node parcellation image
        ResponseSD_algorithm (optional): str |
             Select the algorithm to be used to complete the script operation;
             Options are: dhollander, fa, manual, msmt_5tt, tax, tournier
             (Default is 'tournier')
        fod_algorithm (optional): str |
             The algorithm to use for FOD estimation. (options are: csd,msmt_csd)
             (Default is 'csd')
        tract_algorithm (optional): str |
            specify the tractography algorithm to use. Valid choices are: FACT,
            iFOD1, iFOD2, Nulldist1, Nulldist2, SD_Stream, Seedtest, Tensor_Det,
            Tensor_Prob (Default is 'iFOD2')
        streamlines_number (optional): str |
            set the desired number of streamlines (Default is '10M')
    '''

        if len(data[0]) != len(data[1]):
            raise ValueError(
                'dwi datas do not have the same shape of bvec files')
        if len(data[0]) != len(data[2]):
            raise ValueError(
                'dwi datas do not have the same shape of bval files')
        if len(data[1]) != len(data[2]):
            raise ValueError(
                'bvec files do not have the same shape of bvec files')

        for subj in range(len(data[0])):
            print('Extracting B0 volume for subject', subj)
            self.roi = fsl.ExtractROI(
                in_file=data[0][subj],
                roi_file=os.path.join(
                    os.path.split(data[0][subj])[0] + '/' +
                    os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                    '_nodiff.nii.gz'),
                t_min=0,
                t_size=1)
            self.roi.run()

            print('Converting into .mif for subject', subj)
            self.mrconvert = mrt.MRConvert()
            self.mrconvert.inputs.in_file = data[0][subj]
            self.mrconvert.inputs.grad_fsl = (data[1][subj], data[2][subj])
            self.mrconvert.inputs.out_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi.mif')
            self.mrconvert.run()

            print('Denoising data for subject', subj)
            self.denoise = mrt.DWIDenoise()
            self.denoise.inputs.in_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_dwi.mif')
            self.denoise.inputs.noise = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_noise.mif')
            self.denoise.inputs.out_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_dwi_denoised.mif')
            self.denoise.run()

            self.denoise_convert = mrt.MRConvert()
            self.denoise_convert.inputs.in_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_dwi_denoised.mif')
            self.denoise_convert.inputs.out_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_dwi_denoised.nii.gz')
            self.denoise_convert.run()

            print('Skull stripping for subject', subj)
            self.mybet = fsl.BET()
            self.mybet.inputs.in_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_nodiff.nii.gz')
            self.mybet.inputs.out_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_denoised_brain.nii.gz')
            self.mybet.inputs.frac = 0.1
            self.mybet.inputs.robust = True
            self.mybet.inputs.mask = True
            self.mybet.run()

            print('Running Eddy for subject', subj)
            self.eddy = Eddy()
            self.eddy.inputs.in_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_dwi_denoised.nii.gz')
            self.eddy.inputs.in_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_denoised_brain_mask.nii.gz')
            self.eddy.inputs.in_acqp = acqp
            self.eddy.inputs.in_bvec = data[1][subj]
            self.eddy.inputs.in_bval = data[2][subj]
            self.eddy.inputs.out_base = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_dwi_denoised_eddy.nii.gz')
            self.eddy.run()

            print('Running Bias Correction for subject', subj)
            self.bias_correct = mrt.DWIBiasCorrect()
            self.bias_correct.inputs.use_ants = True
            self.bias_correct.inputs.in_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_dwi_denoised_eddy.nii.gz')
            self.bias_correct.inputs.grad_fsl = (os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_dwi_denoised_eddy.eddy_rotated_bvecs.bvec'), data[2][subj])
            self.bias_correct.inputs.bias = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] + '_bias.mif')
            self.bias_correct.inputs.out_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_dwi_denoised_eddy_unbiased.mif')
            self.bias_correct.run()

            print('Calculating Response function for subject', subj)
            self.resp = mrt.ResponseSD()
            self.resp.inputs.in_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_dwi_denoised_eddy_unbiased.mif')
            self.resp.inputs.algorithm = ResponseSD_algorithm
            self.resp.inputs.grad_fsl = (os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_dwi_denoised_eddy.eddy_rotated_bvecs.bvec'), data[2][subj])
            self.resp.inputs.wm_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_response.txt')
            self.resp.run()

            print('Estimating FOD for subject', subj)
            self.fod = mrt.EstimateFOD()
            self.fod.inputs.algorithm = fod_algorithm
            self.fod.inputs.in_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_dwi_denoised_eddy_unbiased.mif')
            self.fod.inputs.wm_txt = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_response.txt')
            self.fod.inputs.mask_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_denoised_brain_mask.nii.gz')
            self.fod.inputs.grad_fsl = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_response.txt')
            self.fod.run()

            print('Extracting whole brain tract for subject', subj)
            self.tk = mrt.Tractography()
            self.tk.inputs.in_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] + 'fods.mif')
            self.tk.inputs.roi_mask = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_denoised_brain_mask.nii.gz')
            self.tk.inputs.algorithm = tract_algorithm
            self.tk.inputs.seed_image = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_denoised_brain_mask.nii.gz')
            self.tk.inputs.select = streamlines_number
            self.tk.inputs.out_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_whole_brain_' + streamlines_number + '.tck')
            self.tk.run()

            print('Extracting connectome for subject', subj)
            self.mat = mrt.BuildConnectome()
            self.mat.inputs.in_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_whole_brain_' + streamlines_number + '.tck')
            self.mat.inputs.in_parc = atlas2use
            self.mat.inputs.out_file = os.path.join(
                os.path.split(data[0][subj])[0] + '/' +
                os.path.split(data[0][0])[1].split(".nii.gz")[0] +
                '_connectome.csv')
            self.mat.run()
Example #5
0
                          name='io_data_grabber')
io_data_grabber.inputs.sort_filelist = True
io_data_grabber.inputs.template = "/Users/bsms9gep/data/*.nii"

#Wraps the executable command ``mrconvert``.
mrtrix3_mrconvert = pe.Node(interface=mrtrix3.MRConvert(),
                            name='mrtrix3_mrconvert')
mrtrix3_mrconvert.inputs.grad_fsl = ("/Users/bsms9gep/data/bvecs",
                                     "/Users/bsms9gep/data/bvals")

#Wraps the executable command ``dwi2mask``.
mrtrix3_brain_mask = pe.Node(interface=mrtrix3.BrainMask(),
                             name='mrtrix3_brain_mask')

#Wraps the executable command ``dwibiascorrect``.
mrtrix3_dwibias_correct = pe.Node(interface=mrtrix3.DWIBiasCorrect(),
                                  name='mrtrix3_dwibias_correct')
mrtrix3_dwibias_correct.inputs.out_file = 'dwi_unbiased.mif'

#Wraps the executable command ``dwi2response``.
mrtrix3_response_sd = pe.Node(interface=mrtrix3.ResponseSD(),
                              name='mrtrix3_response_sd')
mrtrix3_response_sd.inputs.algorithm = 'dhollander'
mrtrix3_response_sd.inputs.gm_file = 'gm.txt'
mrtrix3_response_sd.inputs.csf_file = 'csf.txt'
mrtrix3_response_sd.inputs.max_sh = (8, 8, 8)

#Wraps the executable command ``dwi2fod``.
mrtrix3_estimate_fod = pe.Node(interface=mrtrix3.EstimateFOD(),
                               name='mrtrix3_estimate_fod')
mrtrix3_estimate_fod.inputs.algorithm = 'msmt_csd'
Example #6
0
    def build_core_nodes(self):
        """Build and connect the core nodes of the pipeline."""
        import nipype.interfaces.fsl as fsl
        import nipype.interfaces.mrtrix3 as mrtrix3
        import nipype.interfaces.utility as nutil
        import nipype.pipeline.engine as npe

        from clinica.utils.dwi import compute_average_b0

        from .dwi_preprocessing_using_t1_utils import (
            init_input_node,
            prepare_reference_b0,
            print_end_pipeline,
        )
        from .dwi_preprocessing_using_t1_workflows import (
            eddy_fsl_pipeline,
            epi_pipeline,
        )

        # Nodes creation
        # ==============
        # Initialize input parameters and print begin message
        init_node = npe.Node(
            interface=nutil.Function(
                input_names=self.get_input_fields(),
                output_names=[
                    "image_id",
                    "t1w",
                    "dwi",
                    "bvec",
                    "bval",
                    "total_readout_time",
                    "phase_encoding_direction",
                ],
                function=init_input_node,
            ),
            name="0-InitNode",
        )

        # Prepare b0 image for further corrections
        prepare_b0 = npe.Node(
            name="PrepareB0",
            interface=nutil.Function(
                input_names=[
                    "in_dwi",
                    "in_bval",
                    "in_bvec",
                    "low_bval",
                    "working_directory",
                ],
                output_names=[
                    "out_reference_b0",
                    "out_b0_dwi_merge",
                    "out_updated_bval",
                    "out_updated_bvec",
                ],
                function=prepare_reference_b0,
            ),
        )
        prepare_b0.inputs.low_bval = self.parameters["low_bval"]
        prepare_b0.inputs.working_directory = self.base_dir
        # Mask b0 for computations purposes
        mask_b0_pre = npe.Node(fsl.BET(frac=0.3, mask=True, robust=True),
                               name="PreMaskB0")
        # Head-motion correction + Eddy-currents correction
        eddy_fsl = eddy_fsl_pipeline(
            low_bval=self.parameters["low_bval"],
            use_cuda=self.parameters["use_cuda"],
            initrand=self.parameters["initrand"],
        )
        # Susceptibility distortion correction using T1w image
        sdc = epi_pipeline(name="SusceptibilityDistortionCorrection")
        # Remove bias correction from (Jeurissen et al., 2014)
        bias = npe.Node(mrtrix3.DWIBiasCorrect(use_ants=True),
                        name="RemoveBias")
        # Compute b0 mask on corrected avg b0
        compute_avg_b0 = npe.Node(
            nutil.Function(
                input_names=["in_dwi", "in_bval"],
                output_names=["out_b0_average"],
                function=compute_average_b0,
            ),
            name="ComputeB0Average",
        )
        compute_avg_b0.inputs.low_bval = self.parameters["low_bval"]

        # Compute brain mask from reference b0
        mask_avg_b0 = npe.Node(fsl.BET(mask=True, robust=True), name="MaskB0")

        # Print end message
        print_end_message = npe.Node(
            interface=nutil.Function(input_names=["image_id", "final_file"],
                                     function=print_end_pipeline),
            name="WriteEndMessage",
        )

        # Connection
        # ==========
        # fmt: off
        self.connect([
            # Initialize input parameters and print begin message
            (self.input_node, init_node, [("t1w", "t1w"), ("dwi", "dwi"),
                                          ("bvec", "bvec"), ("bval", "bval"),
                                          ("dwi_json", "dwi_json")]),
            # Preliminary step (possible computation of a mean b0):
            (init_node, prepare_b0, [("dwi", "in_dwi"), ("bval", "in_bval"),
                                     ("bvec", "in_bvec")]),
            # Mask b0 before corrections
            (prepare_b0, mask_b0_pre, [("out_reference_b0", "in_file")]),
            # Head-motion correction + eddy current correction
            (init_node, eddy_fsl, [("total_readout_time",
                                    "inputnode.total_readout_time"),
                                   ("phase_encoding_direction",
                                    "inputnode.phase_encoding_direction")]),
            (prepare_b0, eddy_fsl, [("out_b0_dwi_merge", "inputnode.in_file"),
                                    ("out_updated_bval", "inputnode.in_bval"),
                                    ("out_updated_bvec", "inputnode.in_bvec"),
                                    ("out_reference_b0", "inputnode.ref_b0")]),
            (mask_b0_pre, eddy_fsl, [("mask_file", "inputnode.in_mask")]),
            # Magnetic susceptibility correction
            (init_node, sdc, [("t1w", "inputnode.T1")]),
            (eddy_fsl, sdc, [("outputnode.out_corrected", "inputnode.DWI")]),
            (eddy_fsl, sdc, [("outputnode.out_rotated_bvecs", "inputnode.bvec")
                             ]),
            # Bias correction
            (prepare_b0, bias, [("out_updated_bval", "in_bval")]),
            (sdc, bias, [("outputnode.DWIs_epicorrected", "in_file"),
                         ("outputnode.out_bvec", "in_bvec")]),
            # Compute average b0 on corrected dataset (for brain mask extraction)
            (prepare_b0, compute_avg_b0, [("out_updated_bval", "in_bval")]),
            (bias, compute_avg_b0, [("out_file", "in_dwi")]),
            # Compute b0 mask on corrected avg b0
            (compute_avg_b0, mask_avg_b0, [("out_b0_average", "in_file")]),
            # Print end message
            (init_node, print_end_message, [("image_id", "image_id")]),
            (mask_avg_b0, print_end_message, [("mask_file", "final_file")]),
            # Output node
            (bias, self.output_node, [("out_file", "preproc_dwi")]),
            (sdc, self.output_node, [("outputnode.out_bvec", "preproc_bvec")]),
            (prepare_b0, self.output_node, [("out_updated_bval",
                                             "preproc_bval")]),
            (mask_avg_b0, self.output_node, [("mask_file", "b0_mask")]),
        ])