def test_BrainExtractionRPT(monkeypatch, moving, nthreads):
    """ test antsBrainExtraction with reports"""

    def _agg(objekt, runtime):
        outputs = Bunch(BrainExtractionMask=os.path.join(
            datadir, 'testBrainExtractionRPTBrainExtractionMask.nii.gz')
        )
        return outputs

    # Patch the _run_interface method
    monkeypatch.setattr(BrainExtractionRPT, '_run_interface',
                        _run_interface_mock)
    monkeypatch.setattr(BrainExtractionRPT, 'aggregate_outputs',
                        _agg)

    bex_rpt = BrainExtractionRPT(
        generate_report=True,
        dimension=3,
        use_floatingpoint_precision=1,
        anatomical_image=moving,
        brain_template=str(
            get_template('OASIS30ANTs', resolution=1, desc=None, suffix='T1w')),
        brain_probability_mask=str(
            get_template('OASIS30ANTs', resolution=1,
                         label='brain', suffix='probseg')),
        extraction_registration_mask=str(
            get_template('OASIS30ANTs', resolution=1,
                         desc='BrainCerebellumRegistration', suffix='mask')),
        out_prefix='testBrainExtractionRPT',
        debug=True,  # run faster for testing purposes
        num_threads=nthreads
    )
    _smoke_test_report(bex_rpt, 'testANTSBrainExtraction.svg')
def test_ROIsPlot():
    """ the BET report capable test """
    import nibabel as nb
    import numpy as np

    im = nb.load(str(
        get_template('OASIS30ANTs', resolution=1, desc='4',
                     suffix='dseg', extensions=['.nii', '.nii.gz'])))
    lookup = np.zeros(5, dtype=int)
    lookup[1] = 1
    lookup[2] = 4
    lookup[3] = 2
    lookup[4] = 3
    newdata = lookup[np.round(im.get_data()).astype(int)]
    hdr = im.header.copy()
    hdr.set_data_dtype('int16')
    hdr['scl_slope'] = 1
    hdr['scl_inter'] = 0
    out_file = os.path.abspath('segments.nii.gz')
    nb.Nifti1Image(newdata, im.affine, hdr).to_filename(out_file)
    roi_rpt = ROIsPlot(
        generate_report=True,
        in_file=str(
            get_template('OASIS30ANTs', resolution=1, desc=None, suffix='T1w')),
        in_mask=str(
            get_template('OASIS30ANTs', resolution=1, desc='brain', suffix='mask')),
        in_rois=[out_file],
        levels=[1.5, 2.5, 3.5],
        colors=['gold', 'magenta', 'b'],
    )
    _smoke_test_report(roi_rpt, 'testROIsPlot.svg')
def test_SimpleShowMaskRPT():
    """ the BET report capable test """

    msk_rpt = SimpleShowMaskRPT(
        generate_report=True,
        background_file=str(
            get_template('OASIS30ANTs', resolution=1, desc=None, suffix='T1w')),
        mask_file=str(
            get_template('OASIS30ANTs', resolution=1,
                         desc='BrainCerebellumRegistration', suffix='mask'))
    )
    _smoke_test_report(msk_rpt, 'testSimpleMask.svg')
Esempio n. 4
0
    def _validate_results(self):
        forward_transform = self._results['composite_transform']
        input_mask = self.inputs.moving_mask
        if isdefined(self.inputs.reference_mask):
            target_mask = self.inputs.reference_mask
        else:
            resolution = self.inputs.template_resolution
            target_mask = get_template(self.inputs.template, resolution=resolution,
                                       desc='brain', suffix='mask')

        res = ApplyTransforms(dimension=3,
                              input_image=input_mask,
                              reference_image=str(target_mask),
                              transforms=forward_transform,
                              interpolation='NearestNeighbor',
                              resource_monitor=False).run()
        input_mask_data = (nb.load(res.outputs.output_image).get_data() != 0)
        target_mask_data = (nb.load(str(target_mask)).get_data() != 0)

        overlap_voxel_count = np.logical_and(input_mask_data, target_mask_data)

        overlap_perc = float(overlap_voxel_count.sum()) / float(input_mask_data.sum()) * 100

        assert overlap_perc > 50, \
            "Normalization failed: only %d%% of the normalized moving image " \
            "mask overlaps with the reference image mask." % overlap_perc
Esempio n. 5
0
def test_ROIsPlot2(tmp_path):
    """ the BET report capable test """
    import nibabel as nb
    import numpy as np

    im = nb.load(
        str(
            get_template(
                "OASIS30ANTs",
                resolution=1,
                desc="4",
                suffix="dseg",
                extension=[".nii", ".nii.gz"],
            )))
    lookup = np.zeros(5, dtype=int)
    lookup[1] = 1
    lookup[2] = 4
    lookup[3] = 2
    lookup[4] = 3
    newdata = lookup[np.round(im.get_fdata()).astype(int)]
    hdr = im.header.copy()
    hdr.set_data_dtype("int16")
    hdr["scl_slope"] = 1
    hdr["scl_inter"] = 0

    out_files = []
    for i in range(1, 5):
        seg = np.zeros_like(newdata, dtype="uint8")
        seg[(newdata > 0) & (newdata <= i)] = 1
        out_file = str(tmp_path / ("segments%02d.nii.gz" % i))
        nb.Nifti1Image(seg, im.affine, hdr).to_filename(out_file)
        out_files.append(out_file)
    roi_rpt = ROIsPlot(
        generate_report=True,
        in_file=str(
            get_template("OASIS30ANTs", resolution=1, desc=None,
                         suffix="T1w")),
        in_mask=str(
            get_template("OASIS30ANTs",
                         resolution=1,
                         desc="brain",
                         suffix="mask")),
        in_rois=out_files,
        colors=["gold", "lightblue", "b", "g"],
    )
    _smoke_test_report(roi_rpt, "testROIsPlot2.svg")
Esempio n. 6
0
def test_ROIsPlot2(tmp_path):
    """ the BET report capable test """
    import nibabel as nb
    import numpy as np

    im = nb.load(
        str(
            get_template('OASIS30ANTs',
                         resolution=1,
                         desc='4',
                         suffix='dseg',
                         extension=['.nii', '.nii.gz'])))
    lookup = np.zeros(5, dtype=int)
    lookup[1] = 1
    lookup[2] = 4
    lookup[3] = 2
    lookup[4] = 3
    newdata = lookup[np.round(im.get_data()).astype(int)]
    hdr = im.header.copy()
    hdr.set_data_dtype('int16')
    hdr['scl_slope'] = 1
    hdr['scl_inter'] = 0

    out_files = []
    for i in range(1, 5):
        seg = np.zeros_like(newdata, dtype='uint8')
        seg[(newdata > 0) & (newdata <= i)] = 1
        out_file = str(tmp_path / ('segments%02d.nii.gz' % i))
        nb.Nifti1Image(seg, im.affine, hdr).to_filename(out_file)
        out_files.append(out_file)
    roi_rpt = ROIsPlot(generate_report=True,
                       in_file=str(
                           get_template('OASIS30ANTs',
                                        resolution=1,
                                        desc=None,
                                        suffix='T1w')),
                       in_mask=str(
                           get_template('OASIS30ANTs',
                                        resolution=1,
                                        desc='brain',
                                        suffix='mask')),
                       in_rois=out_files,
                       colors=['gold', 'lightblue', 'b', 'g'])
    _smoke_test_report(roi_rpt, 'testROIsPlot2.svg')
Esempio n. 7
0
def test_ROIsPlot(tmp_path):
    """ the BET report capable test """
    import nibabel as nb
    import numpy as np

    im = nb.load(
        str(
            get_template(
                "OASIS30ANTs",
                resolution=1,
                desc="4",
                suffix="dseg",
                extension=[".nii", ".nii.gz"],
            )))
    lookup = np.zeros(5, dtype=int)
    lookup[1] = 1
    lookup[2] = 4
    lookup[3] = 2
    lookup[4] = 3
    newdata = lookup[np.round(im.get_fdata()).astype(int)]
    hdr = im.header.copy()
    hdr.set_data_dtype("int16")
    hdr["scl_slope"] = 1
    hdr["scl_inter"] = 0
    out_file = str(tmp_path / "segments.nii.gz")
    nb.Nifti1Image(newdata, im.affine, hdr).to_filename(out_file)
    roi_rpt = ROIsPlot(
        generate_report=True,
        in_file=str(
            get_template("OASIS30ANTs", resolution=1, desc=None,
                         suffix="T1w")),
        in_mask=str(
            get_template("OASIS30ANTs",
                         resolution=1,
                         desc="brain",
                         suffix="mask")),
        in_rois=[out_file],
        levels=[1.5, 2.5, 3.5],
        colors=["gold", "magenta", "b"],
    )
    _smoke_test_report(roi_rpt, "testROIsPlot.svg")
Esempio n. 8
0
def get_template_specs(in_template, template_spec=None, default_resolution=1):
    """
    Parse template specifications

    >>> get_template_specs('MNI152NLin2009cAsym', {'suffix': 'T1w'})[1]
    {'resolution': 1}

    >>> get_template_specs('MNI152NLin2009cAsym', {'res': '2', 'suffix': 'T1w'})[1]
    {'resolution': '2'}

    >>> specs = get_template_specs('MNIInfant', {'res': '2', 'cohort': '10', 'suffix': 'T1w'})[1]
    >>> sorted(specs.items())
    [('cohort', '10'), ('resolution', '2')]

    >>> get_template_specs('MNI152NLin2009cAsym',
    ...                    {'suffix': 'T1w', 'cohort': 1})[1] # doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    RuntimeError:
    ...

    >>> get_template_specs('MNI152NLin2009cAsym',
    ...                    {'suffix': 'T1w', 'res': '1|2'})[1] # doctest: +IGNORE_EXCEPTION_DETAIL
    Traceback (most recent call last):
    RuntimeError:
    ...

    """
    from templateflow.api import get as get_template

    # Massage spec (start creating if None)
    template_spec = template_spec or {}
    template_spec["desc"] = template_spec.get("desc", None)
    template_spec["atlas"] = template_spec.get("atlas", None)
    template_spec["resolution"] = template_spec.pop(
        "res", template_spec.get("resolution", default_resolution))

    common_spec = {"resolution": template_spec["resolution"]}
    if "cohort" in template_spec:
        common_spec["cohort"] = template_spec["cohort"]

    tpl_target_path = get_template(in_template, **template_spec)
    if not tpl_target_path:
        raise RuntimeError("""\
Could not find template "{0}" with specs={1}. Please revise your template \
argument.""".format(in_template, template_spec))

    if isinstance(tpl_target_path, list):
        raise RuntimeError("""\
The available template modifiers ({0}) did not select a unique template \
(got "{1}"). Please revise your template argument.""".format(
            template_spec, ", ".join([str(p) for p in tpl_target_path])))

    return str(tpl_target_path), common_spec
Esempio n. 9
0
def test_BrainExtractionRPT(monkeypatch, moving, nthreads):
    """ test antsBrainExtraction with reports"""
    def _agg(objekt, runtime):
        outputs = objekt.output_spec()
        outputs.BrainExtractionMask = os.path.join(
            datadir, "testBrainExtractionRPTBrainExtractionMask.nii.gz")
        outputs.out_report = os.path.join(runtime.cwd,
                                          objekt.inputs.out_report)
        return outputs

    # Patch the _run_interface method
    monkeypatch.setattr(BrainExtractionRPT, "_run_interface",
                        _run_interface_mock)
    monkeypatch.setattr(BrainExtractionRPT, "aggregate_outputs", _agg)

    bex_rpt = BrainExtractionRPT(
        generate_report=True,
        dimension=3,
        use_floatingpoint_precision=1,
        anatomical_image=moving,
        brain_template=str(
            get_template("OASIS30ANTs", resolution=1, desc=None,
                         suffix="T1w")),
        brain_probability_mask=str(
            get_template("OASIS30ANTs",
                         resolution=1,
                         label="brain",
                         suffix="probseg")),
        extraction_registration_mask=str(
            get_template(
                "OASIS30ANTs",
                resolution=1,
                desc="BrainCerebellumRegistration",
                suffix="mask",
            )),
        out_prefix="testBrainExtractionRPT",
        debug=True,  # run faster for testing purposes
        num_threads=nthreads,
    )
    _smoke_test_report(bex_rpt, "testANTSBrainExtraction.svg")
Esempio n. 10
0
def test_compression(tmp_path):
    """ the BET report capable test """

    uncompressed = pe.Node(
        SimpleShowMaskRPT(generate_report=True,
                          background_file=str(
                              get_template('OASIS30ANTs',
                                           resolution=1,
                                           desc=None,
                                           suffix='T1w')),
                          mask_file=str(
                              get_template('OASIS30ANTs',
                                           resolution=1,
                                           desc='BrainCerebellumRegistration',
                                           suffix='mask')),
                          compress_report=False),
        name='uncompressed',
        base_dir=str(tmp_path)).run().outputs.out_report

    compressed = pe.Node(
        SimpleShowMaskRPT(generate_report=True,
                          background_file=str(
                              get_template('OASIS30ANTs',
                                           resolution=1,
                                           desc=None,
                                           suffix='T1w')),
                          mask_file=str(
                              get_template('OASIS30ANTs',
                                           resolution=1,
                                           desc='BrainCerebellumRegistration',
                                           suffix='mask')),
                          compress_report=True),
        name='compressed',
        base_dir=str(tmp_path)).run().outputs.out_report

    size = int(os.stat(uncompressed).st_size)
    size_compress = int(os.stat(compressed).st_size)
    assert size >= size_compress, ('The uncompressed report is smaller (%d)'
                                   'than the compressed report (%d)' %
                                   (size, size_compress))
Esempio n. 11
0
def test_ROIsPlot(tmp_path):
    """ the BET report capable test """
    import nibabel as nb
    import numpy as np

    im = nb.load(
        str(
            get_template('OASIS30ANTs',
                         resolution=1,
                         desc='4',
                         suffix='dseg',
                         extension=['.nii', '.nii.gz'])))
    lookup = np.zeros(5, dtype=int)
    lookup[1] = 1
    lookup[2] = 4
    lookup[3] = 2
    lookup[4] = 3
    newdata = lookup[np.round(im.get_data()).astype(int)]
    hdr = im.header.copy()
    hdr.set_data_dtype('int16')
    hdr['scl_slope'] = 1
    hdr['scl_inter'] = 0
    out_file = str(tmp_path / 'segments.nii.gz')
    nb.Nifti1Image(newdata, im.affine, hdr).to_filename(out_file)
    roi_rpt = ROIsPlot(
        generate_report=True,
        in_file=str(
            get_template('OASIS30ANTs', resolution=1, desc=None,
                         suffix='T1w')),
        in_mask=str(
            get_template('OASIS30ANTs',
                         resolution=1,
                         desc='brain',
                         suffix='mask')),
        in_rois=[out_file],
        levels=[1.5, 2.5, 3.5],
        colors=['gold', 'magenta', 'b'],
    )
    _smoke_test_report(roi_rpt, 'testROIsPlot.svg')
Esempio n. 12
0
def mni_downsampled(tmp_path_factory):
    tmp_path = tmp_path_factory.mktemp(basename="mni_downsampled")

    os.chdir(str(tmp_path))

    tpl = get_template("MNI152NLin2009cAsym", resolution=2, desc="brain", suffix="mask")

    result = ants.ResampleImageBySpacing(
        dimension=3, input_image=tpl, out_spacing=(6, 6, 6)
    ).run()
    assert result.outputs is not None

    return result.outputs.output_image
Esempio n. 13
0
    def _run_interface(self, runtime, correct_return_codes=(0, )):
        self.resample = False

        input_space = self.inputs.input_space
        reference_space = self.inputs.reference_space
        reference_res = (self.inputs.reference_res
                         if isdefined(self.inputs.reference_res) else None)

        if not isdefined(self.inputs.reference_image):
            if reference_res is not None:
                self.inputs.reference_image = get_template(
                    reference_space,
                    resolution=reference_res,
                    desc="brain",
                    suffix="mask",
                )

        input_image = nib.load(self.inputs.input_image)
        reference_image = nib.load(self.inputs.reference_image)
        input_matches_reference = input_image.shape[:
                                                    3] == reference_image.shape[:
                                                                                3]
        input_matches_reference = input_matches_reference and np.allclose(
            input_image.affine,
            reference_image.affine,
            atol=1e-2,
            rtol=1e-2,  # tolerance of 0.01 mm
        )

        self.inputs.dimension = 3

        input_image_nvol = nvol(input_image)
        if input_image_nvol > 0:
            self.inputs.input_image_type = 3  # time series

        transforms = ["identity"]
        if input_space != reference_space:
            xfm = getresource(
                f"tpl_{reference_space}_from_{input_space}_mode_image_xfm.h5")
            assert Path(xfm).is_file()
            transforms = [str(xfm)]

        self.inputs.transforms = transforms

        if (not input_matches_reference or set(transforms) != set(["identity"])
                or not self.inputs.lazy):
            self.resample = True
            runtime = super(Resample,
                            self)._run_interface(runtime, correct_return_codes)

        return runtime
Esempio n. 14
0
def spatial_normalization(settings,
                          mod='T1w',
                          name='SpatialNormalization',
                          resolution=2):
    """
    A simple workflow to perform spatial normalization

    """
    # Have some settings handy
    tpl_id = settings.get('template_id', 'MNI152NLin2009cAsym')

    # Define workflow interface
    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(
        niu.IdentityInterface(fields=['moving_image', 'moving_mask']),
        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(
        fields=['inverse_composite_transform', 'out_report']),
                         name='outputnode')

    # Spatial normalization
    norm = pe.Node(
        RobustMNINormalization(
            flavor='testing' if settings.get('testing', False) else 'fast',
            num_threads=settings.get('ants_nthreads'),
            float=settings.get('ants_float', False),
            template=tpl_id,
            template_resolution=2,
            reference=mod,
            generate_report=True,
        ),
        name='SpatialNormalization',
        # Request all MultiProc processes when ants_nthreads > n_procs
        num_threads=min(
            settings.get('ants_nthreads', DEFAULTS['ants_nthreads']),
            settings.get('n_procs', 1)),
        mem_gb=3)
    norm.inputs.reference_mask = str(
        get_template(tpl_id,
                     resolution=resolution,
                     desc='brain',
                     suffix='mask'))

    workflow.connect([
        (inputnode, norm, [('moving_image', 'moving_image'),
                           ('moving_mask', 'moving_mask')]),
        (norm, outputnode, [('inverse_composite_transform',
                             'inverse_composite_transform'),
                            ('out_report', 'out_report')]),
    ])
    return workflow
Esempio n. 15
0
def spatial_normalization(name="SpatialNormalization"):
    """Create a simplied workflow to perform fast spatial normalization."""
    from niworkflows.interfaces.reportlets.registration import (
        SpatialNormalizationRPT as RobustMNINormalization, )

    # Have the template id handy
    tpl_id = config.workflow.template_id

    # Define workflow interface
    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(
        niu.IdentityInterface(
            fields=["moving_image", "moving_mask", "modality"]),
        name="inputnode",
    )
    outputnode = pe.Node(
        niu.IdentityInterface(
            fields=["inverse_composite_transform", "out_report"]),
        name="outputnode",
    )

    # Spatial normalization
    norm = pe.Node(
        RobustMNINormalization(
            flavor=["testing", "fast"][config.execution.debug],
            num_threads=config.nipype.omp_nthreads,
            float=config.execution.ants_float,
            template=tpl_id,
            generate_report=True,
        ),
        name="SpatialNormalization",
        # Request all MultiProc processes when ants_nthreads > n_procs
        num_threads=config.nipype.omp_nthreads,
        mem_gb=3,
    )
    norm.inputs.reference_mask = str(
        get_template(tpl_id, resolution=2, desc="brain", suffix="mask"))

    # fmt: off
    workflow.connect([
        (inputnode, norm, [("moving_image", "moving_image"),
                           ("moving_mask", "moving_mask"),
                           ("modality", "reference")]),
        (norm, outputnode, [("inverse_composite_transform",
                             "inverse_composite_transform"),
                            ("out_report", "out_report")]),
    ])
    # fmt: on

    return workflow
Esempio n. 16
0
def airmsk_wf(name='AirMaskWorkflow'):
    """
    Implements the Step 1 of [Mortamet2009]_.

    .. workflow::

        from mriqc.workflows.anatomical import airmsk_wf
        from mriqc.testing import mock_config
        with mock_config():
            wf = airmsk_wf()

    """
    workflow = pe.Workflow(name=name)

    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'in_file', 'in_mask', 'head_mask', 'inverse_composite_transform'
    ]),
                        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(
        fields=['hat_mask', 'air_mask', 'art_mask', 'rot_mask']),
                         name='outputnode')

    rotmsk = pe.Node(RotationMask(), name='RotationMask')

    invt = pe.Node(ants.ApplyTransforms(dimension=3,
                                        default_value=0,
                                        interpolation='MultiLabel',
                                        float=True),
                   name='invert_xfm')
    invt.inputs.input_image = str(
        get_template('MNI152NLin2009cAsym',
                     resolution=1,
                     desc='head',
                     suffix='mask'))

    qi1 = pe.Node(ArtifactMask(), name='ArtifactMask')

    workflow.connect([(inputnode, rotmsk, [('in_file', 'in_file')]),
                      (inputnode, qi1, [('in_file', 'in_file'),
                                        ('head_mask', 'head_mask')]),
                      (rotmsk, qi1, [('out_file', 'rot_mask')]),
                      (inputnode, invt, [('in_mask', 'reference_image'),
                                         ('inverse_composite_transform',
                                          'transforms')]),
                      (invt, qi1, [('output_image', 'nasion_post_mask')]),
                      (qi1, outputnode, [('out_hat_msk', 'hat_mask'),
                                         ('out_air_msk', 'air_mask'),
                                         ('out_art_msk', 'art_mask')]),
                      (rotmsk, outputnode, [('out_file', 'rot_mask')])])
    return workflow
Esempio n. 17
0
def test_ROIsPlot2():
    """ the BET report capable test """
    import nibabel as nb
    import numpy as np

    im = nb.load(str(
        get_template('OASIS30ANTs', resolution=1, desc='4',
                     suffix='dseg', extensions=['.nii', '.nii.gz'])))
    lookup = np.zeros(5, dtype=int)
    lookup[1] = 1
    lookup[2] = 4
    lookup[3] = 2
    lookup[4] = 3
    newdata = lookup[np.round(im.get_data()).astype(int)]
    hdr = im.header.copy()
    hdr.set_data_dtype('int16')
    hdr['scl_slope'] = 1
    hdr['scl_inter'] = 0

    out_files = []
    for i in range(1, 5):
        seg = np.zeros_like(newdata, dtype='uint8')
        seg[(newdata > 0) & (newdata <= i)] = 1
        out_file = os.path.abspath('segments%02d.nii.gz' % i)
        nb.Nifti1Image(seg, im.affine, hdr).to_filename(out_file)
        out_files.append(out_file)
    roi_rpt = ROIsPlot(
        generate_report=True,
        in_file=str(
            get_template('OASIS30ANTs', resolution=1, desc=None, suffix='T1w')),
        in_mask=str(
            get_template('OASIS30ANTs', resolution=1, desc='brain', suffix='mask')),
        in_rois=out_files,
        colors=['gold', 'lightblue', 'b', 'g']
    )
    _smoke_test_report(roi_rpt, 'testROIsPlot2.svg')
Esempio n. 18
0
def spatial_normalization(name='SpatialNormalization', resolution=2):
    """Create a simplied workflow to perform fast spatial normalization."""
    from niworkflows.interfaces.registration import (RobustMNINormalizationRPT
                                                     as RobustMNINormalization)

    # Have the template id handy
    tpl_id = config.workflow.template_id

    # Define workflow interface
    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(niu.IdentityInterface(
        fields=['moving_image', 'moving_mask', 'modality']),
                        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(
        fields=['inverse_composite_transform', 'out_report']),
                         name='outputnode')

    # Spatial normalization
    norm = pe.Node(
        RobustMNINormalization(
            flavor=['testing', 'fast'][config.execution.debug],
            num_threads=config.nipype.omp_nthreads,
            float=config.execution.ants_float,
            template=tpl_id,
            template_resolution=resolution,
            generate_report=True,
        ),
        name='SpatialNormalization',
        # Request all MultiProc processes when ants_nthreads > n_procs
        num_threads=config.nipype.omp_nthreads,
        mem_gb=3)
    norm.inputs.reference_mask = str(
        get_template(tpl_id,
                     resolution=resolution,
                     desc='brain',
                     suffix='mask'))

    workflow.connect([
        (inputnode, norm, [('moving_image', 'moving_image'),
                           ('moving_mask', 'moving_mask'),
                           ('modality', 'reference')]),
        (norm, outputnode, [('inverse_composite_transform',
                             'inverse_composite_transform'),
                            ('out_report', 'out_report')]),
    ])
    return workflow
Esempio n. 19
0
    def _fetch_data(self):
        """Converts inputspec to files"""
        if (self.inputs.surface_target == "fsnative" or
                self.inputs.volume_target != "MNI152NLin2009cAsym"):
            # subject space is not support yet
            raise NotImplementedError

        annotation_files = sorted(glob(os.path.join(self.inputs.subjects_dir,
                                                    self.inputs.surface_target,
                                                    'label',
                                                    '*h.aparc.annot')))
        if not annotation_files:
            raise IOError("Freesurfer annotations for %s not found in %s" % (
                          self.inputs.surface_target, self.inputs.subjects_dir))

        label_file = str(get_template(
            'MNI152NLin2009cAsym', resolution=2, desc='DKT31', suffix='dseg'))
        return annotation_files, label_file
Esempio n. 20
0
    def _fetch_data(self):
        """Converts inputspec to files"""
        if (self.inputs.surface_target == "fsnative"
                or self.inputs.volume_target != "MNI152NLin2009cAsym"):
            # subject space is not support yet
            raise NotImplementedError

        annotation_files = sorted(
            glob(
                os.path.join(self.inputs.subjects_dir,
                             self.inputs.surface_target, 'label',
                             '*h.aparc.annot')))
        if not annotation_files:
            raise IOError(
                "Freesurfer annotations for %s not found in %s" %
                (self.inputs.surface_target, self.inputs.subjects_dir))

        label_file = str(
            get_template('MNI152NLin2009cAsym',
                         resolution=2,
                         desc='DKT31',
                         suffix='dseg'))
        return annotation_files, label_file
def prep_for_fmriprep(bidsdir, rawdir, substr):
    #make subject dir, anat and func
    subid = substr.replace('-', '_').replace('_', '')
    anatdir = bidsdir + '/sub-' + subid + '/anat/'
    funcdir = bidsdir + '/sub-' + subid + '/func/'
    os.makedirs(anatdir, exist_ok=True)
    os.makedirs(funcdir, exist_ok=True)

    # get t1brain and MNI template
    t1brain = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/reg/highres.nii.gz' % substr
    template = str(
        get_template('MNI152NLin2009cAsym',
                     resolution=2,
                     desc='brain',
                     suffix='T1w',
                     extension=['.nii', '.nii.gz']))

    ## registered T1w to template for fmriprep standard
    ### this reg files may not be used

    tranformfile = tempfile.mkdtemp()
    reg = Registration()
    reg.inputs.fixed_image = template
    reg.inputs.moving_image = t1brain
    reg.inputs.output_transform_prefix = tranformfile + '/t12mni_'
    reg.inputs.transforms = ['Affine', 'SyN']
    reg.inputs.transform_parameters = [(2.0, ), (0.25, 3.0, 0.0)]
    reg.inputs.number_of_iterations = [[1500, 200], [100, 50, 30]]
    reg.inputs.dimension = 3
    reg.inputs.num_threads = 3
    reg.inputs.write_composite_transform = True
    reg.inputs.collapse_output_transforms = False
    reg.inputs.initialize_transforms_per_stage = True
    reg.inputs.metric = ['Mattes'] * 2
    reg.inputs.metric_weight = [
        1
    ] * 2  # Default (value ignored currently by ANTs)
    reg.inputs.radius_or_number_of_bins = [32] * 2
    reg.inputs.sampling_strategy = ['Random', None]
    reg.inputs.sampling_percentage = [0.05, None]
    reg.inputs.convergence_threshold = [1.e-8, 1.e-9]
    reg.inputs.convergence_window_size = [20] * 2
    reg.inputs.smoothing_sigmas = [[1, 0], [2, 1, 0]]
    reg.inputs.sigma_units = ['vox'] * 2
    reg.inputs.shrink_factors = [[2, 1], [3, 2, 1]]
    reg.inputs.use_estimate_learning_rate_once = [True, True]
    reg.inputs.use_histogram_matching = [True, True]  # This is the default
    #reg.inputs.output_warped_image = 'output_warped_image.nii.gz'
    reg.cmdline
    reg.run()

    ## copy transform file to fmriprep directory
    mni2twtransform = anatdir + '/sub-' + subid + '_from-MNI152NLin2009cAsym_to-T1w_mode-image_xfm.h5'
    t1w2mnitransform = anatdir + '/sub-' + subid + '_from-T1w_to-MNI152NLin2009cAsym_mode-image_xfm.h5'
    copyfile(tranformfile + '/t12mni_Composite.h5', t1w2mnitransform)
    copyfile(tranformfile + '/t12mni_InverseComposite.h5', mni2twtransform)

    ### warp the non-processed/filtered/smooth bold to fmriprep

    ### now functional

    boldmask = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/mask.nii.gz' % substr
    boldref = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI_SBREF.nii.gz' % substr
    boldprep = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.nii.gz' % substr

    reffile = tempfile.mkdtemp() + '/reffile.nii.gz'
    boldstd = reffile = tempfile.mkdtemp() + '/boldstd.nii.gz'
    maskstd = reffile = tempfile.mkdtemp() + '/maskstd.nii.gz'
    aw = fsl.ApplyWarp()
    aw.inputs.in_file = boldref
    aw.inputs.ref_file = template
    aw.inputs.field_file = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/reg/example_func2standard_warp.nii.gz' % substr
    aw.inputs.out_file = reffile
    aw.inputs.output_type = 'NIFTI_GZ'
    res = aw.run()

    aw1 = fsl.ApplyWarp()
    aw1.inputs.interp = 'spline'
    aw1.inputs.ref_file = template
    aw1.inputs.field_file = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/reg/example_func2standard_warp.nii.gz' % substr
    aw1.inputs.in_file = boldprep
    aw1.inputs.out_file = boldstd
    aw1.inputs.output_type = 'NIFTI_GZ'
    res1 = aw1.run()

    aw2 = fsl.ApplyWarp()
    aw2.inputs.in_file = boldmask
    aw2.inputs.ref_file = template
    aw2.inputs.field_file = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/reg/example_func2standard_warp.nii.gz' % substr
    aw2.inputs.out_file = maskstd
    aw2.inputs.output_type = 'NIFTI_GZ'
    res2 = aw2.run()

    tr = nb.load(boldprep).header.get_zooms()[-1]

    jsontis = {
        "RepetitionTime": np.float64(tr),
        "TaskName": 'rest',
        "SkullStripped": False,
    }

    jsmaks = {"mask": True}

    #newname
    preprocbold = funcdir + '/sub-' + subid + '_task-rest_space-MNI152NLin2009cAsym_desc-preproc_bold.nii.gz'
    preprocboldjson = funcdir + '/sub-' + subid + '_task-rest_space-MNI152NLin2009cAsym_desc-preproc_bold.json'
    preprocboldref = funcdir + '/sub-' + subid + '_task-rest_space-MNI152NLin2009cAsym_boldref.nii.gz'
    preprocmask = funcdir + '/sub-' + subid + '_task-rest_space-MNI152NLin2009cAsym_desc-brain_mask.nii.gz'
    preprocmaskjson = funcdir + '/sub-' + subid + '_task-rest_space-MNI152NLin2009cAsym_desc-brain_mask.json'

    copyfile(maskstd, preprocmask)
    copyfile(reffile, preprocboldref)
    copyfile(boldstd, preprocbold)
    writejson(jsontis, preprocboldjson)
    writejson(jsmaks, preprocmaskjson)

    # get wm and csf mask to extract mean signals for regressors
    ### first warp the anatomical to bold space
    wmask = rawdir + '/UKB_Pipeline/%s/T1/T1_fast/T1_brain_pve_2.nii.gz' % substr
    csfmask = rawdir + '/UKB_Pipeline/%s/T1/T1_fast/T1_brain_pve_0.nii.gz' % substr

    t2funcwmask = tempfile.mkdtemp() + '/wmask.nii.gz'
    t2funcwcsf = tempfile.mkdtemp() + '/csf.nii.gz'

    aw = fsl.preprocess.ApplyXFM()
    aw.inputs.in_file = wmask
    aw.inputs.reference = boldref
    aw.inputs.in_matrix_file = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/reg/highres2example_func.mat' % substr
    aw.inputs.out_file = t2funcwmask
    aw.inputs.apply_xfm = True
    aw.inputs.interp = 'nearestneighbour'
    aw.inputs.output_type = 'NIFTI_GZ'
    res = aw.run()

    aw2 = fsl.preprocess.ApplyXFM()
    aw2.inputs.in_file = csfmask
    aw2.inputs.reference = boldref
    aw2.inputs.in_matrix_file = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/reg/highres2example_func.mat' % substr
    aw2.inputs.out_file = t2funcwcsf
    aw2.inputs.apply_xfm = True
    aw2.inputs.interp = 'nearestneighbour'
    aw2.inputs.output_type = 'NIFTI_GZ'
    res2 = aw2.run()

    # binarized and extract signals
    wmbin = nb.load(t2funcwmask).get_fdata()
    wmbin[wmbin < 0.99999] = 0

    csfbin = nb.load(t2funcwcsf).get_fdata()
    csfbin[csfbin < 0.99999] = 0

    maskbin = nb.load(boldmask).get_fdata()

    bolddata = nb.load(boldprep).get_fdata()
    wm_mean = bolddata[wmbin > 0, :].mean(axis=0)
    csf_mean = bolddata[csfbin > 0, :].mean(axis=0)
    global_mean = bolddata[maskbin > 0, :].mean(axis=0)

    #### combine all the regressors

    mcfile = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/mc/prefiltered_func_data_mcf.par' % substr
    rsmdfile = rawdir + '/UKB_Pipeline/%s/fMRI_nosmooth/rfMRI.ica/mc/prefiltered_func_data_mcf_abs.rms' % substr
    motionfile = np.loadtxt(mcfile)

    rsmd = np.loadtxt(rsmdfile)
    motionparam = pd.DataFrame(
        motionfile,
        columns=['rot_x', 'rot_y', 'rot_z', 'trans_x', 'trans_y', 'trans_z'])

    otherparam = pd.DataFrame({
        'global_signal': global_mean,
        'white_matter': wm_mean,
        'csf': csf_mean,
        'rmsd': rsmd
    })

    regressors = pd.concat([motionparam, otherparam], axis=1)
    jsonreg = {'regressor': 'not'}
    regcsv = funcdir + '/sub-' + subid + '_task-rest_desc-confounds_timeseries.tsv'
    regjson = funcdir + '/sub-' + subid + '_task-rest_desc-confounds_timeseries.json'

    regressors.to_csv(regcsv, index=None, sep='\t')
    writejson(jsonreg, regjson)
Esempio n. 22
0
def init_rodent_brain_extraction_wf(
    ants_affine_init=False,
    factor=20,
    arc=0.12,
    step=4,
    grid=(0, 4, 4),
    debug=False,
    interim_checkpoints=True,
    mem_gb=3.0,
    mri_scheme="T2w",
    name="rodent_brain_extraction_wf",
    omp_nthreads=None,
    output_dir=None,
    template_id="Fischer344",
    template_specs=None,
    use_float=True,
):
    """
    Build an atlas-based brain extraction pipeline for rodent T1w and T2w MRI data.

    Parameters
    ----------
    ants_affine_init : :obj:`bool`, optional
        Set-up a pre-initialization step with ``antsAI`` to account for mis-oriented images.

    """
    inputnode = pe.Node(niu.IdentityInterface(fields=["in_files", "in_mask"]),
                        name="inputnode")
    outputnode = pe.Node(
        niu.IdentityInterface(
            fields=["out_corrected", "out_brain", "out_mask"]),
        name="outputnode",
    )

    template_specs = template_specs or {}
    if template_id == "WHS" and "resolution" not in template_specs:
        template_specs["resolution"] = 2

    # Find a suitable target template in TemplateFlow
    tpl_target_path = get_template(
        template_id,
        suffix=mri_scheme,
        **template_specs,
    )
    if not tpl_target_path:
        raise RuntimeError(
            f"An instance of template <tpl-{template_id}> with MR scheme '{mri_scheme}'"
            " could not be found.")

    tpl_brainmask_path = get_template(
        template_id,
        atlas=None,
        hemi=None,
        desc="brain",
        suffix="probseg",
        **template_specs,
    ) or get_template(
        template_id,
        atlas=None,
        hemi=None,
        desc="brain",
        suffix="mask",
        **template_specs,
    )

    tpl_regmask_path = get_template(
        template_id,
        atlas=None,
        desc="BrainCerebellumExtraction",
        suffix="mask",
        **template_specs,
    )

    denoise = pe.Node(DenoiseImage(dimension=3, copy_header=True),
                      name="denoise",
                      n_procs=omp_nthreads)

    # Resample template to a controlled, isotropic resolution
    res_tmpl = pe.Node(RegridToZooms(zooms=HIRES_ZOOMS, smooth=True),
                       name="res_tmpl")

    # Create Laplacian images
    lap_tmpl = pe.Node(ImageMath(operation="Laplacian", copy_header=True),
                       name="lap_tmpl")
    tmpl_sigma = pe.Node(niu.Function(function=_lap_sigma),
                         name="tmpl_sigma",
                         run_without_submitting=True)
    norm_lap_tmpl = pe.Node(niu.Function(function=_norm_lap),
                            name="norm_lap_tmpl")

    lap_target = pe.Node(ImageMath(operation="Laplacian", copy_header=True),
                         name="lap_target")
    target_sigma = pe.Node(niu.Function(function=_lap_sigma),
                           name="target_sigma",
                           run_without_submitting=True)
    norm_lap_target = pe.Node(niu.Function(function=_norm_lap),
                              name="norm_lap_target")

    # Set up initial spatial normalization
    ants_params = "testing" if debug else "precise"
    norm = pe.Node(
        Registration(from_file=pkgr_fn(
            "nirodents",
            f"data/artsBrainExtraction_{ants_params}_{mri_scheme}.json")),
        name="norm",
        n_procs=omp_nthreads,
        mem_gb=mem_gb,
    )
    norm.inputs.float = use_float

    # main workflow
    wf = pe.Workflow(name)

    # truncate target intensity for N4 correction
    clip_target = pe.Node(IntensityClip(p_min=15, p_max=99.9),
                          name="clip_target")

    # truncate template intensity to match target
    clip_tmpl = pe.Node(IntensityClip(p_min=5, p_max=98), name="clip_tmpl")
    clip_tmpl.inputs.in_file = _pop(tpl_target_path)

    # set INU bspline grid based on voxel size
    bspline_grid = pe.Node(niu.Function(function=_bspline_grid),
                           name="bspline_grid")

    # INU correction of the target image
    init_n4 = pe.Node(
        N4BiasFieldCorrection(
            dimension=3,
            save_bias=False,
            copy_header=True,
            n_iterations=[50] * (4 - debug),
            convergence_threshold=1e-7,
            shrink_factor=4,
            rescale_intensities=True,
        ),
        n_procs=omp_nthreads,
        name="init_n4",
    )
    clip_inu = pe.Node(IntensityClip(p_min=1, p_max=99.8), name="clip_inu")

    # Create a buffer interface as a cache for the actual inputs to registration
    buffernode = pe.Node(niu.IdentityInterface(fields=["hires_target"]),
                         name="buffernode")

    # Merge image nodes
    mrg_target = pe.Node(niu.Merge(2), name="mrg_target")
    mrg_tmpl = pe.Node(niu.Merge(2), name="mrg_tmpl")

    # fmt: off
    wf.connect([
        # Target image massaging
        (inputnode, denoise, [(("in_files", _pop), "input_image")]),
        (inputnode, bspline_grid, [(("in_files", _pop), "in_file")]),
        (bspline_grid, init_n4, [("out", "args")]),
        (denoise, clip_target, [("output_image", "in_file")]),
        (clip_target, init_n4, [("out_file", "input_image")]),
        (init_n4, clip_inu, [("output_image", "in_file")]),
        (clip_inu, target_sigma, [("out_file", "in_file")]),
        (clip_inu, buffernode, [("out_file", "hires_target")]),
        (buffernode, lap_target, [("hires_target", "op1")]),
        (target_sigma, lap_target, [("out", "op2")]),
        (lap_target, norm_lap_target, [("output_image", "in_file")]),
        (buffernode, mrg_target, [("hires_target", "in1")]),
        (norm_lap_target, mrg_target, [("out", "in2")]),
        # Template massaging
        (clip_tmpl, res_tmpl, [("out_file", "in_file")]),
        (res_tmpl, tmpl_sigma, [("out_file", "in_file")]),
        (res_tmpl, lap_tmpl, [("out_file", "op1")]),
        (tmpl_sigma, lap_tmpl, [("out", "op2")]),
        (lap_tmpl, norm_lap_tmpl, [("output_image", "in_file")]),
        (res_tmpl, mrg_tmpl, [("out_file", "in1")]),
        (norm_lap_tmpl, mrg_tmpl, [("out", "in2")]),
        # Setup inputs to spatial normalization
        (mrg_target, norm, [("out", "moving_image")]),
        (mrg_tmpl, norm, [("out", "fixed_image")]),
    ])
    # fmt: on

    # Graft a template registration-mask if present
    if tpl_regmask_path:
        hires_mask = pe.Node(
            ApplyTransforms(
                input_image=_pop(tpl_regmask_path),
                transforms="identity",
                interpolation="Gaussian",
                float=True,
            ),
            name="hires_mask",
            mem_gb=1,
        )

        # fmt: off
        wf.connect([
            (res_tmpl, hires_mask, [("out_file", "reference_image")]),
            (hires_mask, norm, [("output_image", "fixed_image_masks")]),
        ])
        # fmt: on

    # Finally project brain mask and refine INU correction
    map_brainmask = pe.Node(
        ApplyTransforms(interpolation="Gaussian", float=True),
        name="map_brainmask",
        mem_gb=1,
    )
    map_brainmask.inputs.input_image = str(tpl_brainmask_path)

    thr_brainmask = pe.Node(Binarize(thresh_low=0.50), name="thr_brainmask")

    final_n4 = pe.Node(
        N4BiasFieldCorrection(
            dimension=3,
            save_bias=True,
            copy_header=True,
            n_iterations=[50] * 4,
            convergence_threshold=1e-7,
            rescale_intensities=True,
            shrink_factor=4,
        ),
        n_procs=omp_nthreads,
        name="final_n4",
    )
    final_mask = pe.Node(ApplyMask(), name="final_mask")

    # fmt: off
    wf.connect([
        (inputnode, map_brainmask, [(("in_files", _pop), "reference_image")]),
        (bspline_grid, final_n4, [("out", "args")]),
        (denoise, final_n4, [("output_image", "input_image")]),
        # Project template's brainmask into subject space
        (norm, map_brainmask, [("reverse_transforms", "transforms"),
                               ("reverse_invert_flags",
                                "invert_transform_flags")]),
        (map_brainmask, thr_brainmask, [("output_image", "in_file")]),
        # take a second pass of N4
        (map_brainmask, final_n4, [("output_image", "mask_image")]),
        (final_n4, final_mask, [("output_image", "in_file")]),
        (thr_brainmask, final_mask, [("out_mask", "in_mask")]),
        (final_n4, outputnode, [("output_image", "out_corrected")]),
        (thr_brainmask, outputnode, [("out_mask", "out_mask")]),
        (final_mask, outputnode, [("out_file", "out_brain")]),
    ])
    # fmt: on

    if interim_checkpoints:
        final_apply = pe.Node(
            ApplyTransforms(interpolation="BSpline", float=True),
            name="final_apply",
            mem_gb=1,
        )
        final_report = pe.Node(
            SimpleBeforeAfter(after_label="target",
                              before_label=f"tpl-{template_id}"),
            name="final_report",
        )
        # fmt: off
        wf.connect([
            (inputnode, final_apply, [(("in_files", _pop), "reference_image")
                                      ]),
            (res_tmpl, final_apply, [("out_file", "input_image")]),
            (norm, final_apply, [("reverse_transforms", "transforms"),
                                 ("reverse_invert_flags",
                                  "invert_transform_flags")]),
            (final_apply, final_report, [("output_image", "before")]),
            (outputnode, final_report, [("out_corrected", "after"),
                                        ("out_mask", "wm_seg")]),
        ])
        # fmt: on

    if ants_affine_init:
        # Initialize transforms with antsAI
        lowres_tmpl = pe.Node(RegridToZooms(zooms=LOWRES_ZOOMS, smooth=True),
                              name="lowres_tmpl")
        lowres_trgt = pe.Node(RegridToZooms(zooms=LOWRES_ZOOMS, smooth=True),
                              name="lowres_trgt")

        init_aff = pe.Node(
            AI(
                convergence=(100, 1e-6, 10),
                metric=("Mattes", 32, "Random", 0.25),
                principal_axes=False,
                search_factor=(factor, arc),
                search_grid=(step, grid),
                transform=("Affine", 0.1),
                verbose=True,
            ),
            name="init_aff",
            n_procs=omp_nthreads,
        )
        # fmt: off
        wf.connect([
            (clip_inu, lowres_trgt, [("out_file", "in_file")]),
            (lowres_trgt, init_aff, [("out_file", "moving_image")]),
            (clip_tmpl, lowres_tmpl, [("out_file", "in_file")]),
            (lowres_tmpl, init_aff, [("out_file", "fixed_image")]),
            (init_aff, norm, [("output_transform", "initial_moving_transform")
                              ]),
        ])
        # fmt: on

        if tpl_regmask_path:
            lowres_mask = pe.Node(
                ApplyTransforms(
                    input_image=_pop(tpl_regmask_path),
                    transforms="identity",
                    interpolation="MultiLabel",
                ),
                name="lowres_mask",
                mem_gb=1,
            )
            # fmt: off
            wf.connect([
                (lowres_tmpl, lowres_mask, [("out_file", "reference_image")]),
                (lowres_mask, init_aff, [("output_image", "fixed_image_mask")
                                         ]),
            ])
            # fmt: on

        if interim_checkpoints:
            init_apply = pe.Node(
                ApplyTransforms(interpolation="BSpline",
                                invert_transform_flags=[True]),
                name="init_apply",
                mem_gb=1,
            )
            init_mask = pe.Node(
                ApplyTransforms(interpolation="Gaussian",
                                invert_transform_flags=[True]),
                name="init_mask",
                mem_gb=1,
            )
            init_mask.inputs.input_image = str(tpl_brainmask_path)
            init_report = pe.Node(
                SimpleBeforeAfter(
                    out_report="init_report.svg",
                    before_label="target",
                    after_label="template",
                ),
                name="init_report",
            )
            # fmt: off
            wf.connect([
                (lowres_trgt, init_apply, [("out_file", "reference_image")]),
                (lowres_tmpl, init_apply, [("out_file", "input_image")]),
                (init_aff, init_apply, [("output_transform", "transforms")]),
                (lowres_trgt, init_report, [("out_file", "before")]),
                (init_apply, init_report, [("output_image", "after")]),
                (lowres_trgt, init_mask, [("out_file", "reference_image")]),
                (init_aff, init_mask, [("output_transform", "transforms")]),
                (init_mask, init_report, [("output_image", "wm_seg")]),
            ])
            # fmt: on
    else:
        norm.inputs.initial_moving_transform_com = 1

    if output_dir:
        ds_final_inu = pe.Node(DerivativesDataSink(
            base_directory=str(output_dir),
            desc="preproc",
            compress=True,
        ),
                               name="ds_final_inu",
                               run_without_submitting=True)
        ds_final_msk = pe.Node(DerivativesDataSink(
            base_directory=str(output_dir),
            desc="brain",
            suffix="mask",
            compress=True,
        ),
                               name="ds_final_msk",
                               run_without_submitting=True)

        # fmt: off
        wf.connect([
            (inputnode, ds_final_inu, [("in_files", "source_file")]),
            (inputnode, ds_final_msk, [("in_files", "source_file")]),
            (outputnode, ds_final_inu, [("out_corrected", "in_file")]),
            (outputnode, ds_final_msk, [("out_mask", "in_file")]),
        ])
        # fmt: on

        if interim_checkpoints:
            ds_report = pe.Node(DerivativesDataSink(
                base_directory=str(output_dir),
                desc="brain",
                suffix="mask",
                datatype="figures"),
                                name="ds_report",
                                run_without_submitting=True)
            # fmt: off
            wf.connect([
                (inputnode, ds_report, [("in_files", "source_file")]),
                (final_report, ds_report, [("out_report", "in_file")]),
            ])
            # fmt: on

        if ants_affine_init and interim_checkpoints:
            ds_report_init = pe.Node(DerivativesDataSink(
                base_directory=str(output_dir),
                desc="init",
                suffix="mask",
                datatype="figures"),
                                     name="ds_report_init",
                                     run_without_submitting=True)
            # fmt: off
            wf.connect([
                (inputnode, ds_report_init, [("in_files", "source_file")]),
                (init_report, ds_report_init, [("out_report", "in_file")]),
            ])
            # fmt: on

    return wf
Esempio n. 23
0
def epi_mni_align(name='SpatialNormalization'):
    """
    Estimate the transform that maps the EPI space into MNI152NLin2009cAsym.

    The input epi_mean is the averaged and brain-masked EPI timeseries

    Returns the EPI mean resampled in MNI space (for checking out registration) and
    the associated "lobe" parcellation in EPI space.

    .. workflow::

        from mriqc.workflows.functional import epi_mni_align
        from mriqc.testing import mock_config
        with mock_config():
            wf = epi_mni_align()

    """
    from nipype.interfaces.ants import ApplyTransforms, N4BiasFieldCorrection
    from templateflow.api import get as get_template
    from niworkflows.interfaces.registration import (RobustMNINormalizationRPT
                                                     as RobustMNINormalization)

    # Get settings
    testing = config.execution.debug
    n_procs = config.nipype.nprocs
    ants_nthreads = config.nipype.omp_nthreads

    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(niu.IdentityInterface(fields=['epi_mean', 'epi_mask']),
                        name='inputnode')
    outputnode = pe.Node(
        niu.IdentityInterface(fields=['epi_mni', 'epi_parc', 'report']),
        name='outputnode')

    n4itk = pe.Node(N4BiasFieldCorrection(dimension=3, copy_header=True),
                    name='SharpenEPI')

    norm = pe.Node(RobustMNINormalization(
        explicit_masking=False,
        flavor='testing' if testing else 'precise',
        float=config.execution.ants_float,
        generate_report=True,
        moving='boldref',
        num_threads=ants_nthreads,
        reference='boldref',
        reference_image=str(
            get_template('MNI152NLin2009cAsym', resolution=2,
                         suffix='boldref')),
        reference_mask=str(
            get_template('MNI152NLin2009cAsym',
                         resolution=2,
                         desc='brain',
                         suffix='mask')),
        template='MNI152NLin2009cAsym',
        template_resolution=2,
    ),
                   name='EPI2MNI',
                   num_threads=n_procs,
                   mem_gb=3)

    # Warp segmentation into EPI space
    invt = pe.Node(ApplyTransforms(float=True,
                                   input_image=str(
                                       get_template('MNI152NLin2009cAsym',
                                                    resolution=1,
                                                    desc='carpet',
                                                    suffix='dseg')),
                                   dimension=3,
                                   default_value=0,
                                   interpolation='MultiLabel'),
                   name='ResampleSegmentation')

    workflow.connect([
        (inputnode, invt, [('epi_mean', 'reference_image')]),
        (inputnode, n4itk, [('epi_mean', 'input_image')]),
        (inputnode, norm, [('epi_mask', 'moving_mask')]),
        (n4itk, norm, [('output_image', 'moving_image')]),
        (norm, invt, [('inverse_composite_transform', 'transforms')]),
        (invt, outputnode, [('output_image', 'epi_parc')]),
        (norm, outputnode, [('warped_image', 'epi_mni'),
                            ('out_report', 'report')]),
    ])
    return workflow
Esempio n. 24
0
def init_cbfqc_compt_wf(mem_gb,
                        asl_file,
                        metadata,
                        omp_nthreads,
                        name='cbfqc_compt_wf'):
    """
    Create a workflow for :abbr:`cbfqc( compute cbf)`.

    Workflow Graph
        .. workflow::
            :graph2use: orig
            :simple_form: yes

            from aslprep.workflows.asl.cbf import init_cbfqc_compt_wf
            wf = init_cbfqc_compt_wf(mem_gb=0.1)

    Parameters
    ----------
    metadata : :obj:`dict`
        BIDS metadata for asl file
    name : :obj:`str`
        Name of workflow (default: ``cbfqc_compt_wf'``)

    Inputs
    ------
    *cbf
        all cbf 
    asl_mask
        asl mask NIFTI file 
    t1w_tpms
        t1w probability maps 
    t1_asl_xform
        t1w to asl transfromation file 

    Outputs
    -------
    qc_file
       qc measures in tsv

    """

    workflow = Workflow(name=name)
    workflow.__desc__ = """\
The following quality control (qc) measures was estimated: framewise displacement and relative
root mean square dice index. Other qc meaure include dice and jaccard indices, cross-correlation
and coverage that estimate the coregistration quality of  ASL and T1W images and  normalization
quality of ASL to template. Quality evaluation index (QEI) was also computed for CBF [@cbfqc].
The  QEI is  automated for objective quality evaluation of CBF maps and measured the CBF quality
based on structural similarity,spatial variability and the percentatge  of voxels with  negtaive
CBF within Grey matter
"""
    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'meancbf', 'avgscore', 'scrub', 'basil', 'asl_mask', 't1w_tpms',
        'confmat', 'asl_mask_std', 't1_asl_xform', 'pv', 't1w_mask'
    ]),
                        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(fields=['qc_file']),
                         name='outputnode')

    def _pick_csf(files):
        return files[-1]

    def _pick_gm(files):
        return files[0]

    def _pick_wm(files):
        return files[1]

    csf_tfm = pe.Node(ApplyTransforms(interpolation='NearestNeighbor',
                                      float=True),
                      name='csf_tfm',
                      mem_gb=0.1)
    wm_tfm = pe.Node(ApplyTransforms(interpolation='NearestNeighbor',
                                     float=True),
                     name='wm_tfm',
                     mem_gb=0.1)
    gm_tfm = pe.Node(ApplyTransforms(interpolation='NearestNeighbor',
                                     float=True),
                     name='gm_tfm',
                     mem_gb=0.1)

    mask_tfm = pe.Node(ApplyTransforms(interpolation='NearestNeighbor',
                                       float=True),
                       name='masktonative',
                       mem_gb=0.1)

    from templateflow.api import get as get_template
    brain_mask = str(
        get_template('MNI152NLin2009cAsym',
                     resolution=2,
                     desc='brain',
                     suffix='mask'))

    from nipype.interfaces.afni import Resample
    resample = pe.Node(Resample(in_file=brain_mask, outputtype='NIFTI_GZ'),
                       name='resample',
                       mem_gb=0.1)

    qccompute = pe.Node(qccbf(in_file=asl_file),
                        name='qccompute',
                        run_without_submitting=True,
                        mem_gb=0.2)

    workflow.connect([
        (inputnode, csf_tfm, [('asl_mask', 'reference_image'),
                              ('t1_asl_xform', 'transforms')]),
        (inputnode, csf_tfm, [(('t1w_tpms', _pick_csf), 'input_image')]),
        (inputnode, wm_tfm, [('asl_mask', 'reference_image'),
                             ('t1_asl_xform', 'transforms')]),
        (inputnode, wm_tfm, [(('t1w_tpms', _pick_wm), 'input_image')]),
        (inputnode, gm_tfm, [('asl_mask', 'reference_image'),
                             ('t1_asl_xform', 'transforms')]),
        (inputnode, gm_tfm, [(('t1w_tpms', _pick_gm), 'input_image')]),
        (inputnode, mask_tfm, [('asl_mask', 'reference_image'),
                               ('t1_asl_xform', 'transforms'),
                               ('t1w_mask', 'input_image')]),
        (mask_tfm, qccompute, [('output_image', 'in_t1mask')]),
        (inputnode, qccompute, [('asl_mask', 'in_aslmask'),
                                ('confmat', 'in_confmat')]),
        (inputnode, qccompute, [(('asl_mask_std', _pick_csf), 'in_aslmaskstd')
                                ]),
        (inputnode, resample, [(('asl_mask_std', _pick_csf), 'master')]),
        (resample, qccompute, [('out_file', 'in_templatemask')]),
        (gm_tfm, qccompute, [('output_image', 'in_greyM')]),
        (wm_tfm, qccompute, [('output_image', 'in_whiteM')]),
        (csf_tfm, qccompute, [('output_image', 'in_csf')]),
        (inputnode, qccompute, [('scrub', 'in_scrub'),
                                ('meancbf', 'in_meancbf'),
                                ('avgscore', 'in_avgscore'),
                                ('basil', 'in_basil'), ('pv', 'in_pvc')]),
        (qccompute, outputnode, [('qc_file', 'qc_file')]),
    ])
    return workflow
Esempio n. 25
0
def anat_qc_workflow(name="anatMRIQC"):
    """
    One-subject-one-session-one-run pipeline to extract the NR-IQMs from
    anatomical images

    .. workflow::

        import os.path as op
        from mriqc.workflows.anatomical import anat_qc_workflow
        from mriqc.testing import mock_config
        with mock_config():
            wf = anat_qc_workflow()

    """

    dataset = config.workflow.inputs.get(
        "T1w", []) + config.workflow.inputs.get("T2w", [])

    message = BUILDING_WORKFLOW.format(
        detail=(f"for {len(dataset)} NIfTI files." if len(dataset) > 2 else
                f"({' and '.join(('<%s>' % v for v in dataset))})."), )
    config.loggers.workflow.info(message)

    # Initialize workflow
    workflow = pe.Workflow(name=name)

    # Define workflow, inputs and outputs
    # 0. Get data
    inputnode = pe.Node(niu.IdentityInterface(fields=["in_file"]),
                        name="inputnode")
    inputnode.iterables = [("in_file", dataset)]

    outputnode = pe.Node(niu.IdentityInterface(fields=["out_json"]),
                         name="outputnode")

    # 1. Reorient anatomical image
    to_ras = pe.Node(ConformImage(check_dtype=False), name="conform")
    # 2. species specific skull-stripping
    if config.workflow.species.lower() == "human":
        skull_stripping = synthstrip_wf(
            omp_nthreads=config.nipype.omp_nthreads)
        ss_bias_field = "outputnode.bias_image"
    else:
        from nirodents.workflows.brainextraction import init_rodent_brain_extraction_wf

        skull_stripping = init_rodent_brain_extraction_wf(
            template_id=config.workflow.template_id)
        ss_bias_field = "final_n4.bias_image"
    # 3. Head mask
    hmsk = headmsk_wf()
    # 4. Spatial Normalization, using ANTs
    norm = spatial_normalization()
    # 5. Air mask (with and without artifacts)
    amw = airmsk_wf()
    # 6. Brain tissue segmentation
    if config.workflow.species.lower() == "human":
        segment = pe.Node(
            fsl.FAST(segments=True, out_basename="segment"),
            name="segmentation",
            mem_gb=5,
        )
        seg_in_file = "in_files"
        dseg_out = "tissue_class_map"
        pve_out = "partial_volume_files"
    else:
        from niworkflows.interfaces.fixes import ApplyTransforms

        tpms = [
            str(tpm) for tpm in get_template(config.workflow.template_id,
                                             label=["CSF", "GM", "WM"],
                                             suffix="probseg")
        ]

        xfm_tpms = pe.MapNode(
            ApplyTransforms(
                dimension=3,
                default_value=0,
                float=True,
                interpolation="Gaussian",
                output_image="prior.nii.gz",
            ),
            iterfield=["input_image"],
            name="xfm_tpms",
        )
        xfm_tpms.inputs.input_image = tpms

        format_tpm_names = pe.Node(
            niu.Function(
                input_names=["in_files"],
                output_names=["file_format"],
                function=_format_tpm_names,
                execution={
                    "keep_inputs": True,
                    "remove_unnecessary_outputs": False
                },
            ),
            name="format_tpm_names",
        )

        segment = pe.Node(
            ants.Atropos(
                initialization="PriorProbabilityImages",
                number_of_tissue_classes=3,
                prior_weighting=0.1,
                mrf_radius=[1, 1, 1],
                mrf_smoothing_factor=0.01,
                save_posteriors=True,
                out_classified_image_name="segment.nii.gz",
                output_posteriors_name_template="segment_%02d.nii.gz",
            ),
            name="segmentation",
            mem_gb=5,
        )
        seg_in_file = "intensity_images"
        dseg_out = "classified_image"
        pve_out = "posteriors"

    # 7. Compute IQMs
    iqmswf = compute_iqms()
    # Reports
    repwf = individual_reports()

    # Connect all nodes
    # fmt: off
    workflow.connect([
        (inputnode, to_ras, [("in_file", "in_file")]),
        (inputnode, iqmswf, [("in_file", "inputnode.in_file")]),
        (inputnode, norm, [(("in_file", _get_mod), "inputnode.modality")]),
        (to_ras, skull_stripping, [("out_file", "inputnode.in_files")]),
        (skull_stripping, segment, [("outputnode.out_brain", seg_in_file)]),
        (skull_stripping, hmsk, [("outputnode.out_corrected",
                                  "inputnode.in_file")]),
        (segment, hmsk, [(dseg_out, "inputnode.in_segm")]),
        (skull_stripping, norm,
         [("outputnode.out_corrected", "inputnode.moving_image"),
          ("outputnode.out_mask", "inputnode.moving_mask")]),
        (norm, amw, [("outputnode.inverse_composite_transform",
                      "inputnode.inverse_composite_transform")]),
        (norm, iqmswf, [("outputnode.inverse_composite_transform",
                         "inputnode.inverse_composite_transform")]),
        (norm, repwf, ([("outputnode.out_report", "inputnode.mni_report")])),
        (to_ras, amw, [("out_file", "inputnode.in_file")]),
        (skull_stripping, amw, [("outputnode.out_mask", "inputnode.in_mask")]),
        (hmsk, amw, [("outputnode.out_file", "inputnode.head_mask")]),
        (to_ras, iqmswf, [("out_file", "inputnode.in_ras")]),
        (skull_stripping, iqmswf,
         [("outputnode.out_corrected", "inputnode.inu_corrected"),
          (ss_bias_field, "inputnode.in_inu"),
          ("outputnode.out_mask", "inputnode.brainmask")]),
        (amw, iqmswf, [("outputnode.air_mask", "inputnode.airmask"),
                       ("outputnode.hat_mask", "inputnode.hatmask"),
                       ("outputnode.art_mask", "inputnode.artmask"),
                       ("outputnode.rot_mask", "inputnode.rotmask")]),
        (segment, iqmswf, [(dseg_out, "inputnode.segmentation"),
                           (pve_out, "inputnode.pvms")]),
        (hmsk, iqmswf, [("outputnode.out_file", "inputnode.headmask")]),
        (to_ras, repwf, [("out_file", "inputnode.in_ras")]),
        (skull_stripping, repwf,
         [("outputnode.out_corrected", "inputnode.inu_corrected"),
          ("outputnode.out_mask", "inputnode.brainmask")]),
        (hmsk, repwf, [("outputnode.out_file", "inputnode.headmask")]),
        (amw, repwf, [("outputnode.air_mask", "inputnode.airmask"),
                      ("outputnode.art_mask", "inputnode.artmask"),
                      ("outputnode.rot_mask", "inputnode.rotmask")]),
        (segment, repwf, [(dseg_out, "inputnode.segmentation")]),
        (iqmswf, repwf, [("outputnode.noisefit", "inputnode.noisefit")]),
        (iqmswf, repwf, [("outputnode.out_file", "inputnode.in_iqms")]),
        (iqmswf, outputnode, [("outputnode.out_file", "out_json")]),
    ])

    if config.workflow.species.lower() == 'human':
        workflow.connect([
            (inputnode, segment, [(("in_file", _get_imgtype), "img_type")]),
        ])
    else:
        workflow.connect([
            (skull_stripping, xfm_tpms, [("outputnode.out_brain",
                                          "reference_image")]),
            (norm, xfm_tpms, [("outputnode.inverse_composite_transform",
                               "transforms")]),
            (xfm_tpms, format_tpm_names, [('output_image', 'in_files')]),
            (format_tpm_names, segment, [(('file_format', _pop), 'prior_image')
                                         ]),
            (skull_stripping, segment, [("outputnode.out_mask", "mask_image")
                                        ]),
        ])
    # fmt: on

    # Upload metrics
    if not config.execution.no_sub:
        from ..interfaces.webapi import UploadIQMs

        upldwf = pe.Node(UploadIQMs(), name="UploadMetrics")
        upldwf.inputs.url = config.execution.webapi_url
        upldwf.inputs.strict = config.execution.upload_strict
        if config.execution.webapi_port:
            upldwf.inputs.port = config.execution.webapi_port

        # fmt: off
        workflow.connect([
            (iqmswf, upldwf, [("outputnode.out_file", "in_iqms")]),
            (upldwf, repwf, [("api_id", "inputnode.api_id")]),
        ])
        # fmt: on

    return workflow
Esempio n. 26
0
def reference_mask():
    return str(
        get_template('MNI152Lin', resolution=2, desc='brain', suffix='mask'))
Esempio n. 27
0
def init_enhance_and_skullstrip_bold_wf(name='enhance_and_skullstrip_bold_wf',
                                        pre_mask=False,
                                        omp_nthreads=1):
    """
    This workflow takes in a :abbr:`BOLD (blood-oxygen level-dependant)`
    :abbr:`fMRI (functional MRI)` average/summary (e.g., a reference image
    averaging non-steady-state timepoints), and sharpens the histogram
    with the application of the N4 algorithm for removing the
    :abbr:`INU (intensity non-uniformity)` bias field and calculates a signal
    mask.

    Steps of this workflow are:

      1. Calculate a tentative mask by registering (9-parameters) to *fMRIPrep*'s
         :abbr:`EPI (echo-planar imaging)` -*boldref* template, which
         is in MNI space.
         The tentative mask is obtained by resampling the MNI template's
         brainmask into *boldref*-space.
      2. Binary dilation of the tentative mask with a sphere of 3mm diameter.
      3. Run ANTs' ``N4BiasFieldCorrection`` on the input
         :abbr:`BOLD (blood-oxygen level-dependant)` average, using the
         mask generated in 1) instead of the internal Otsu thresholding.
      4. Calculate a loose mask using FSL's ``bet``, with one mathematical morphology
         dilation of one iteration and a sphere of 6mm as structuring element.
      5. Mask the :abbr:`INU (intensity non-uniformity)`-corrected image
         with the latest mask calculated in 3), then use AFNI's ``3dUnifize``
         to *standardize* the T2* contrast distribution.
      6. Calculate a mask using AFNI's ``3dAutomask`` after the contrast
         enhancement of 4).
      7. Calculate a final mask as the intersection of 4) and 6).
      8. Apply final mask on the enhanced reference.

    Step 1 can be skipped if the ``pre_mask`` argument is set to ``True`` and
    a tentative mask is passed in to the workflow throught the ``pre_mask``
    Nipype input.


    .. workflow ::
        :graph2use: orig
        :simple_form: yes

        from niworkflows.func.util import init_enhance_and_skullstrip_bold_wf
        wf = init_enhance_and_skullstrip_bold_wf(omp_nthreads=1)

    **Parameters**
        name : str
            Name of workflow (default: ``enhance_and_skullstrip_bold_wf``)
        pre_mask : bool
            Indicates whether the ``pre_mask`` input will be set (and thus, step 1
            should be skipped).
        omp_nthreads : int
            number of threads available to parallel nodes

    **Inputs**

        in_file
            BOLD image (single volume)
        pre_mask : bool
            A tentative brain mask to initialize the workflow (requires ``pre_mask``
            parameter set ``True``).


    **Outputs**

        bias_corrected_file
            the ``in_file`` after `N4BiasFieldCorrection`_
        skull_stripped_file
            the ``bias_corrected_file`` after skull-stripping
        mask_file
            mask of the skull-stripped input file
        out_report
            reportlet for the skull-stripping

    .. _N4BiasFieldCorrection: https://hdl.handle.net/10380/3053
    """
    workflow = Workflow(name=name)
    inputnode = pe.Node(niu.IdentityInterface(fields=['in_file', 'pre_mask']),
                        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(
        fields=['mask_file', 'skull_stripped_file', 'bias_corrected_file']),
                         name='outputnode')

    # Dilate pre_mask
    pre_dilate = pe.Node(fsl.DilateImage(operation='max',
                                         kernel_shape='sphere',
                                         kernel_size=3.0,
                                         internal_datatype='char'),
                         name='pre_mask_dilate')

    # Ensure mask's header matches reference's
    check_hdr = pe.Node(MatchHeader(),
                        name='check_hdr',
                        run_without_submitting=True)

    # Run N4 normally, force num_threads=1 for stability (images are small, no need for >1)
    n4_correct = pe.Node(ants.N4BiasFieldCorrection(
        dimension=3, copy_header=True, bspline_fitting_distance=200),
                         name='n4_correct',
                         n_procs=1)

    # Create a generous BET mask out of the bias-corrected EPI
    skullstrip_first_pass = pe.Node(fsl.BET(frac=0.2, mask=True),
                                    name='skullstrip_first_pass')
    bet_dilate = pe.Node(fsl.DilateImage(operation='max',
                                         kernel_shape='sphere',
                                         kernel_size=6.0,
                                         internal_datatype='char'),
                         name='skullstrip_first_dilate')
    bet_mask = pe.Node(fsl.ApplyMask(), name='skullstrip_first_mask')

    # Use AFNI's unifize for T2 constrast & fix header
    unifize = pe.Node(
        afni.Unifize(
            t2=True,
            outputtype='NIFTI_GZ',
            # Default -clfrac is 0.1, 0.4 was too conservative
            # -rbt because I'm a Jedi AFNI Master (see 3dUnifize's documentation)
            args='-clfrac 0.2 -rbt 18.3 65.0 90.0',
            out_file="uni.nii.gz"),
        name='unifize')
    fixhdr_unifize = pe.Node(CopyXForm(), name='fixhdr_unifize', mem_gb=0.1)

    # Run ANFI's 3dAutomask to extract a refined brain mask
    skullstrip_second_pass = pe.Node(afni.Automask(dilate=1,
                                                   outputtype='NIFTI_GZ'),
                                     name='skullstrip_second_pass')
    fixhdr_skullstrip2 = pe.Node(CopyXForm(),
                                 name='fixhdr_skullstrip2',
                                 mem_gb=0.1)

    # Take intersection of both masks
    combine_masks = pe.Node(fsl.BinaryMaths(operation='mul'),
                            name='combine_masks')

    # Compute masked brain
    apply_mask = pe.Node(fsl.ApplyMask(), name='apply_mask')

    if not pre_mask:
        bold_template = get_template('MNI152NLin2009cAsym',
                                     resolution=2,
                                     desc='fMRIPrep',
                                     suffix='boldref')
        brain_mask = get_template('MNI152NLin2009cAsym',
                                  resolution=2,
                                  desc='brain',
                                  suffix='mask')

        # Initialize transforms with antsAI
        init_aff = pe.Node(AI(fixed_image=str(bold_template),
                              fixed_image_mask=str(brain_mask),
                              metric=('Mattes', 32, 'Regular', 0.2),
                              transform=('Affine', 0.1),
                              search_factor=(20, 0.12),
                              principal_axes=False,
                              convergence=(10, 1e-6, 10),
                              verbose=True),
                           name='init_aff',
                           n_procs=omp_nthreads)

        # Registration().version may be None
        if parseversion(Registration().version or '0.0.0') > Version('2.2.0'):
            init_aff.inputs.search_grid = (40, (0, 40, 40))

        # Set up spatial normalization
        norm = pe.Node(Registration(from_file=pkgr_fn(
            'fmriprep.data', 'epi_atlasbased_brainmask.json')),
                       name='norm',
                       n_procs=omp_nthreads)
        norm.inputs.fixed_image = str(bold_template)
        map_brainmask = pe.Node(ApplyTransforms(interpolation='MultiLabel',
                                                float=True,
                                                input_image=str(brain_mask)),
                                name='map_brainmask')
        workflow.connect([
            (inputnode, init_aff, [('in_file', 'moving_image')]),
            (inputnode, map_brainmask, [('in_file', 'reference_image')]),
            (inputnode, norm, [('in_file', 'moving_image')]),
            (init_aff, norm, [('output_transform', 'initial_moving_transform')
                              ]),
            (norm, map_brainmask, [('reverse_invert_flags',
                                    'invert_transform_flags'),
                                   ('reverse_transforms', 'transforms')]),
            (map_brainmask, pre_dilate, [('output_image', 'in_file')]),
        ])
    else:
        workflow.connect([
            (inputnode, pre_dilate, [('pre_mask', 'in_file')]),
        ])

    workflow.connect([
        (inputnode, check_hdr, [('in_file', 'reference')]),
        (pre_dilate, check_hdr, [('out_file', 'in_file')]),
        (check_hdr, n4_correct, [('out_file', 'mask_image')]),
        (inputnode, n4_correct, [('in_file', 'input_image')]),
        (inputnode, fixhdr_unifize, [('in_file', 'hdr_file')]),
        (inputnode, fixhdr_skullstrip2, [('in_file', 'hdr_file')]),
        (n4_correct, skullstrip_first_pass, [('output_image', 'in_file')]),
        (skullstrip_first_pass, bet_dilate, [('mask_file', 'in_file')]),
        (bet_dilate, bet_mask, [('out_file', 'mask_file')]),
        (skullstrip_first_pass, bet_mask, [('out_file', 'in_file')]),
        (bet_mask, unifize, [('out_file', 'in_file')]),
        (unifize, fixhdr_unifize, [('out_file', 'in_file')]),
        (fixhdr_unifize, skullstrip_second_pass, [('out_file', 'in_file')]),
        (skullstrip_first_pass, combine_masks, [('mask_file', 'in_file')]),
        (skullstrip_second_pass, fixhdr_skullstrip2, [('out_file', 'in_file')
                                                      ]),
        (fixhdr_skullstrip2, combine_masks, [('out_file', 'operand_file')]),
        (fixhdr_unifize, apply_mask, [('out_file', 'in_file')]),
        (combine_masks, apply_mask, [('out_file', 'mask_file')]),
        (combine_masks, outputnode, [('out_file', 'mask_file')]),
        (apply_mask, outputnode, [('out_file', 'skull_stripped_file')]),
        (n4_correct, outputnode, [('output_image', 'bias_corrected_file')]),
    ])

    return workflow
Esempio n. 28
0
def reference_mask():
    return str(get_template('MNI152Lin', resolution=2, desc='brain', suffix='mask'))
Esempio n. 29
0
    def _get_ants_args(self):
        args = {
            "moving_image": self.inputs.moving_image,
            "num_threads": self.inputs.num_threads,
            "float": self.inputs.float,
            "terminal_output": "file",
            "write_composite_transform": True,
            "initial_moving_transform": self.inputs.initial_moving_transform,
        }
        """
        Moving image handling - The following truth table maps out the intended action
        sequence. Future refactoring may more directly encode this.

        moving_mask and lesion_mask are files
        True = file
        False = None

        | moving_mask | explicit_masking | lesion_mask | action
        |-------------|------------------|-------------|-------------------------------------------
        | True        | True             | True        | Update `moving_image` after applying
        |             |                  |             | mask.
        |             |                  |             | Set `moving_image_masks` applying
        |             |                  |             | `create_cfm` with `global_mask=True`.
        |-------------|------------------|-------------|-------------------------------------------
        | True        | True             | False       | Update `moving_image` after applying
        |             |                  |             | mask.
        |-------------|------------------|-------------|-------------------------------------------
        | True        | False            | True        | Set `moving_image_masks` applying
        |             |                  |             | `create_cfm` with `global_mask=False`
        |-------------|------------------|-------------|-------------------------------------------
        | True        | False            | False       | args['moving_image_masks'] = moving_mask
        |-------------|------------------|-------------|-------------------------------------------
        | False       | *                | True        | Set `moving_image_masks` applying
        |             |                  |             | `create_cfm` with `global_mask=True`
        |-------------|------------------|-------------|-------------------------------------------
        | False       | *                | False       | No action
        """
        # If a moving mask is provided...
        if isdefined(self.inputs.moving_mask):
            # If explicit masking is enabled...
            if self.inputs.explicit_masking:
                # Mask the moving image.
                # Do not use a moving mask during registration.
                args["moving_image"] = mask(
                    self.inputs.moving_image,
                    self.inputs.moving_mask,
                    "moving_masked.nii.gz",
                )

            # If explicit masking is disabled...
            else:
                # Use the moving mask during registration.
                # Do not mask the moving image.
                args["moving_image_masks"] = self.inputs.moving_mask

            # If a lesion mask is also provided...
            if isdefined(self.inputs.lesion_mask):
                # Create a cost function mask with the form:
                # [global mask - lesion mask] (if explicit masking is enabled)
                # [moving mask - lesion mask] (if explicit masking is disabled)
                # Use this as the moving mask.
                args["moving_image_masks"] = create_cfm(
                    self.inputs.moving_mask,
                    lesion_mask=self.inputs.lesion_mask,
                    global_mask=self.inputs.explicit_masking,
                )

        # If no moving mask is provided...
        # But a lesion mask *IS* provided...
        elif isdefined(self.inputs.lesion_mask):
            # Create a cost function mask with the form: [global mask - lesion mask]
            # Use this as the moving mask.
            args["moving_image_masks"] = create_cfm(
                self.inputs.moving_image,
                lesion_mask=self.inputs.lesion_mask,
                global_mask=True,
            )
        """
        Reference image handling - The following truth table maps out the intended action
        sequence. Future refactoring may more directly encode this.

        reference_mask and lesion_mask are files
        True = file
        False = None

        | reference_mask | explicit_masking | lesion_mask | action
        |----------------|------------------|-------------|----------------------------------------
        | True           | True             | True        | Update `fixed_image` after applying
        |                |                  |             | mask.
        |                |                  |             | Set `fixed_image_masks` applying
        |                |                  |             | `create_cfm` with `global_mask=True`.
        |----------------|------------------|-------------|----------------------------------------
        | True           | True             | False       | Update `fixed_image` after applying
        |                |                  |             | mask.
        |----------------|------------------|-------------|----------------------------------------
        | True           | False            | True        | Set `fixed_image_masks` applying
        |                |                  |             | `create_cfm` with `global_mask=False`
        |----------------|------------------|-------------|----------------------------------------
        | True           | False            | False       | args['fixed_image_masks'] = fixed_mask
        |----------------|------------------|-------------|----------------------------------------
        | False          | *                | True        | Set `fixed_image_masks` applying
        |                |                  |             | `create_cfm` with `global_mask=True`
        |----------------|------------------|-------------|----------------------------------------
        | False          | *                | False       | No action
        """
        # If a reference image is provided...
        if isdefined(self.inputs.reference_image):
            # Use the reference image as the fixed image.
            args["fixed_image"] = self.inputs.reference_image
            self._reference_image = self.inputs.reference_image

            # If a reference mask is provided...
            if isdefined(self.inputs.reference_mask):
                # If explicit masking is enabled...
                if self.inputs.explicit_masking:
                    # Mask the reference image.
                    # Do not use a fixed mask during registration.
                    args["fixed_image"] = mask(
                        self.inputs.reference_image,
                        self.inputs.reference_mask,
                        "fixed_masked.nii.gz",
                    )

                    # If a lesion mask is also provided...
                    if isdefined(self.inputs.lesion_mask):
                        # Create a cost function mask with the form: [global mask]
                        # Use this as the fixed mask.
                        args["fixed_image_masks"] = create_cfm(
                            self.inputs.reference_mask,
                            lesion_mask=None,
                            global_mask=True,
                        )

                # If a reference mask is provided...
                # But explicit masking is disabled...
                else:
                    # Use the reference mask as the fixed mask during registration.
                    # Do not mask the fixed image.
                    args["fixed_image_masks"] = self.inputs.reference_mask

            # If no reference mask is provided...
            # But a lesion mask *IS* provided ...
            elif isdefined(self.inputs.lesion_mask):
                # Create a cost function mask with the form: [global mask]
                # Use this as the fixed mask
                args["fixed_image_masks"] = create_cfm(
                    self.inputs.reference_image,
                    lesion_mask=None,
                    global_mask=True)

        # If no reference image is provided, fall back to the default template.
        else:
            from ..utils.misc import get_template_specs

            # Raise an error if the user specifies an unsupported image orientation.
            if self.inputs.orientation == "LAS":
                raise NotImplementedError

            template_spec = (self.inputs.template_spec
                             if isdefined(self.inputs.template_spec) else {})

            default_resolution = {
                "precise": 1,
                "fast": 2,
                "testing": 2
            }[self.inputs.flavor]

            # Set the template resolution.
            if isdefined(self.inputs.template_resolution):
                NIWORKFLOWS_LOG.warning(
                    "The use of ``template_resolution`` is deprecated")
                template_spec["res"] = self.inputs.template_resolution

            template_spec["suffix"] = self.inputs.reference
            template_spec["desc"] = None
            ref_template, template_spec = get_template_specs(
                self.inputs.template,
                template_spec=template_spec,
                default_resolution=default_resolution,
            )

            # Set reference image
            self._reference_image = ref_template
            if not op.isfile(self._reference_image):
                raise ValueError("""\
The registration reference must be an existing file, but path "%s" \
cannot be found.""" % ref_template)

            # Get the template specified by the user.
            ref_mask = get_template(self.inputs.template,
                                    desc="brain",
                                    suffix="mask",
                                    **template_spec)

            # Default is explicit masking disabled
            args["fixed_image"] = ref_template
            # Use the template mask as the fixed mask.
            args["fixed_image_masks"] = str(ref_mask)

            # Overwrite defaults if explicit masking
            if self.inputs.explicit_masking:
                # Mask the template image with the template mask.
                args["fixed_image"] = mask(ref_template, str(ref_mask),
                                           "fixed_masked.nii.gz")
                # Do not use a fixed mask during registration.
                args.pop("fixed_image_masks", None)

                # If a lesion mask is provided...
                if isdefined(self.inputs.lesion_mask):
                    # Create a cost function mask with the form: [global mask]
                    # Use this as the fixed mask.
                    args["fixed_image_masks"] = create_cfm(str(ref_mask),
                                                           lesion_mask=None,
                                                           global_mask=True)

        return args
Esempio n. 30
0
def init_enhance_and_skullstrip_bold_wf(
    brainmask_thresh=0.5,
    name="enhance_and_skullstrip_bold_wf",
    omp_nthreads=1,
    pre_mask=False,
):
    """
    Enhance and run brain extraction on a BOLD EPI image.

    This workflow takes in a :abbr:`BOLD (blood-oxygen level-dependant)`
    :abbr:`fMRI (functional MRI)` average/summary (e.g., a reference image
    averaging non-steady-state timepoints), and sharpens the histogram
    with the application of the N4 algorithm for removing the
    :abbr:`INU (intensity non-uniformity)` bias field and calculates a signal
    mask.

    Steps of this workflow are:

      1. Calculate a tentative mask by registering (9-parameters) to *fMRIPrep*'s
         :abbr:`EPI (echo-planar imaging)` -*boldref* template, which
         is in MNI space.
         The tentative mask is obtained by resampling the MNI template's
         brainmask into *boldref*-space.
      2. Binary dilation of the tentative mask with a sphere of 3mm diameter.
      3. Run ANTs' ``N4BiasFieldCorrection`` on the input
         :abbr:`BOLD (blood-oxygen level-dependant)` average, using the
         mask generated in 1) instead of the internal Otsu thresholding.
      4. Calculate a loose mask using FSL's ``bet``, with one mathematical morphology
         dilation of one iteration and a sphere of 6mm as structuring element.
      5. Mask the :abbr:`INU (intensity non-uniformity)`-corrected image
         with the latest mask calculated in 3), then use AFNI's ``3dUnifize``
         to *standardize* the T2* contrast distribution.
      6. Calculate a mask using AFNI's ``3dAutomask`` after the contrast
         enhancement of 4).
      7. Calculate a final mask as the intersection of 4) and 6).
      8. Apply final mask on the enhanced reference.

    Step 1 can be skipped if the ``pre_mask`` argument is set to ``True`` and
    a tentative mask is passed in to the workflow throught the ``pre_mask``
    Nipype input.


    Workflow graph
        .. workflow ::
            :graph2use: orig
            :simple_form: yes

            from niworkflows.func.util import init_enhance_and_skullstrip_bold_wf
            wf = init_enhance_and_skullstrip_bold_wf(omp_nthreads=1)

    .. _N4BiasFieldCorrection: https://hdl.handle.net/10380/3053

    Parameters
    ----------
    brainmask_thresh: :obj:`float`
        Lower threshold for the probabilistic brainmask to obtain
        the final binary mask (default: 0.5).
    name : str
        Name of workflow (default: ``enhance_and_skullstrip_bold_wf``)
    omp_nthreads : int
        number of threads available to parallel nodes
    pre_mask : bool
        Indicates whether the ``pre_mask`` input will be set (and thus, step 1
        should be skipped).

    Inputs
    ------
    in_file : str
        BOLD image (single volume)
    pre_mask : bool
        A tentative brain mask to initialize the workflow (requires ``pre_mask``
        parameter set ``True``).


    Outputs
    -------
    bias_corrected_file : str
        the ``in_file`` after `N4BiasFieldCorrection`_
    skull_stripped_file : str
        the ``bias_corrected_file`` after skull-stripping
    mask_file : str
        mask of the skull-stripped input file
    out_report : str
        reportlet for the skull-stripping

    """
    workflow = Workflow(name=name)
    inputnode = pe.Node(niu.IdentityInterface(fields=["in_file", "pre_mask"]),
                        name="inputnode")
    outputnode = pe.Node(
        niu.IdentityInterface(
            fields=["mask_file", "skull_stripped_file", "bias_corrected_file"
                    ]),
        name="outputnode",
    )

    # Dilate pre_mask
    pre_dilate = pe.Node(
        fsl.DilateImage(
            operation="max",
            kernel_shape="sphere",
            kernel_size=3.0,
            internal_datatype="char",
        ),
        name="pre_mask_dilate",
    )

    # Ensure mask's header matches reference's
    check_hdr = pe.Node(MatchHeader(),
                        name="check_hdr",
                        run_without_submitting=True)

    # Run N4 normally, force num_threads=1 for stability (images are small, no need for >1)
    n4_correct = pe.Node(
        N4BiasFieldCorrection(dimension=3,
                              copy_header=True,
                              bspline_fitting_distance=200),
        shrink_factor=2,
        name="n4_correct",
        n_procs=1,
    )
    n4_correct.inputs.rescale_intensities = True

    # Create a generous BET mask out of the bias-corrected EPI
    skullstrip_first_pass = pe.Node(fsl.BET(frac=0.2, mask=True),
                                    name="skullstrip_first_pass")
    bet_dilate = pe.Node(
        fsl.DilateImage(
            operation="max",
            kernel_shape="sphere",
            kernel_size=6.0,
            internal_datatype="char",
        ),
        name="skullstrip_first_dilate",
    )
    bet_mask = pe.Node(fsl.ApplyMask(), name="skullstrip_first_mask")

    # Use AFNI's unifize for T2 constrast & fix header
    unifize = pe.Node(
        afni.Unifize(
            t2=True,
            outputtype="NIFTI_GZ",
            # Default -clfrac is 0.1, 0.4 was too conservative
            # -rbt because I'm a Jedi AFNI Master (see 3dUnifize's documentation)
            args="-clfrac 0.2 -rbt 18.3 65.0 90.0",
            out_file="uni.nii.gz",
        ),
        name="unifize",
    )
    fixhdr_unifize = pe.Node(CopyXForm(), name="fixhdr_unifize", mem_gb=0.1)

    # Run ANFI's 3dAutomask to extract a refined brain mask
    skullstrip_second_pass = pe.Node(afni.Automask(dilate=1,
                                                   outputtype="NIFTI_GZ"),
                                     name="skullstrip_second_pass")
    fixhdr_skullstrip2 = pe.Node(CopyXForm(),
                                 name="fixhdr_skullstrip2",
                                 mem_gb=0.1)

    # Take intersection of both masks
    combine_masks = pe.Node(fsl.BinaryMaths(operation="mul"),
                            name="combine_masks")

    # Compute masked brain
    apply_mask = pe.Node(fsl.ApplyMask(), name="apply_mask")

    if not pre_mask:
        from ..interfaces.nibabel import Binarize

        bold_template = get_template("MNI152NLin2009cAsym",
                                     resolution=2,
                                     desc="fMRIPrep",
                                     suffix="boldref")
        brain_mask = get_template("MNI152NLin2009cAsym",
                                  resolution=2,
                                  desc="brain",
                                  suffix="mask")

        # Initialize transforms with antsAI
        init_aff = pe.Node(
            AI(
                fixed_image=str(bold_template),
                fixed_image_mask=str(brain_mask),
                metric=("Mattes", 32, "Regular", 0.2),
                transform=("Affine", 0.1),
                search_factor=(20, 0.12),
                principal_axes=False,
                convergence=(10, 1e-6, 10),
                verbose=True,
            ),
            name="init_aff",
            n_procs=omp_nthreads,
        )

        # Registration().version may be None
        if parseversion(Registration().version or "0.0.0") > Version("2.2.0"):
            init_aff.inputs.search_grid = (40, (0, 40, 40))

        # Set up spatial normalization
        norm = pe.Node(
            Registration(from_file=pkgr_fn("niworkflows.data",
                                           "epi_atlasbased_brainmask.json")),
            name="norm",
            n_procs=omp_nthreads,
        )
        norm.inputs.fixed_image = str(bold_template)
        map_brainmask = pe.Node(
            ApplyTransforms(
                interpolation="BSpline",
                float=True,
                # Use the higher resolution and probseg for numerical stability in rounding
                input_image=str(
                    get_template(
                        "MNI152NLin2009cAsym",
                        resolution=1,
                        label="brain",
                        suffix="probseg",
                    )),
            ),
            name="map_brainmask",
        )
        binarize_mask = pe.Node(Binarize(thresh_low=brainmask_thresh),
                                name="binarize_mask")

        # fmt: off
        workflow.connect([
            (inputnode, init_aff, [("in_file", "moving_image")]),
            (inputnode, map_brainmask, [("in_file", "reference_image")]),
            (inputnode, norm, [("in_file", "moving_image")]),
            (init_aff, norm, [("output_transform", "initial_moving_transform")
                              ]),
            (norm, map_brainmask, [
                ("reverse_invert_flags", "invert_transform_flags"),
                ("reverse_transforms", "transforms"),
            ]),
            (map_brainmask, binarize_mask, [("output_image", "in_file")]),
            (binarize_mask, pre_dilate, [("out_mask", "in_file")]),
        ])
        # fmt: on
    else:
        # fmt: off
        workflow.connect([
            (inputnode, pre_dilate, [("pre_mask", "in_file")]),
        ])
        # fmt: on

    # fmt: off
    workflow.connect([
        (inputnode, check_hdr, [("in_file", "reference")]),
        (pre_dilate, check_hdr, [("out_file", "in_file")]),
        (check_hdr, n4_correct, [("out_file", "mask_image")]),
        (inputnode, n4_correct, [("in_file", "input_image")]),
        (inputnode, fixhdr_unifize, [("in_file", "hdr_file")]),
        (inputnode, fixhdr_skullstrip2, [("in_file", "hdr_file")]),
        (n4_correct, skullstrip_first_pass, [("output_image", "in_file")]),
        (skullstrip_first_pass, bet_dilate, [("mask_file", "in_file")]),
        (bet_dilate, bet_mask, [("out_file", "mask_file")]),
        (skullstrip_first_pass, bet_mask, [("out_file", "in_file")]),
        (bet_mask, unifize, [("out_file", "in_file")]),
        (unifize, fixhdr_unifize, [("out_file", "in_file")]),
        (fixhdr_unifize, skullstrip_second_pass, [("out_file", "in_file")]),
        (skullstrip_first_pass, combine_masks, [("mask_file", "in_file")]),
        (skullstrip_second_pass, fixhdr_skullstrip2, [("out_file", "in_file")
                                                      ]),
        (fixhdr_skullstrip2, combine_masks, [("out_file", "operand_file")]),
        (fixhdr_unifize, apply_mask, [("out_file", "in_file")]),
        (combine_masks, apply_mask, [("out_file", "mask_file")]),
        (combine_masks, outputnode, [("out_file", "mask_file")]),
        (apply_mask, outputnode, [("out_file", "skull_stripped_file")]),
        (n4_correct, outputnode, [("output_image", "bias_corrected_file")]),
    ])
    # fmt: on

    return workflow
Esempio n. 31
0
def compute_iqms(name="ComputeIQMs"):
    """
    Setup the workflow that actually computes the IQMs.

    .. workflow::

        from mriqc.workflows.anatomical import compute_iqms
        from mriqc.testing import mock_config
        with mock_config():
            wf = compute_iqms()

    """
    from niworkflows.interfaces.bids import ReadSidecarJSON

    from ..interfaces.anatomical import Harmonize
    from .utils import _tofloat

    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(
        niu.IdentityInterface(fields=[
            "in_file",
            "in_ras",
            "brainmask",
            "airmask",
            "artmask",
            "headmask",
            "rotmask",
            "hatmask",
            "segmentation",
            "inu_corrected",
            "in_inu",
            "pvms",
            "metadata",
            "inverse_composite_transform",
        ]),
        name="inputnode",
    )
    outputnode = pe.Node(
        niu.IdentityInterface(fields=["out_file", "noisefit"]),
        name="outputnode",
    )

    # Extract metadata
    meta = pe.Node(ReadSidecarJSON(), name="metadata")

    # Add provenance
    addprov = pe.Node(AddProvenance(),
                      name="provenance",
                      run_without_submitting=True)

    # AFNI check smoothing
    fwhm_interface = get_fwhmx()

    fwhm = pe.Node(fwhm_interface, name="smoothness")

    # Harmonize
    homog = pe.Node(Harmonize(), name="harmonize")
    if config.workflow.species.lower() != "human":
        homog.inputs.erodemsk = False
        homog.inputs.thresh = 0.8

    # Mortamet's QI2
    getqi2 = pe.Node(ComputeQI2(), name="ComputeQI2")

    # Compute python-coded measures
    measures = pe.Node(
        StructuralQC(human=config.workflow.species.lower() == "human"),
        "measures")

    # Project MNI segmentation to T1 space
    invt = pe.MapNode(
        ants.ApplyTransforms(dimension=3,
                             default_value=0,
                             interpolation="Linear",
                             float=True),
        iterfield=["input_image"],
        name="MNItpms2t1",
    )
    if config.workflow.species.lower() == "human":
        invt.inputs.input_image = [
            str(p) for p in get_template(
                config.workflow.template_id,
                suffix="probseg",
                resolution=1,
                label=["CSF", "GM", "WM"],
            )
        ]
    else:
        invt.inputs.input_image = [
            str(p) for p in get_template(
                config.workflow.template_id,
                suffix="probseg",
                label=["CSF", "GM", "WM"],
            )
        ]

    datasink = pe.Node(
        IQMFileSink(
            out_dir=config.execution.output_dir,
            dataset=config.execution.dsname,
        ),
        name="datasink",
        run_without_submitting=True,
    )

    def _getwm(inlist):
        return inlist[-1]

    # fmt: off
    workflow.connect([
        (inputnode, meta, [("in_file", "in_file")]),
        (inputnode, datasink, [("in_file", "in_file"),
                               (("in_file", _get_mod), "modality")]),
        (inputnode, addprov, [(("in_file", _get_mod), "modality")]),
        (meta, datasink, [("subject", "subject_id"), ("session", "session_id"),
                          ("task", "task_id"), ("acquisition", "acq_id"),
                          ("reconstruction", "rec_id"), ("run", "run_id"),
                          ("out_dict", "metadata")]),
        (inputnode, addprov, [("in_file", "in_file"), ("airmask", "air_msk"),
                              ("rotmask", "rot_msk")]),
        (inputnode, getqi2, [("in_ras", "in_file"), ("hatmask", "air_msk")]),
        (inputnode, homog, [("inu_corrected", "in_file"),
                            (("pvms", _getwm), "wm_mask")]),
        (inputnode, measures, [("in_inu", "in_bias"), ("in_ras", "in_file"),
                               ("airmask", "air_msk"),
                               ("headmask", "head_msk"),
                               ("artmask", "artifact_msk"),
                               ("rotmask", "rot_msk"),
                               ("segmentation", "in_segm"),
                               ("pvms", "in_pvms")]),
        (inputnode, fwhm, [("in_ras", "in_file"), ("brainmask", "mask")]),
        (inputnode, invt, [("in_ras", "reference_image"),
                           ("inverse_composite_transform", "transforms")]),
        (homog, measures, [("out_file", "in_noinu")]),
        (invt, measures, [("output_image", "mni_tpms")]),
        (fwhm, measures, [(("fwhm", _tofloat), "in_fwhm")]),
        (measures, datasink, [("out_qc", "root")]),
        (addprov, datasink, [("out_prov", "provenance")]),
        (getqi2, datasink, [("qi2", "qi_2")]),
        (getqi2, outputnode, [("out_file", "noisefit")]),
        (datasink, outputnode, [("out_file", "out_file")]),
    ])
    # fmt: on

    return workflow
Esempio n. 32
0
def init_brain_extraction_wf(name='brain_extraction_wf',
                             in_template='OASIS30ANTs',
                             use_float=True,
                             normalization_quality='precise',
                             omp_nthreads=None,
                             mem_gb=3.0,
                             bids_suffix='T1w',
                             atropos_refine=True,
                             atropos_use_random_seed=True,
                             atropos_model=None,
                             use_laplacian=True,
                             bspline_fitting_distance=200):
    """
    A Nipype implementation of the official ANTs' ``antsBrainExtraction.sh``
    workflow (only for 3D images).

    The official workflow is built as follows (and this implementation
    follows the same organization):

      1. Step 1 performs several clerical tasks (adding padding, calculating
         the Laplacian of inputs, affine initialization) and the core
         spatial normalization.
      2. Maps the brain mask into target space using the normalization
         calculated in 1.
      3. Superstep 1b: smart binarization of the brain mask
      4. Superstep 6: apply ATROPOS and massage its outputs
      5. Superstep 7: use results from 4 to refine the brain mask


    .. workflow::
        :graph2use: orig
        :simple_form: yes
        from niworkflows.anat import init_brain_extraction_wf
        wf = init_brain_extraction_wf()


    **Parameters**

        in_template : str
            Name of the skull-stripping template ('OASIS30ANTs', 'NKI', or
            path).
            The brain template from which regions will be projected
            Anatomical template created using e.g. LPBA40 data set with
            ``buildtemplateparallel.sh`` in ANTs.
            The workflow will automatically search for a brain probability
            mask created using e.g. LPBA40 data set which have brain masks
            defined, and warped to anatomical template and
            averaged resulting in a probability image.
        use_float : bool
            Whether single precision should be used
        normalization_quality : str
            Use more precise or faster registration parameters
            (default: ``precise``, other possible values: ``testing``)
        omp_nthreads : int
            Maximum number of threads an individual process may use
        mem_gb : float
            Estimated peak memory consumption of the most hungry nodes
            in the workflow
        bids_suffix : str
            Sequence type of the first input image. For a list of acceptable values
            see https://bids-specification.readthedocs.io/en/latest/\
04-modality-specific-files/01-magnetic-resonance-imaging-data.html#anatomy-imaging-data
        atropos_refine : bool
            Enables or disables the whole ATROPOS sub-workflow
        atropos_use_random_seed : bool
            Whether ATROPOS should generate a random seed based on the
            system's clock
        atropos_model : tuple or None
            Allows to specify a particular segmentation model, overwriting
            the defaults based on ``bids_suffix``
        use_laplacian : bool
            Enables or disables alignment of the Laplacian as an additional
            criterion for image registration quality (default: True)
        bspline_fitting_distance : float
            The size of the b-spline mesh grid elements, in mm (default: 200)
        name : str, optional
            Workflow name (default: antsBrainExtraction)


    **Inputs**

        in_files
            List of input anatomical images to be brain-extracted,
            typically T1-weighted.
            If a list of anatomical images is provided, subsequently
            specified images are used during the segmentation process.
            However, only the first image is used in the registration
            of priors.
            Our suggestion would be to specify the T1w as the first image.
        in_mask
            (optional) Mask used for registration to limit the metric
            computation to a specific region.


    **Outputs**


        out_file
            Skull-stripped and :abbr:`INU (intensity non-uniformity)`-corrected ``in_files``
        out_mask
            Calculated brain mask
        bias_corrected
            The ``in_files`` input images, after :abbr:`INU (intensity non-uniformity)`
            correction, before skull-stripping.
        bias_image
            The :abbr:`INU (intensity non-uniformity)` field estimated for each
            input in ``in_files``
        out_segm
            Output segmentation by ATROPOS
        out_tpms
            Output :abbr:`TPMs (tissue probability maps)` by ATROPOS


    """
    from templateflow.api import get as get_template
    wf = pe.Workflow(name)

    tpl_target_path = str(
        get_template(in_template, desc=None, resolution=1, suffix=bids_suffix))

    # Get probabilistic brain mask if available
    tpl_mask_path = get_template(
        in_template, resolution=1, label='brain', suffix='probseg') or \
        get_template(in_template, resolution=1, desc='brain', suffix='mask')

    if omp_nthreads is None or omp_nthreads < 1:
        omp_nthreads = cpu_count()

    inputnode = pe.Node(niu.IdentityInterface(fields=['in_files', 'in_mask']),
                        name='inputnode')

    # Try to find a registration mask, set if available
    tpl_regmask_path = get_template(
        in_template, resolution=1,
        desc='BrainCerebellumExtraction', suffix='mask')
    if tpl_regmask_path:
        inputnode.inputs.in_mask = str(tpl_regmask_path)

    outputnode = pe.Node(niu.IdentityInterface(
        fields=['out_file', 'out_mask', 'bias_corrected', 'bias_image', 'out_segm']),
        name='outputnode')

    trunc = pe.MapNode(ImageMath(operation='TruncateImageIntensity', op2='0.01 0.999 256'),
                       name='truncate_images', iterfield=['op1'])
    inu_n4 = pe.MapNode(
        N4BiasFieldCorrection(
            dimension=3, save_bias=False, copy_header=True,
            n_iterations=[50] * 4, convergence_threshold=1e-7, shrink_factor=4,
            bspline_fitting_distance=bspline_fitting_distance),
        n_procs=omp_nthreads, name='inu_n4', iterfield=['input_image'])

    res_tmpl = pe.Node(ResampleImageBySpacing(
        out_spacing=(4, 4, 4), apply_smoothing=True), name='res_tmpl')
    res_tmpl.inputs.input_image = tpl_target_path
    res_target = pe.Node(ResampleImageBySpacing(
        out_spacing=(4, 4, 4), apply_smoothing=True), name='res_target')

    lap_tmpl = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'),
                       name='lap_tmpl')
    lap_tmpl.inputs.op1 = tpl_target_path
    lap_target = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'),
                         name='lap_target')
    mrg_tmpl = pe.Node(niu.Merge(2), name='mrg_tmpl')
    mrg_tmpl.inputs.in1 = tpl_target_path
    mrg_target = pe.Node(niu.Merge(2), name='mrg_target')

    # Initialize transforms with antsAI
    init_aff = pe.Node(AI(
        metric=('Mattes', 32, 'Regular', 0.25),
        transform=('Affine', 0.1),
        search_factor=(15, 0.1),
        principal_axes=False,
        convergence=(10, 1e-6, 10),
        verbose=True),
        name='init_aff',
        n_procs=omp_nthreads)

    if parseversion(Registration().version) > Version('2.2.0'):
        init_aff.inputs.search_grid = (40, (0, 40, 40))

    # Set up spatial normalization
    settings_file = 'antsBrainExtraction_%s.json' if use_laplacian \
        else 'antsBrainExtractionNoLaplacian_%s.json'
    norm = pe.Node(Registration(from_file=pkgr_fn(
        'niworkflows.data', settings_file % normalization_quality)),
        name='norm',
        n_procs=omp_nthreads,
        mem_gb=mem_gb)
    norm.inputs.float = use_float
    fixed_mask_trait = 'fixed_image_mask'
    if parseversion(Registration().version) >= Version('2.2.0'):
        fixed_mask_trait += 's'

    map_brainmask = pe.Node(
        ApplyTransforms(interpolation='Gaussian', float=True),
        name='map_brainmask',
        mem_gb=1
    )
    map_brainmask.inputs.input_image = str(tpl_mask_path)

    thr_brainmask = pe.Node(ThresholdImage(
        dimension=3, th_low=0.5, th_high=1.0, inside_value=1,
        outside_value=0), name='thr_brainmask')

    # Morphological dilation, radius=2
    dil_brainmask = pe.Node(ImageMath(operation='MD', op2='2'),
                            name='dil_brainmask')
    # Get largest connected component
    get_brainmask = pe.Node(ImageMath(operation='GetLargestComponent'),
                            name='get_brainmask')

    # Refine INU correction
    inu_n4_final = pe.MapNode(
        N4BiasFieldCorrection(
            dimension=3, save_bias=True, copy_header=True,
            n_iterations=[50] * 5, convergence_threshold=1e-7, shrink_factor=4,
            bspline_fitting_distance=bspline_fitting_distance),
        n_procs=omp_nthreads, name='inu_n4_final', iterfield=['input_image'])

    # Apply mask
    apply_mask = pe.MapNode(ApplyMask(), iterfield=['in_file'], name='apply_mask')

    wf.connect([
        (inputnode, trunc, [('in_files', 'op1')]),
        (inputnode, inu_n4_final, [('in_files', 'input_image')]),
        (inputnode, init_aff, [('in_mask', 'fixed_image_mask')]),
        (inputnode, norm, [('in_mask', fixed_mask_trait)]),
        (inputnode, map_brainmask, [(('in_files', _pop), 'reference_image')]),
        (trunc, inu_n4, [('output_image', 'input_image')]),
        (inu_n4, res_target, [
            (('output_image', _pop), 'input_image')]),
        (res_tmpl, init_aff, [('output_image', 'fixed_image')]),
        (res_target, init_aff, [('output_image', 'moving_image')]),
        (init_aff, norm, [('output_transform', 'initial_moving_transform')]),
        (norm, map_brainmask, [
            ('reverse_transforms', 'transforms'),
            ('reverse_invert_flags', 'invert_transform_flags')]),
        (map_brainmask, thr_brainmask, [('output_image', 'input_image')]),
        (thr_brainmask, dil_brainmask, [('output_image', 'op1')]),
        (dil_brainmask, get_brainmask, [('output_image', 'op1')]),
        (inu_n4_final, apply_mask, [('output_image', 'in_file')]),
        (get_brainmask, apply_mask, [('output_image', 'mask_file')]),
        (get_brainmask, outputnode, [('output_image', 'out_mask')]),
        (apply_mask, outputnode, [('out_file', 'out_file')]),
        (inu_n4_final, outputnode, [('output_image', 'bias_corrected'),
                                    ('bias_image', 'bias_image')]),
    ])

    if use_laplacian:
        lap_tmpl = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'),
                           name='lap_tmpl')
        lap_tmpl.inputs.op1 = tpl_target_path
        lap_target = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'),
                             name='lap_target')
        mrg_tmpl = pe.Node(niu.Merge(2), name='mrg_tmpl')
        mrg_tmpl.inputs.in1 = tpl_target_path
        mrg_target = pe.Node(niu.Merge(2), name='mrg_target')
        wf.connect([
            (inu_n4, lap_target, [
                (('output_image', _pop), 'op1')]),
            (lap_tmpl, mrg_tmpl, [('output_image', 'in2')]),
            (inu_n4, mrg_target, [('output_image', 'in1')]),
            (lap_target, mrg_target, [('output_image', 'in2')]),
            (mrg_tmpl, norm, [('out', 'fixed_image')]),
            (mrg_target, norm, [('out', 'moving_image')]),
        ])
    else:
        norm.inputs.fixed_image = tpl_target_path
        wf.connect([
            (inu_n4, norm, [
                (('output_image', _pop), 'moving_image')]),
        ])

    if atropos_refine:
        atropos_model = atropos_model or list(ATROPOS_MODELS[bids_suffix].values())
        atropos_wf = init_atropos_wf(
            use_random_seed=atropos_use_random_seed,
            omp_nthreads=omp_nthreads,
            mem_gb=mem_gb,
            in_segmentation_model=atropos_model,
        )
        sel_wm = pe.Node(niu.Select(index=atropos_model[-1] - 1), name='sel_wm',
                         run_without_submitting=True)

        wf.disconnect([
            (get_brainmask, outputnode, [('output_image', 'out_mask')]),
            (get_brainmask, apply_mask, [('output_image', 'mask_file')]),
        ])
        wf.connect([
            (inu_n4, atropos_wf, [
                ('output_image', 'inputnode.in_files')]),
            (thr_brainmask, atropos_wf, [
                ('output_image', 'inputnode.in_mask')]),
            (get_brainmask, atropos_wf, [
                ('output_image', 'inputnode.in_mask_dilated')]),
            (atropos_wf, sel_wm, [('outputnode.out_tpms', 'inlist')]),
            (sel_wm, inu_n4_final, [('out', 'weight_image')]),
            (atropos_wf, outputnode, [
                ('outputnode.out_mask', 'out_mask')]),
            (atropos_wf, apply_mask, [
                ('outputnode.out_mask', 'mask_file')]),
            (atropos_wf, outputnode, [
                ('outputnode.out_segm', 'out_segm'),
                ('outputnode.out_tpms', 'out_tpms')])
        ])
    return wf
Esempio n. 33
0
def airmsk_wf(name="AirMaskWorkflow"):
    """
    Implements the Step 1 of [Mortamet2009]_.

    .. workflow::

        from mriqc.testing import mock_config
        from mriqc.workflows.anatomical import airmsk_wf
        with mock_config():
            wf = airmsk_wf()

    """
    workflow = pe.Workflow(name=name)

    inputnode = pe.Node(
        niu.IdentityInterface(fields=[
            "in_file",
            "in_mask",
            "head_mask",
            "inverse_composite_transform",
        ]),
        name="inputnode",
    )
    outputnode = pe.Node(
        niu.IdentityInterface(
            fields=["hat_mask", "air_mask", "art_mask", "rot_mask"]),
        name="outputnode",
    )

    rotmsk = pe.Node(RotationMask(), name="RotationMask")

    invt = pe.Node(
        ants.ApplyTransforms(
            dimension=3,
            default_value=0,
            interpolation="MultiLabel",
            float=True,
        ),
        name="invert_xfm",
    )
    if config.workflow.species.lower() == "human":
        invt.inputs.input_image = str(
            get_template(config.workflow.template_id,
                         resolution=1,
                         desc="head",
                         suffix="mask"))
    else:
        # TODO: provide options for other populations
        invt.inputs.input_image = str(
            get_template(config.workflow.template_id,
                         desc="brain",
                         suffix="mask")[0])

    qi1 = pe.Node(ArtifactMask(), name="ArtifactMask")

    # fmt: off
    workflow.connect([(inputnode, rotmsk, [("in_file", "in_file")]),
                      (inputnode, qi1, [("in_file", "in_file"),
                                        ("head_mask", "head_mask")]),
                      (rotmsk, qi1, [("out_file", "rot_mask")]),
                      (inputnode, invt, [("in_mask", "reference_image"),
                                         ("inverse_composite_transform",
                                          "transforms")]),
                      (invt, qi1, [("output_image", "nasion_post_mask")]),
                      (qi1, outputnode, [("out_hat_msk", "hat_mask"),
                                         ("out_air_msk", "air_mask"),
                                         ("out_art_msk", "art_mask")]),
                      (rotmsk, outputnode, [("out_file", "rot_mask")])])
    # fmt: on

    return workflow
Esempio n. 34
0
def init_carpetplot_wf(mem_gb, metadata, cifti_output, name="bold_carpet_wf"):
    """
    Build a workflow to generate *carpet* plots.

    Resamples the MNI parcellation (ad-hoc parcellation derived from the
    Harvard-Oxford template and others).

    Parameters
    ----------
    mem_gb : :obj:`float`
        Size of BOLD file in GB - please note that this size
        should be calculated after resamplings that may extend
        the FoV
    metadata : :obj:`dict`
        BIDS metadata for BOLD file
    name : :obj:`str`
        Name of workflow (default: ``bold_carpet_wf``)

    Inputs
    ------
    bold
        BOLD image, after the prescribed corrections (STC, HMC and SDC)
        when available.
    bold_mask
        BOLD series mask
    confounds_file
        TSV of all aggregated confounds
    t1_bold_xform
        Affine matrix that maps the T1w space into alignment with
        the native BOLD space
    std2anat_xfm
        ANTs-compatible affine-and-warp transform file
    cifti_bold
        BOLD image in CIFTI format, to be used in place of volumetric BOLD

    Outputs
    -------
    out_carpetplot
        Path of the generated SVG file

    """
    from niworkflows.engine.workflows import LiterateWorkflow as Workflow
    from niworkflows.interfaces.fixes import FixHeaderApplyTransforms as ApplyTransforms

    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'bold', 'bold_mask', 'confounds_file', 't1_bold_xform', 'std2anat_xfm',
        'cifti_bold'
    ]),
                        name='inputnode')

    outputnode = pe.Node(niu.IdentityInterface(fields=['out_carpetplot']),
                         name='outputnode')

    # List transforms
    mrg_xfms = pe.Node(niu.Merge(2), name='mrg_xfms')

    # Warp segmentation into EPI space
    resample_parc = pe.Node(ApplyTransforms(
        dimension=3,
        input_image=str(
            get_template('MNI152NLin2009cAsym',
                         resolution=1,
                         desc='carpet',
                         suffix='dseg',
                         extension=['.nii', '.nii.gz'])),
        interpolation='MultiLabel'),
                            name='resample_parc')

    # Carpetplot and confounds plot
    conf_plot = pe.Node(FMRISummary(tr=metadata['RepetitionTime'],
                                    confounds_list=[
                                        ('global_signal', None, 'GS'),
                                        ('csf', None, 'GSCSF'),
                                        ('white_matter', None, 'GSWM'),
                                        ('std_dvars', None, 'DVARS'),
                                        ('framewise_displacement', 'mm', 'FD')
                                    ]),
                        name='conf_plot',
                        mem_gb=mem_gb)
    ds_report_bold_conf = pe.Node(DerivativesDataSink(
        desc='carpetplot',
        datatype="figures",
        extension="svg",
        dismiss_entities=("echo", )),
                                  name='ds_report_bold_conf',
                                  run_without_submitting=True,
                                  mem_gb=DEFAULT_MEMORY_MIN_GB)

    workflow = Workflow(name=name)
    # no need for segmentations if using CIFTI
    if cifti_output:
        workflow.connect(inputnode, 'cifti_bold', conf_plot, 'in_func')
    else:
        workflow.connect([
            (inputnode, mrg_xfms, [('t1_bold_xform', 'in1'),
                                   ('std2anat_xfm', 'in2')]),
            (inputnode, resample_parc, [('bold_mask', 'reference_image')]),
            (mrg_xfms, resample_parc, [('out', 'transforms')]),
            # Carpetplot
            (inputnode, conf_plot, [('bold', 'in_func'),
                                    ('bold_mask', 'in_mask')]),
            (resample_parc, conf_plot, [('output_image', 'in_segm')])
        ])

    workflow.connect([
        (inputnode, conf_plot, [('confounds_file', 'confounds_file')]),
        (conf_plot, ds_report_bold_conf, [('out_file', 'in_file')]),
        (conf_plot, outputnode, [('out_file', 'out_carpetplot')]),
    ])
    return workflow
Esempio n. 35
0
def init_cbfplot_wf(mem_gb, metadata, omp_nthreads, name='cbf_plot'):
    workflow = Workflow(name=name)

    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'cbf', 'cbf_ts', 'score_ts', 'score', 'scrub', 'asl_ref', 'basil',
        'pvc', 'asl_mask', 't1_asl_xform', 'std2anat_xfm', 'confounds_file',
        'scoreindex'
    ]),
                        name='inputnode')
    outputnode = pe.Node(niu.IdentityInterface(fields=[
        'cbf_carpetplot', 'score_carpetplot', 'cbf_summary_plot',
        'cbf_summary_plot', 'score_summary_plot', 'scrub_summary_plot',
        'basil_summary_plot', 'pvc_summary_plot'
    ]),
                         name='outputnode')
    mrg_xfms = pe.Node(niu.Merge(2), name='mrg_xfms')
    from templateflow.api import get as get_template
    seg = get_template('MNI152NLin2009cAsym',
                       resolution=1,
                       desc='carpet',
                       suffix='dseg')
    print(seg)
    resample_parc = pe.Node(ApplyTransforms(float=True,
                                            input_image=str(seg),
                                            dimension=3,
                                            default_value=0,
                                            interpolation='MultiLabel'),
                            name='resample_parc')

    cbftssummary = pe.Node(CBFtsSummary(tr=metadata['RepetitionTime']),
                           name='cbf_ts_summary',
                           mem_gb=0.2)
    cbfsummary = pe.Node(CBFSummary(label='cbf'),
                         name='cbf_summary',
                         mem_gb=0.2)
    scoresummary = pe.Node(CBFSummary(label='score'),
                           name='score_summary',
                           mem_gb=0.2)
    scrubsummary = pe.Node(CBFSummary(label='scrub'),
                           name='scrub_summary',
                           mem_gb=0.2)
    basilsummary = pe.Node(CBFSummary(label='basil'),
                           name='basil_summary',
                           mem_gb=0.2)
    pvcsummary = pe.Node(CBFSummary(label='pvc'),
                         name='pvc_summary',
                         mem_gb=0.2)

    ds_report_cbftsplot = pe.Node(DerivativesDataSink(desc='cbftsplot',
                                                      datatype="figures",
                                                      keep_dtype=True),
                                  name='ds_report_cbftsplot',
                                  run_without_submitting=True,
                                  mem_gb=DEFAULT_MEMORY_MIN_GB)
    ds_report_cbfplot = pe.Node(DerivativesDataSink(desc='cbfplot',
                                                    datatype="figures",
                                                    keep_dtype=True),
                                name='ds_report_cbfplot',
                                run_without_submitting=True,
                                mem_gb=DEFAULT_MEMORY_MIN_GB)
    ds_report_scoreplot = pe.Node(DerivativesDataSink(desc='scoreplot',
                                                      datatype="figures",
                                                      keep_dtype=True),
                                  name='ds_report_scoreplot',
                                  run_without_submitting=True,
                                  mem_gb=DEFAULT_MEMORY_MIN_GB)
    ds_report_scrubplot = pe.Node(DerivativesDataSink(desc='scrubplot',
                                                      datatype="figures",
                                                      keep_dtype=True),
                                  name='ds_report_scrubplot',
                                  run_without_submitting=True,
                                  mem_gb=DEFAULT_MEMORY_MIN_GB)
    ds_report_basilplot = pe.Node(DerivativesDataSink(desc='basilplot',
                                                      datatype="figures",
                                                      keep_dtype=True),
                                  name='ds_report_basilplot',
                                  run_without_submitting=True,
                                  mem_gb=DEFAULT_MEMORY_MIN_GB)
    ds_report_pvcplot = pe.Node(DerivativesDataSink(desc='pvcplot',
                                                    datatype="figures",
                                                    keep_dtype=True),
                                name='ds_report_pvcplot',
                                run_without_submitting=True,
                                mem_gb=DEFAULT_MEMORY_MIN_GB)

    workflow.connect([
        (inputnode, mrg_xfms, [('t1_asl_xform', 'in1'),
                               ('std2anat_xfm', 'in2')]),
        (inputnode, resample_parc, [('asl_mask', 'reference_image')]),
        (mrg_xfms, resample_parc, [('out', 'transforms')]),
        (resample_parc, cbftssummary, [('output_image', 'seg_file')]),
        (inputnode, cbftssummary, [('cbf_ts', 'cbf_ts'),
                                   ('confounds_file', 'conf_file'),
                                   ('scoreindex', 'score_file')]),
        (cbftssummary, ds_report_cbftsplot, [('out_file', 'in_file')]),
        (cbftssummary, outputnode, [('out_file', 'cbf_carpetplot')]),
        (inputnode, cbfsummary, [('cbf', 'cbf'), ('asl_ref', 'ref_vol')]),
        (cbfsummary, ds_report_cbfplot, [('out_file', 'in_file')]),
        (cbfsummary, outputnode, [('out_file', 'cbf_summary_plot')]),
        (inputnode, scoresummary, [('score', 'cbf'), ('asl_ref', 'ref_vol')]),
        (scoresummary, ds_report_scoreplot, [('out_file', 'in_file')]),
        (scoresummary, outputnode, [('out_file', 'score_summary_plot')]),
        (inputnode, scrubsummary, [('scrub', 'cbf'), ('asl_ref', 'ref_vol')]),
        (scrubsummary, ds_report_scrubplot, [('out_file', 'in_file')]),
        (scrubsummary, outputnode, [('out_file', 'scrub_summary_plot')]),
        (inputnode, basilsummary, [('basil', 'cbf'), ('asl_ref', 'ref_vol')]),
        (basilsummary, ds_report_basilplot, [('out_file', 'in_file')]),
        (basilsummary, outputnode, [('out_file', 'basil_summary_plot')]),
        (inputnode, pvcsummary, [('pvc', 'cbf'), ('asl_ref', 'ref_vol')]),
        (pvcsummary, ds_report_pvcplot, [('out_file', 'in_file')]),
        (pvcsummary, outputnode, [('out_file', 'pvc_summary_plot')]),
    ])
    return workflow
Esempio n. 36
0
def reference():
    return str(get_template('MNI152Lin', resolution=2, desc=None, suffix='T1w'))
Esempio n. 37
0
def init_brain_extraction_wf(name='brain_extraction_wf',
                             in_template='OASIS30ANTs',
                             template_spec=None,
                             use_float=True,
                             normalization_quality='precise',
                             omp_nthreads=None,
                             mem_gb=3.0,
                             bids_suffix='T1w',
                             atropos_refine=True,
                             atropos_use_random_seed=True,
                             atropos_model=None,
                             use_laplacian=True,
                             bspline_fitting_distance=200):
    """
    Build a workflow for atlas-based brain extraction on anatomical MRI data.

    A Nipype implementation of the official ANTs' ``antsBrainExtraction.sh``
    workflow (only for 3D images).

    The official workflow is built as follows (and this implementation
    follows the same organization):

      1. Step 1 performs several clerical tasks (adding padding, calculating
         the Laplacian of inputs, affine initialization) and the core
         spatial normalization.
      2. Maps the brain mask into target space using the normalization
         calculated in 1.
      3. Superstep 1b: smart binarization of the brain mask
      4. Superstep 6: apply ATROPOS and massage its outputs
      5. Superstep 7: use results from 4 to refine the brain mask

    Workflow Graph
        .. workflow::
            :graph2use: orig
            :simple_form: yes

            from niworkflows.anat.ants import init_brain_extraction_wf
            wf = init_brain_extraction_wf()

    Parameters
    ----------
    in_template : str
        Name of the skull-stripping template ('OASIS30ANTs', 'NKI', or
        path).
        The brain template from which regions will be projected
        Anatomical template created using e.g. LPBA40 data set with
        ``buildtemplateparallel.sh`` in ANTs.
        The workflow will automatically search for a brain probability
        mask created using e.g. LPBA40 data set which have brain masks
        defined, and warped to anatomical template and
        averaged resulting in a probability image.
    use_float : bool
        Whether single precision should be used
    normalization_quality : str
        Use more precise or faster registration parameters
        (default: ``precise``, other possible values: ``testing``)
    omp_nthreads : int
        Maximum number of threads an individual process may use
    mem_gb : float
        Estimated peak memory consumption of the most hungry nodes
        in the workflow
    bids_suffix : str
        Sequence type of the first input image. For a list of acceptable values
        see https://bids-specification.readthedocs.io/en/latest/\
04-modality-specific-files/01-magnetic-resonance-imaging-data.html#anatomy-imaging-data
    atropos_refine : bool
        Enables or disables the whole ATROPOS sub-workflow
    atropos_use_random_seed : bool
        Whether ATROPOS should generate a random seed based on the
        system's clock
    atropos_model : tuple or None
        Allows to specify a particular segmentation model, overwriting
        the defaults based on ``bids_suffix``
    use_laplacian : bool
        Enables or disables alignment of the Laplacian as an additional
        criterion for image registration quality (default: True)
    bspline_fitting_distance : float
        The size of the b-spline mesh grid elements, in mm (default: 200)
    name : str, optional
        Workflow name (default: antsBrainExtraction)

    Inputs
    ------
    in_files : list
        List of input anatomical images to be brain-extracted,
        typically T1-weighted.
        If a list of anatomical images is provided, subsequently
        specified images are used during the segmentation process.
        However, only the first image is used in the registration
        of priors.
        Our suggestion would be to specify the T1w as the first image.
    in_mask : list, optional
        Mask used for registration to limit the metric
        computation to a specific region.

    Outputs
    -------
    out_file : str
        Skull-stripped and :abbr:`INU (intensity non-uniformity)`-corrected ``in_files``
    out_mask : str
        Calculated brain mask
    bias_corrected : str
        The ``in_files`` input images, after :abbr:`INU (intensity non-uniformity)`
        correction, before skull-stripping.
    bias_image : str
        The :abbr:`INU (intensity non-uniformity)` field estimated for each
        input in ``in_files``
    out_segm : str
        Output segmentation by ATROPOS
    out_tpms : str
        Output :abbr:`TPMs (tissue probability maps)` by ATROPOS

    """
    from templateflow.api import get as get_template
    wf = pe.Workflow(name)

    template_spec = template_spec or {}

    # suffix passed via spec takes precedence
    template_spec['suffix'] = template_spec.get('suffix', bids_suffix)

    tpl_target_path, common_spec = get_template_specs(
        in_template,
        template_spec=template_spec)

    # Get probabilistic brain mask if available
    tpl_mask_path = get_template(
        in_template, label='brain', suffix='probseg', **common_spec) or \
        get_template(in_template, desc='brain', suffix='mask', **common_spec)

    if omp_nthreads is None or omp_nthreads < 1:
        omp_nthreads = cpu_count()

    inputnode = pe.Node(niu.IdentityInterface(fields=['in_files', 'in_mask']),
                        name='inputnode')

    # Try to find a registration mask, set if available
    tpl_regmask_path = get_template(
        in_template, desc='BrainCerebellumExtraction', suffix='mask',
        **common_spec)
    if tpl_regmask_path:
        inputnode.inputs.in_mask = str(tpl_regmask_path)

    outputnode = pe.Node(niu.IdentityInterface(
        fields=['out_file', 'out_mask', 'bias_corrected', 'bias_image',
                'out_segm', 'out_tpms']),
        name='outputnode')

    copy_xform = pe.Node(CopyXForm(
        fields=['out_file', 'out_mask', 'bias_corrected', 'bias_image']),
        name='copy_xform', run_without_submitting=True)

    trunc = pe.MapNode(ImageMath(operation='TruncateImageIntensity', op2='0.01 0.999 256'),
                       name='truncate_images', iterfield=['op1'])
    inu_n4 = pe.MapNode(
        N4BiasFieldCorrection(
            dimension=3, save_bias=False, copy_header=True,
            n_iterations=[50] * 4, convergence_threshold=1e-7, shrink_factor=4,
            bspline_fitting_distance=bspline_fitting_distance),
        n_procs=omp_nthreads, name='inu_n4', iterfield=['input_image'])

    res_tmpl = pe.Node(ResampleImageBySpacing(
        out_spacing=(4, 4, 4), apply_smoothing=True), name='res_tmpl')
    res_tmpl.inputs.input_image = tpl_target_path
    res_target = pe.Node(ResampleImageBySpacing(
        out_spacing=(4, 4, 4), apply_smoothing=True), name='res_target')

    lap_tmpl = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'),
                       name='lap_tmpl')
    lap_tmpl.inputs.op1 = tpl_target_path
    lap_target = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'),
                         name='lap_target')
    mrg_tmpl = pe.Node(niu.Merge(2), name='mrg_tmpl')
    mrg_tmpl.inputs.in1 = tpl_target_path
    mrg_target = pe.Node(niu.Merge(2), name='mrg_target')

    # Initialize transforms with antsAI
    init_aff = pe.Node(AI(
        metric=('Mattes', 32, 'Regular', 0.25),
        transform=('Affine', 0.1),
        search_factor=(15, 0.1),
        principal_axes=False,
        convergence=(10, 1e-6, 10),
        verbose=True),
        name='init_aff',
        n_procs=omp_nthreads)

    # Tolerate missing ANTs at construction time
    _ants_version = Registration().version
    if _ants_version and parseversion(_ants_version) >= Version('2.3.0'):
        init_aff.inputs.search_grid = (40, (0, 40, 40))

    # Set up spatial normalization
    settings_file = 'antsBrainExtraction_%s.json' if use_laplacian \
        else 'antsBrainExtractionNoLaplacian_%s.json'
    norm = pe.Node(Registration(from_file=pkgr_fn(
        'niworkflows.data', settings_file % normalization_quality)),
        name='norm',
        n_procs=omp_nthreads,
        mem_gb=mem_gb)
    norm.inputs.float = use_float
    fixed_mask_trait = 'fixed_image_mask'
    if _ants_version and parseversion(_ants_version) >= Version('2.2.0'):
        fixed_mask_trait += 's'

    map_brainmask = pe.Node(
        ApplyTransforms(interpolation='Gaussian', float=True),
        name='map_brainmask',
        mem_gb=1
    )
    map_brainmask.inputs.input_image = str(tpl_mask_path)

    thr_brainmask = pe.Node(ThresholdImage(
        dimension=3, th_low=0.5, th_high=1.0, inside_value=1,
        outside_value=0), name='thr_brainmask')

    # Morphological dilation, radius=2
    dil_brainmask = pe.Node(ImageMath(operation='MD', op2='2'),
                            name='dil_brainmask')
    # Get largest connected component
    get_brainmask = pe.Node(ImageMath(operation='GetLargestComponent'),
                            name='get_brainmask')

    # Refine INU correction
    inu_n4_final = pe.MapNode(
        N4BiasFieldCorrection(
            dimension=3, save_bias=True, copy_header=True,
            n_iterations=[50] * 5, convergence_threshold=1e-7, shrink_factor=4,
            bspline_fitting_distance=bspline_fitting_distance),
        n_procs=omp_nthreads, name='inu_n4_final', iterfield=['input_image'])
    if _ants_version and parseversion(_ants_version) >= Version('2.1.0'):
        inu_n4_final.inputs.rescale_intensities = True
    else:
        warn("""\
Found ANTs version %s, which is too old. Please consider upgrading to 2.1.0 or \
greater so that the --rescale-intensities option is available with \
N4BiasFieldCorrection.""" % _ants_version, DeprecationWarning)

    # Apply mask
    apply_mask = pe.MapNode(ApplyMask(), iterfield=['in_file'], name='apply_mask')

    wf.connect([
        (inputnode, trunc, [('in_files', 'op1')]),
        (inputnode, copy_xform, [(('in_files', _pop), 'hdr_file')]),
        (inputnode, inu_n4_final, [('in_files', 'input_image')]),
        (inputnode, init_aff, [('in_mask', 'fixed_image_mask')]),
        (inputnode, norm, [('in_mask', fixed_mask_trait)]),
        (inputnode, map_brainmask, [(('in_files', _pop), 'reference_image')]),
        (trunc, inu_n4, [('output_image', 'input_image')]),
        (inu_n4, res_target, [
            (('output_image', _pop), 'input_image')]),
        (res_tmpl, init_aff, [('output_image', 'fixed_image')]),
        (res_target, init_aff, [('output_image', 'moving_image')]),
        (init_aff, norm, [('output_transform', 'initial_moving_transform')]),
        (norm, map_brainmask, [
            ('reverse_transforms', 'transforms'),
            ('reverse_invert_flags', 'invert_transform_flags')]),
        (map_brainmask, thr_brainmask, [('output_image', 'input_image')]),
        (thr_brainmask, dil_brainmask, [('output_image', 'op1')]),
        (dil_brainmask, get_brainmask, [('output_image', 'op1')]),
        (inu_n4_final, apply_mask, [('output_image', 'in_file')]),
        (get_brainmask, apply_mask, [('output_image', 'mask_file')]),
        (get_brainmask, copy_xform, [('output_image', 'out_mask')]),
        (apply_mask, copy_xform, [('out_file', 'out_file')]),
        (inu_n4_final, copy_xform, [('output_image', 'bias_corrected'),
                                    ('bias_image', 'bias_image')]),
        (copy_xform, outputnode, [
            ('out_file', 'out_file'),
            ('out_mask', 'out_mask'),
            ('bias_corrected', 'bias_corrected'),
            ('bias_image', 'bias_image')]),
    ])

    if use_laplacian:
        lap_tmpl = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'),
                           name='lap_tmpl')
        lap_tmpl.inputs.op1 = tpl_target_path
        lap_target = pe.Node(ImageMath(operation='Laplacian', op2='1.5 1'),
                             name='lap_target')
        mrg_tmpl = pe.Node(niu.Merge(2), name='mrg_tmpl')
        mrg_tmpl.inputs.in1 = tpl_target_path
        mrg_target = pe.Node(niu.Merge(2), name='mrg_target')
        wf.connect([
            (inu_n4, lap_target, [
                (('output_image', _pop), 'op1')]),
            (lap_tmpl, mrg_tmpl, [('output_image', 'in2')]),
            (inu_n4, mrg_target, [('output_image', 'in1')]),
            (lap_target, mrg_target, [('output_image', 'in2')]),
            (mrg_tmpl, norm, [('out', 'fixed_image')]),
            (mrg_target, norm, [('out', 'moving_image')]),
        ])
    else:
        norm.inputs.fixed_image = tpl_target_path
        wf.connect([
            (inu_n4, norm, [
                (('output_image', _pop), 'moving_image')]),
        ])

    if atropos_refine:
        atropos_model = atropos_model or list(ATROPOS_MODELS[bids_suffix].values())
        atropos_wf = init_atropos_wf(
            use_random_seed=atropos_use_random_seed,
            omp_nthreads=omp_nthreads,
            mem_gb=mem_gb,
            in_segmentation_model=atropos_model,
        )
        sel_wm = pe.Node(niu.Select(index=atropos_model[-1] - 1), name='sel_wm',
                         run_without_submitting=True)

        wf.disconnect([
            (get_brainmask, apply_mask, [('output_image', 'mask_file')]),
            (copy_xform, outputnode, [('out_mask', 'out_mask')]),
        ])
        wf.connect([
            (inu_n4, atropos_wf, [
                ('output_image', 'inputnode.in_files')]),
            (thr_brainmask, atropos_wf, [
                ('output_image', 'inputnode.in_mask')]),
            (get_brainmask, atropos_wf, [
                ('output_image', 'inputnode.in_mask_dilated')]),
            (atropos_wf, sel_wm, [('outputnode.out_tpms', 'inlist')]),
            (sel_wm, inu_n4_final, [('out', 'weight_image')]),
            (atropos_wf, apply_mask, [
                ('outputnode.out_mask', 'mask_file')]),
            (atropos_wf, outputnode, [
                ('outputnode.out_mask', 'out_mask'),
                ('outputnode.out_segm', 'out_segm'),
                ('outputnode.out_tpms', 'out_tpms')]),
        ])
    return wf
Esempio n. 38
0
def compute_iqms(settings, modality='T1w', name='ComputeIQMs'):
    """
    Workflow that actually computes the IQMs

    .. workflow::

        from mriqc.workflows.anatomical import compute_iqms
        wf = compute_iqms(settings={'output_dir': 'out'})

    """
    from .utils import _tofloat
    from ..interfaces.anatomical import Harmonize

    workflow = pe.Workflow(name=name)
    inputnode = pe.Node(niu.IdentityInterface(fields=[
        'in_file', 'in_ras', 'brainmask', 'airmask', 'artmask', 'headmask',
        'rotmask', 'hatmask', 'segmentation', 'inu_corrected', 'in_inu',
        'pvms', 'metadata', 'inverse_composite_transform'
    ]),
                        name='inputnode')
    outputnode = pe.Node(
        niu.IdentityInterface(fields=['out_file', 'noisefit']),
        name='outputnode')

    # Extract metadata
    meta = pe.Node(ReadSidecarJSON(), name='metadata')

    # Add provenance
    addprov = pe.Node(niu.Function(function=_add_provenance),
                      name='provenance')
    addprov.inputs.settings = {
        'testing': settings.get('testing', False),
        'webapi_url': settings.get('webapi_url'),
        'webapi_port': settings.get('webapi_port')
    }

    # AFNI check smoothing
    fwhm_interface = get_fwhmx()

    fwhm = pe.Node(fwhm_interface, name='smoothness')

    # Harmonize
    homog = pe.Node(Harmonize(), name='harmonize')

    # Mortamet's QI2
    getqi2 = pe.Node(ComputeQI2(), name='ComputeQI2')

    # Compute python-coded measures
    measures = pe.Node(StructuralQC(), 'measures')

    # Project MNI segmentation to T1 space
    invt = pe.MapNode(ants.ApplyTransforms(dimension=3,
                                           default_value=0,
                                           interpolation='Linear',
                                           float=True),
                      iterfield=['input_image'],
                      name='MNItpms2t1')
    invt.inputs.input_image = [
        str(p) for p in get_template('MNI152NLin2009cAsym',
                                     suffix='probseg',
                                     resolution=1,
                                     label=['CSF', 'GM', 'WM'])
    ]

    datasink = pe.Node(IQMFileSink(modality=modality,
                                   out_dir=str(settings['output_dir']),
                                   dataset=settings.get(
                                       'dataset_name', 'unknown')),
                       name='datasink',
                       run_without_submitting=True)
    datasink.inputs.modality = modality

    def _getwm(inlist):
        return inlist[-1]

    workflow.connect([
        (inputnode, meta, [('in_file', 'in_file')]),
        (inputnode, datasink, [('in_file', 'in_file')]),
        (meta, datasink, [('subject', 'subject_id'), ('session', 'session_id'),
                          ('task', 'task_id'), ('acquisition', 'acq_id'),
                          ('reconstruction', 'rec_id'), ('run', 'run_id'),
                          ('out_dict', 'metadata')]),
        (inputnode, addprov, [('in_file', 'in_file'), ('airmask', 'air_msk'),
                              ('rotmask', 'rot_msk')]),
        (inputnode, getqi2, [('in_ras', 'in_file'), ('hatmask', 'air_msk')]),
        (inputnode, homog, [('inu_corrected', 'in_file'),
                            (('pvms', _getwm), 'wm_mask')]),
        (inputnode, measures, [('in_inu', 'in_bias'), ('in_ras', 'in_file'),
                               ('airmask', 'air_msk'),
                               ('headmask', 'head_msk'),
                               ('artmask', 'artifact_msk'),
                               ('rotmask', 'rot_msk'),
                               ('segmentation', 'in_segm'),
                               ('pvms', 'in_pvms')]),
        (inputnode, fwhm, [('in_ras', 'in_file'), ('brainmask', 'mask')]),
        (inputnode, invt, [('in_ras', 'reference_image'),
                           ('inverse_composite_transform', 'transforms')]),
        (homog, measures, [('out_file', 'in_noinu')]),
        (invt, measures, [('output_image', 'mni_tpms')]),
        (fwhm, measures, [(('fwhm', _tofloat), 'in_fwhm')]),
        (measures, datasink, [('out_qc', 'root')]),
        (addprov, datasink, [('out', 'provenance')]),
        (getqi2, datasink, [('qi2', 'qi_2')]),
        (getqi2, outputnode, [('out_file', 'noisefit')]),
        (datasink, outputnode, [('out_file', 'out_file')]),
    ])
    return workflow
Esempio n. 39
0
def init_ica_aroma_components_wf(workdir=None,
                                 name="ica_aroma_components_wf",
                                 memcalc=MemoryCalculator()):
    """

    """
    workflow = pe.Workflow(name=name)

    strfields = ["bold_file", "bold_mask", "itk_bold_to_t1", "out_warp"]
    inputnode = pe.Node(Exec(fieldtpls=[
        ("tags", None),
        ("anat2std_xfm", None),
        *[(field, "firststr") for field in strfields],
        ("bold_split", None),
        ("repetition_time", None),
        ("skip_vols", None),
        ("movpar_file", None),
        ("xforms", None),
        ("std_dseg", "ravel"),
    ]),
                        name="inputnode",
                        run_without_submitting=True)
    outputnode = pe.Node(
        niu.IdentityInterface(fields=[
            "aroma_noise_ics", "melodic_mix", "aroma_metadata", "aromavals"
        ]),
        name="outputnode",
    )

    #
    make_resultdicts = pe.Node(MakeResultdicts(reportkeys=["ica_aroma"]),
                               name="make_resultdicts",
                               run_without_submitting=True)
    workflow.connect(inputnode, "tags", make_resultdicts, "tags")

    #
    resultdict_datasink = pe.Node(ResultdictDatasink(base_directory=workdir),
                                  name="resultdict_datasink",
                                  run_without_submitting=True)
    workflow.connect(make_resultdicts, "resultdicts", resultdict_datasink,
                     "indicts")

    #
    mergexfm = pe.Node(niu.Merge(numinputs=2),
                       name="mergexfm",
                       run_without_submitting=True)
    workflow.connect(inputnode, "anat2std_xfm", mergexfm, "in1")
    mergexfm.inputs.in2 = getresource(
        f"tpl_MNI152NLin6Asym_from_{constants.reference_space}_mode_image_xfm.h5"
    )

    compxfm = pe.Node(
        ApplyTransforms(
            dimension=3,
            print_out_composite_warp_file=True,
            output_image="ants_t1_to_mniComposite.nii.gz",
        ),
        name="compxfm",
    )
    compxfm.inputs.reference_image = firststr(
        get_template("MNI152NLin6Asym", resolution=1, suffix="T1w"))
    workflow.connect(mergexfm, "out", compxfm, "transforms")

    compxfmlist = pe.Node(niu.Merge(1),
                          name="compxfmlist",
                          run_without_submitting=True)
    workflow.connect(compxfm, "output_image", compxfmlist, "in1")

    #
    bold_std_trans_wf = init_bold_std_trans_wf(
        freesurfer=False,
        mem_gb=memcalc.series_std_gb,
        omp_nthreads=config.nipype.omp_nthreads,
        spaces=spaces,
        name="bold_std_trans_wf",
        use_compression=not config.execution.low_mem,
    )

    bold_std_trans_wf_inputnode = bold_std_trans_wf.get_node("inputnode")
    bold_std_trans_wf_inputnode.inputs.templates = ["MNI152NLin6Asym"]

    workflow.connect(compxfmlist, "out", bold_std_trans_wf,
                     "inputnode.anat2std_xfm")
    workflow.connect(inputnode, "bold_file", bold_std_trans_wf,
                     "inputnode.name_source")
    workflow.connect(inputnode, "bold_split", bold_std_trans_wf,
                     "inputnode.bold_split")
    workflow.connect(inputnode, "xforms", bold_std_trans_wf,
                     "inputnode.hmc_xforms")
    workflow.connect(inputnode, "itk_bold_to_t1", bold_std_trans_wf,
                     "inputnode.itk_bold_to_t1")
    workflow.connect(inputnode, "bold_mask", bold_std_trans_wf,
                     "inputnode.bold_mask")
    workflow.connect(inputnode, "out_warp", bold_std_trans_wf,
                     "inputnode.fieldwarp")

    #
    ica_aroma_wf = init_ica_aroma_wf(
        mem_gb=memcalc.series_std_gb,
        metadata={"RepetitionTime": np.nan},
        omp_nthreads=config.nipype.omp_nthreads,
        err_on_aroma_warn=config.workflow.aroma_err_on_warn,
        aroma_melodic_dim=config.workflow.aroma_melodic_dim,
        name="ica_aroma_wf",
    )
    ica_aroma_wf.get_node("ica_aroma").inputs.denoise_type = "no"

    add_nonsteady = ica_aroma_wf.get_node("add_nonsteady")
    ds_report_ica_aroma = ica_aroma_wf.get_node("ds_report_ica_aroma")
    ica_aroma_wf.remove_nodes([add_nonsteady, ds_report_ica_aroma])

    workflow.connect(inputnode, "repetition_time", ica_aroma_wf,
                     "melodic.tr_sec")
    workflow.connect(inputnode, "repetition_time", ica_aroma_wf,
                     "ica_aroma.TR")
    workflow.connect(inputnode, "movpar_file", ica_aroma_wf,
                     "inputnode.movpar_file")
    workflow.connect(inputnode, "skip_vols", ica_aroma_wf,
                     "inputnode.skip_vols")

    workflow.connect(bold_std_trans_wf, "outputnode.bold_std", ica_aroma_wf,
                     "inputnode.bold_std")
    workflow.connect(bold_std_trans_wf, "outputnode.bold_mask_std",
                     ica_aroma_wf, "inputnode.bold_mask_std")
    workflow.connect(
        bold_std_trans_wf,
        "outputnode.spatial_reference",
        ica_aroma_wf,
        "inputnode.spatial_reference",
    )

    workflow.connect(ica_aroma_wf, "outputnode.aroma_noise_ics", outputnode,
                     "aroma_noise_ics")
    workflow.connect(ica_aroma_wf, "outputnode.melodic_mix", outputnode,
                     "melodic_mix")
    workflow.connect(ica_aroma_wf, "outputnode.aroma_metadata", outputnode,
                     "aroma_metadata")
    workflow.connect(ica_aroma_wf, "ica_aroma.out_report", make_resultdicts,
                     "ica_aroma")

    return workflow
Esempio n. 40
0
    def _get_ants_args(self):
        args = {'moving_image': self.inputs.moving_image,
                'num_threads': self.inputs.num_threads,
                'float': self.inputs.float,
                'terminal_output': 'file',
                'write_composite_transform': True,
                'initial_moving_transform': self.inputs.initial_moving_transform}

        """
        Moving image handling - The following truth table maps out the intended action
        sequence. Future refactoring may more directly encode this.

        moving_mask and lesion_mask are files
        True = file
        False = None

        | moving_mask | explicit_masking | lesion_mask | action
        |-------------|------------------|-------------|-------------------------------------------
        | True        | True             | True        | Update `moving_image` after applying
        |             |                  |             | mask.
        |             |                  |             | Set `moving_image_masks` applying
        |             |                  |             | `create_cfm` with `global_mask=True`.
        |-------------|------------------|-------------|-------------------------------------------
        | True        | True             | False       | Update `moving_image` after applying
        |             |                  |             | mask.
        |-------------|------------------|-------------|-------------------------------------------
        | True        | False            | True        | Set `moving_image_masks` applying
        |             |                  |             | `create_cfm` with `global_mask=False`
        |-------------|------------------|-------------|-------------------------------------------
        | True        | False            | False       | args['moving_image_masks'] = moving_mask
        |-------------|------------------|-------------|-------------------------------------------
        | False       | *                | True        | Set `moving_image_masks` applying
        |             |                  |             | `create_cfm` with `global_mask=True`
        |-------------|------------------|-------------|-------------------------------------------
        | False       | *                | False       | No action
        """
        # If a moving mask is provided...
        if isdefined(self.inputs.moving_mask):
            # If explicit masking is enabled...
            if self.inputs.explicit_masking:
                # Mask the moving image.
                # Do not use a moving mask during registration.
                args['moving_image'] = mask(
                    self.inputs.moving_image,
                    self.inputs.moving_mask,
                    "moving_masked.nii.gz")

            # If explicit masking is disabled...
            else:
                # Use the moving mask during registration.
                # Do not mask the moving image.
                args['moving_image_masks'] = self.inputs.moving_mask

            # If a lesion mask is also provided...
            if isdefined(self.inputs.lesion_mask):
                # Create a cost function mask with the form:
                # [global mask - lesion mask] (if explicit masking is enabled)
                # [moving mask - lesion mask] (if explicit masking is disabled)
                # Use this as the moving mask.
                args['moving_image_masks'] = create_cfm(
                    self.inputs.moving_mask,
                    lesion_mask=self.inputs.lesion_mask,
                    global_mask=self.inputs.explicit_masking)

        # If no moving mask is provided...
        # But a lesion mask *IS* provided...
        elif isdefined(self.inputs.lesion_mask):
            # Create a cost function mask with the form: [global mask - lesion mask]
            # Use this as the moving mask.
            args['moving_image_masks'] = create_cfm(
                self.inputs.moving_image,
                lesion_mask=self.inputs.lesion_mask,
                global_mask=True)

        """
        Reference image handling - The following truth table maps out the intended action
        sequence. Future refactoring may more directly encode this.

        reference_mask and lesion_mask are files
        True = file
        False = None

        | reference_mask | explicit_masking | lesion_mask | action
        |----------------|------------------|-------------|----------------------------------------
        | True           | True             | True        | Update `fixed_image` after applying
        |                |                  |             | mask.
        |                |                  |             | Set `fixed_image_masks` applying
        |                |                  |             | `create_cfm` with `global_mask=True`.
        |----------------|------------------|-------------|----------------------------------------
        | True           | True             | False       | Update `fixed_image` after applying
        |                |                  |             | mask.
        |----------------|------------------|-------------|----------------------------------------
        | True           | False            | True        | Set `fixed_image_masks` applying
        |                |                  |             | `create_cfm` with `global_mask=False`
        |----------------|------------------|-------------|----------------------------------------
        | True           | False            | False       | args['fixed_image_masks'] = fixed_mask
        |----------------|------------------|-------------|----------------------------------------
        | False          | *                | True        | Set `fixed_image_masks` applying
        |                |                  |             | `create_cfm` with `global_mask=True`
        |----------------|------------------|-------------|----------------------------------------
        | False          | *                | False       | No action
        """
        # If a reference image is provided...
        if isdefined(self.inputs.reference_image):
            # Use the reference image as the fixed image.
            args['fixed_image'] = self.inputs.reference_image

            # If a reference mask is provided...
            if isdefined(self.inputs.reference_mask):
                # If explicit masking is enabled...
                if self.inputs.explicit_masking:
                    # Mask the reference image.
                    # Do not use a fixed mask during registration.
                    args['fixed_image'] = mask(
                        self.inputs.reference_image,
                        self.inputs.reference_mask,
                        "fixed_masked.nii.gz")

                    # If a lesion mask is also provided...
                    if isdefined(self.inputs.lesion_mask):
                        # Create a cost function mask with the form: [global mask]
                        # Use this as the fixed mask.
                        args['fixed_image_masks'] = create_cfm(
                            self.inputs.reference_mask,
                            lesion_mask=None,
                            global_mask=True)

                # If a reference mask is provided...
                # But explicit masking is disabled...
                else:
                    # Use the reference mask as the fixed mask during registration.
                    # Do not mask the fixed image.
                    args['fixed_image_masks'] = self.inputs.reference_mask

            # If no reference mask is provided...
            # But a lesion mask *IS* provided ...
            elif isdefined(self.inputs.lesion_mask):
                # Create a cost function mask with the form: [global mask]
                # Use this as the fixed mask
                args['fixed_image_masks'] = create_cfm(
                    self.inputs.reference_image,
                    lesion_mask=None,
                    global_mask=True)

        # If no reference image is provided, fall back to the default template.
        else:
            # Raise an error if the user specifies an unsupported image orientation.
            if self.inputs.orientation == 'LAS':
                raise NotImplementedError

            # Set the template resolution.
            resolution = self.inputs.template_resolution
            # Get the template specified by the user.
            ref_template = get_template(self.inputs.template, resolution=resolution,
                                        desc=None, suffix=self.inputs.reference)
            ref_mask = get_template(self.inputs.template, resolution=resolution,
                                    desc='brain', suffix='mask')

            # Default is explicit masking disabled
            args['fixed_image'] = str(ref_template)
            # Use the template mask as the fixed mask.
            args['fixed_image_masks'] = str(ref_mask)

            # Overwrite defaults if explicit masking
            if self.inputs.explicit_masking:
                # Mask the template image with the template mask.
                args['fixed_image'] = mask(str(ref_template), str(ref_mask),
                                           "fixed_masked.nii.gz")
                # Do not use a fixed mask during registration.
                args.pop('fixed_image_masks', None)

                # If a lesion mask is provided...
                if isdefined(self.inputs.lesion_mask):
                    # Create a cost function mask with the form: [global mask]
                    # Use this as the fixed mask.
                    args['fixed_image_masks'] = create_cfm(
                        str(ref_mask), lesion_mask=None, global_mask=True)

        return args