Source code for macapype.pipelines.register

import shutil

import nipype.interfaces.utility as niu
import nipype.pipeline.engine as pe

import nipype.interfaces.fsl as fsl
import nipype.interfaces.afni as afni
import nipype.interfaces.ants as ants

from ..utils.misc import get_elem
from ..utils.utils_nodes import NodeParams, parse_key

from ..nodes.register import (interative_flirt, NMTSubjectAlign,
                              NMTSubjectAlign2, NwarpApplyPriors,
                              animal_warper)


def create_iterative_register_pipe(
        template_file, template_brain_file, template_mask_file, gm_prob_file,
        wm_prob_file, csf_prob_file, n_iter, name="register_pipe"):
    """
    Registration of template (NMT or other) according to Regis:

    - The iterative FLIRT is between NMT_SS and subject's anat after a quick
    skull-stripping but the anat is more and more refined to corresponds to the
    brain

    - there is also a FNIRT done once, for comparison of the quality of the
    template on the subject's brain

    Not used anymore: corresponds to the IterREGBET provided by Regis in bash
    and wrapped node IterREGBET in nodes/register.py

    #TODO: test if gives the same results as IterREGBET
    """
    register_pipe = pe.Workflow(name=name)

    # creating inputnode
    inputnode = pe.Node(
        niu.IdentityInterface(fields=['anat_file_BET', 'anat_file']),
        name='inputnode')

    # register node
    register = pe.Node(
        niu.Function(input_names=["anat_file", "anat_file_BET",
                                  "template_brain_file",
                                  "template_mask_file", 'n_iter'],
                     output_names=["anat_file_brain", "template_to_anat_file"],
                     function=interative_flirt),
        name="register")

    register.inputs.template_brain_file = template_brain_file
    register.inputs.template_mask_file = template_mask_file
    register.inputs.n_iter = n_iter

    register_pipe.connect(inputnode, 'anat_file', register, 'anat_file')
    register_pipe.connect(inputnode, 'anat_file_BET',
                          register, "anat_file_BET")

    # apply transfo over the 3 tissues:
    # gm
    register_gm = pe.Node(fsl.ApplyXFM(), name="register_gm")

    register_gm.inputs.in_file = gm_prob_file
    register_gm.inputs.apply_xfm = True
    register_gm.inputs.interp = "nearestneighbour"
    register_gm.inputs.output_type = "NIFTI"  # for SPM segment

    register_pipe.connect(register, 'anat_file_brain',
                          register_gm, 'reference')
    register_pipe.connect(register, 'template_to_anat_file',
                          register_gm, "in_matrix_file")

    # wm
    register_wm = pe.Node(fsl.ApplyXFM(), name="register_wm")

    register_wm.inputs.in_file = wm_prob_file
    register_wm.inputs.apply_xfm = True
    register_wm.inputs.interp = "nearestneighbour"
    register_wm.inputs.output_type = "NIFTI"  # for SPM segment

    register_pipe.connect(register, 'anat_file_brain',
                          register_wm, 'reference')
    register_pipe.connect(register, 'template_to_anat_file',
                          register_wm, "in_matrix_file")

    # csf
    register_csf = pe.Node(fsl.ApplyXFM(), name="register_csf")

    register_csf.inputs.in_file = csf_prob_file
    register_csf.inputs.apply_xfm = True
    register_csf.inputs.interp = "nearestneighbour"
    register_csf.inputs.output_type = "NIFTI"  # for SPM segment

    register_pipe.connect(register, 'anat_file_brain',
                          register_csf, 'reference')
    register_pipe.connect(register, 'template_to_anat_file',
                          register_csf, "in_matrix_file")

    def return_list(file1, file2, file3):
        return [file1, file2, file3]

    # merge 3 outputs to a list (...)
    merge_3_files = pe.Node(
        niu.Function(input_names=["file1", "file2", "file3"],
                     output_names=["list3files"],
                     function=return_list),
        name="merge_3_files")

    register_pipe.connect(register_gm, 'out_file', merge_3_files, "file1")
    register_pipe.connect(register_wm, 'out_file', merge_3_files, "file2")
    register_pipe.connect(register_csf, 'out_file', merge_3_files, "file3")

    # same with non linear
    # non linear register between anat and head
    # (FNIRT work directly on head?
    # I thought FLIRT was only skull-stripped brain, is it different? )

    nl_register = pe.Node(fsl.FNIRT(), name="nl_register")
    nl_register.inputs.in_file = template_file

    register_pipe.connect(inputnode, 'anat_file', nl_register, 'ref_file')
    register_pipe.connect(register, 'template_to_anat_file',
                          nl_register, 'affine_file')

    # apply non linear warp to NMT_SS
    nl_apply = pe.Node(fsl.ApplyWarp(), name="nl_apply")
    nl_apply.inputs.in_file = template_brain_file
    register_pipe.connect(inputnode, 'anat_file', nl_apply, 'ref_file')
    register_pipe.connect(nl_register, 'fieldcoeff_file',
                          nl_apply, 'field_file')  # iout from fnirt

    return register_pipe


###############################################################################
[docs]def create_register_NMT_pipe(params_template, params={}, name="register_NMT_pipe", NMT_version="v1.3"): """Description: Register template to anat with the script NMT_subject_align Processing steps: - Bias correction (norm_intensity) - Deoblique (Refit with deoblique option) - NMT_subject_align (see :class:`NMTSubjectAlign \ <macapype.nodes.register.NMTSubjectAlign>` and :class:`NMTSubjectAlign2 \ <macapype.nodes.register.NMTSubjectAlign2>` for explanations) - apply it to tissues list_priors (NwarpApplyPriors and Allineate) Params: - norm_intensity (see `N4BiasFieldCorrection <https://\ nipype.readthedocs.io/en/0.12.1/interfaces/generated/nipype.interfaces\ .ants.segmentation.html#n4biasfieldcorrection>`_ for arguments)) - \ also available as :ref:`indiv_params <indiv_params>` - NMT_version (default = 1.2; 1.3 is also accepted) Inputs: inputnode: T1: T1 file name indiv_params: dict with individuals parameters for some nodes arguments: params_template: dictionary of info about template params: dictionary of node sub-parameters (from a json file) name: pipeline name (default = "register_NMT_pipe") NMT_version: NMT version (default = 1.2); can be overwritten in params json Outputs: norm_intensity.output_image: filled mask after erode align_seg_csf.out_file: csf template tissue in subject space align_seg_gm.out_file: grey matter template tissue in subject space align_seg_wm.out_file: white matter template tissue in subject space """ register_NMT_pipe = pe.Workflow(name=name) # creating inputnode inputnode = pe.Node( niu.IdentityInterface(fields=['T1', 'indiv_params']), name='inputnode') if "NMT_version" in params.keys(): NMT_version = params['NMT_version'] print("*** Overriding NMT_version with params NMT_version: {}".format( params['NMT_version'])) if "norm_intensity" in params.keys(): # N4 intensity normalization over brain norm_intensity = NodeParams(ants.N4BiasFieldCorrection(), params=parse_key(params, "norm_intensity"), name='norm_intensity') register_NMT_pipe.connect(inputnode, 'T1', norm_intensity, "input_image") register_NMT_pipe.connect( inputnode, ('indiv_params', parse_key, "norm_intensity"), norm_intensity, "indiv_params") # deoblique (seems mandatory from NMTSubjectAlign) deoblique = pe.Node(afni.Refit(deoblique=True), name="deoblique") if "norm_intensity" in params.keys(): register_NMT_pipe.connect(norm_intensity, 'output_image', deoblique, "in_file") else: register_NMT_pipe.connect(inputnode, 'T1', deoblique, "in_file") print("which @animal_warper: ", shutil.which("@animal_warper")) if "NMT_subject_align" in params.keys() \ or shutil.which("@animal_warper") is None: print("running NMT_subject_align with version {}".format(NMT_version)) if NMT_version == "v1.2": # align subj to nmt NMT_subject_align = NodeParams( NMTSubjectAlign(), params=parse_key(params, "NMT_subject_align"), name='NMT_subject_align') elif NMT_version == "v1.3" or NMT_version == "v2.0": # align subj to nmt NMT_subject_align = NodeParams( NMTSubjectAlign2(), params=parse_key(params, "NMT_subject_align"), name='NMT_subject_align') else: print("NMT_version {} is not implemented, breaking".format( NMT_version)) exit() elif shutil.which("@animal_warper") is not None: # TODO AnimalWarper() print("running @animal_warper with version {}".format( shutil.which("@animal_warper"))) NMT_subject_align = pe.Node( niu.Function(input_names=["T1_file", "NMT_SS_file"], output_names=["aff_file", "warp_file", "warpinv_file", "transfo_file", "inv_transfo_file"], function=animal_warper), name='NMT_subject_align') else: print("could not find normalisation procedure,\ either with NMT_subject_align, or @animal_warper, breaking") exit() NMT_subject_align.inputs.NMT_SS_file = params_template["template_brain"] register_NMT_pipe.connect(deoblique, 'out_file', NMT_subject_align, "T1_file") if NMT_version.split(".")[0] == "v1": # align_masks # "overwrap" of NwarpApply, with specifying the outputs as wished list_priors = [params_template["template_head"], params_template["template_csf"], params_template["template_gm"], params_template["template_wm"]] elif NMT_version.split(".")[0] == "v2": # align_masks # "overwrap" of NwarpApply, with specifying the outputs as wished list_priors = [params_template["template_head"], params_template["template_seg"]] align_masks = pe.Node(NwarpApplyPriors(), name='align_masks') align_masks.inputs.in_file = list_priors align_masks.inputs.out_file = list_priors align_masks.inputs.interp = "NN" align_masks.inputs.args = "-overwrite" register_NMT_pipe.connect(NMT_subject_align, 'aff_file', align_masks, 'master') register_NMT_pipe.connect(NMT_subject_align, 'warpinv_file', align_masks, "warp") # align_NMT align_NMT = pe.Node( afni.Allineate(), name="align_NMT", iterfield=['in_file']) align_NMT.inputs.final_interpolation = "nearestneighbour" align_NMT.inputs.overwrite = True align_NMT.inputs.outputtype = "NIFTI_GZ" register_NMT_pipe.connect(align_masks, ('out_file', get_elem, 0), align_NMT, "in_file") # -source register_NMT_pipe.connect(deoblique, 'out_file', align_NMT, "reference") # -base register_NMT_pipe.connect(NMT_subject_align, 'inv_transfo_file', align_NMT, "in_matrix") # -1Dmatrix_apply if NMT_version.split(".")[0] == "v1": # seg_csf align_seg_csf = pe.Node( afni.Allineate(), name="align_seg_csf", iterfield=['in_file']) align_seg_csf.inputs.final_interpolation = "nearestneighbour" align_seg_csf.inputs.overwrite = True align_seg_csf.inputs.outputtype = "NIFTI_GZ" register_NMT_pipe.connect(align_masks, ('out_file', get_elem, 1), align_seg_csf, "in_file") # -source register_NMT_pipe.connect(deoblique, 'out_file', align_seg_csf, "reference") # -base register_NMT_pipe.connect( NMT_subject_align, 'inv_transfo_file', align_seg_csf, "in_matrix") # -1Dmatrix_apply # seg_gm align_seg_gm = pe.Node( afni.Allineate(), name="align_seg_gm", iterfield=['in_file']) align_seg_gm.inputs.final_interpolation = "nearestneighbour" align_seg_gm.inputs.overwrite = True align_seg_gm.inputs.outputtype = "NIFTI_GZ" register_NMT_pipe.connect(align_masks, ('out_file', get_elem, 2), align_seg_gm, "in_file") # -source register_NMT_pipe.connect(deoblique, 'out_file', align_seg_gm, "reference") # -base register_NMT_pipe.connect(NMT_subject_align, 'inv_transfo_file', align_seg_gm, "in_matrix") # -1Dmatrix_apply # seg_wm align_seg_wm = pe.Node(afni.Allineate(), name="align_seg_wm", iterfield=['in_file']) align_seg_wm.inputs.final_interpolation = "nearestneighbour" align_seg_wm.inputs.overwrite = True align_seg_wm.inputs.outputtype = "NIFTI_GZ" register_NMT_pipe.connect(align_masks, ('out_file', get_elem, 3), align_seg_wm, "in_file") # -source register_NMT_pipe.connect(deoblique, 'out_file', align_seg_wm, "reference") # -base register_NMT_pipe.connect(NMT_subject_align, 'inv_transfo_file', align_seg_wm, "in_matrix") # -1Dmatrix_apply elif NMT_version.split(".")[0] == "v2": # seg align_seg = pe.Node( afni.Allineate(), name="align_seg", iterfield=['in_file']) align_seg.inputs.final_interpolation = "nearestneighbour" align_seg.inputs.overwrite = True align_seg.inputs.outputtype = "NIFTI_GZ" register_NMT_pipe.connect(align_masks, ('out_file', get_elem, 1), align_seg, "in_file") # -source register_NMT_pipe.connect(deoblique, 'out_file', align_seg, "reference") # -base register_NMT_pipe.connect(NMT_subject_align, 'inv_transfo_file', align_seg, "in_matrix") # -1Dmatrix_apply return register_NMT_pipe
def create_reg_seg_pipe(name="reg_seg_pipe"): reg_pipe = pe.Workflow(name=name) # creating inputnode inputnode = pe.Node( niu.IdentityInterface(fields=['native_seg', 'native_threshold_gm', 'native_threshold_wm', 'native_threshold_csf', 'native_prob_gm', 'native_prob_wm', 'native_prob_csf', 'transfo_file', 'ref_image']), name='inputnode') # align_seg align_seg = pe.Node( afni.Allineate(), name="align_seg", iterfield=['in_file']) align_seg.inputs.final_interpolation = "nearestneighbour" align_seg.inputs.overwrite = True align_seg.inputs.outputtype = "NIFTI_GZ" reg_pipe.connect(inputnode, 'native_seg', align_seg, "in_file") reg_pipe.connect(inputnode, 'ref_image', align_seg, "reference") reg_pipe.connect(inputnode, 'transfo_file', align_seg, "in_matrix") # align_threshold_gm align_threshold_gm = pe.Node( afni.Allineate(), name="align_threshold_gm", iterfield=['in_file']) align_threshold_gm.inputs.final_interpolation = "nearestneighbour" align_threshold_gm.inputs.overwrite = True align_threshold_gm.inputs.outputtype = "NIFTI_GZ" reg_pipe.connect(inputnode, 'native_threshold_gm', align_threshold_gm, "in_file") reg_pipe.connect(inputnode, 'ref_image', align_threshold_gm, "reference") reg_pipe.connect(inputnode, 'transfo_file', align_threshold_gm, "in_matrix") # align_threshold_wm align_threshold_wm = pe.Node( afni.Allineate(), name="align_threshold_wm", iterfield=['in_file']) align_threshold_wm.inputs.final_interpolation = "nearestneighbour" align_threshold_wm.inputs.overwrite = True align_threshold_wm.inputs.outputtype = "NIFTI_GZ" reg_pipe.connect(inputnode, 'native_threshold_wm', align_threshold_wm, "in_file") reg_pipe.connect(inputnode, 'ref_image', align_threshold_wm, "reference") reg_pipe.connect(inputnode, 'transfo_file', align_threshold_wm, "in_matrix") # align_threshold_csf align_threshold_csf = pe.Node( afni.Allineate(), name="align_threshold_csf", iterfield=['in_file']) align_threshold_csf.inputs.final_interpolation = "nearestneighbour" align_threshold_csf.inputs.overwrite = True align_threshold_csf.inputs.outputtype = "NIFTI_GZ" reg_pipe.connect(inputnode, 'native_threshold_csf', align_threshold_csf, "in_file") reg_pipe.connect(inputnode, 'ref_image', align_threshold_csf, "reference") reg_pipe.connect(inputnode, 'transfo_file', align_threshold_csf, "in_matrix") # align_prob_gm align_prob_gm = pe.Node( afni.Allineate(), name="align_prob_gm", iterfield=['in_file']) align_prob_gm.inputs.final_interpolation = "nearestneighbour" align_prob_gm.inputs.overwrite = True align_prob_gm.inputs.outputtype = "NIFTI_GZ" reg_pipe.connect(inputnode, 'native_prob_gm', align_prob_gm, "in_file") reg_pipe.connect(inputnode, 'ref_image', align_prob_gm, "reference") reg_pipe.connect(inputnode, 'transfo_file', align_prob_gm, "in_matrix") # align_prob_wm align_prob_wm = pe.Node( afni.Allineate(), name="align_prob_wm", iterfield=['in_file']) align_prob_wm.inputs.final_interpolation = "nearestneighbour" align_prob_wm.inputs.overwrite = True align_prob_wm.inputs.outputtype = "NIFTI_GZ" reg_pipe.connect(inputnode, 'native_prob_wm', align_prob_wm, "in_file") reg_pipe.connect(inputnode, 'ref_image', align_prob_wm, "reference") reg_pipe.connect(inputnode, 'transfo_file', align_prob_wm, "in_matrix") # align_prob_csf align_prob_csf = pe.Node( afni.Allineate(), name="align_prob_csf", iterfield=['in_file']) align_prob_csf.inputs.final_interpolation = "nearestneighbour" align_prob_csf.inputs.overwrite = True align_prob_csf.inputs.outputtype = "NIFTI_GZ" reg_pipe.connect(inputnode, 'native_prob_csf', align_prob_csf, "in_file") reg_pipe.connect(inputnode, 'ref_image', align_prob_csf, "reference") reg_pipe.connect(inputnode, 'transfo_file', align_prob_csf, "in_matrix") outputnode = pe.Node( niu.IdentityInterface(fields=['norm_seg', 'norm_threshold_gm', 'norm_threshold_wm', 'norm_threshold_csf', 'norm_prob_gm', 'norm_prob_wm', 'norm_prob_csf']), name='outputnode') reg_pipe.connect(align_seg, 'out_file', outputnode, "norm_seg") reg_pipe.connect(align_threshold_gm, 'out_file', outputnode, "norm_threshold_gm") reg_pipe.connect(align_threshold_wm, 'out_file', outputnode, "norm_threshold_wm") reg_pipe.connect(align_threshold_csf, 'out_file', outputnode, "norm_threshold_csf") reg_pipe.connect(align_prob_gm, 'out_file', outputnode, "norm_prob_gm") reg_pipe.connect(align_prob_wm, 'out_file', outputnode, "norm_prob_wm") reg_pipe.connect(align_prob_csf, 'out_file', outputnode, "norm_prob_csf") return reg_pipe