def test_RobustMNINormalizationRPT_masked(self): """ the RobustMNINormalizationRPT report capable test with masking """ ants_rpt = RobustMNINormalizationRPT( generate_report=True, moving_image=self.moving, reference_mask=self.reference_mask, testing=True) _smoke_test_report(ants_rpt, 'testRobustMNINormalizationRPT_masked.svg')
def test_RobustMNINormalizationRPT(monkeypatch, moving): """ the RobustMNINormalizationRPT report capable test """ def _agg(objekt, runtime): outputs = Bunch(warped_image=os.path.join( datadir, 'testRobustMNINormalizationRPTMovingWarpedImage.nii.gz')) return outputs # Patch the _run_interface method monkeypatch.setattr(RobustMNINormalizationRPT, '_run_interface', _run_interface_mock) monkeypatch.setattr(RobustMNINormalizationRPT, 'aggregate_outputs', _agg) ants_rpt = RobustMNINormalizationRPT(generate_report=True, moving_image=moving, flavor='testing') _smoke_test_report(ants_rpt, 'testRobustMNINormalizationRPT.svg')
def test_RobustMNINormalizationRPT(monkeypatch, moving): """ the RobustMNINormalizationRPT report capable test """ def _agg(objekt, runtime): outputs = objekt.output_spec() outputs.warped_image = os.path.join( datadir, "testRobustMNINormalizationRPTMovingWarpedImage.nii.gz") outputs.out_report = os.path.join(runtime.cwd, objekt.inputs.out_report) return outputs # Patch the _run_interface method monkeypatch.setattr(RobustMNINormalizationRPT, "_run_interface", _run_interface_mock) monkeypatch.setattr(RobustMNINormalizationRPT, "aggregate_outputs", _agg) ants_rpt = RobustMNINormalizationRPT(generate_report=True, moving_image=moving, flavor="testing") _smoke_test_report(ants_rpt, "testRobustMNINormalizationRPT.svg")
def test_RobustMNINormalizationRPT_masked(monkeypatch, moving, reference_mask): """ the RobustMNINormalizationRPT report capable test with masking """ def _agg(objekt, runtime): outputs = objekt.output_spec() outputs.warped_image = os.path.join( datadir, 'testRobustMNINormalizationRPTMovingWarpedImage.nii.gz') outputs.out_report = os.path.join(runtime.cwd, objekt.inputs.out_report) return outputs # Patch the _run_interface method monkeypatch.setattr(RobustMNINormalizationRPT, '_run_interface', _run_interface_mock) monkeypatch.setattr(RobustMNINormalizationRPT, 'aggregate_outputs', _agg) ants_rpt = RobustMNINormalizationRPT(generate_report=True, moving_image=moving, reference_mask=reference_mask, flavor='testing') _smoke_test_report(ants_rpt, 'testRobustMNINormalizationRPT_masked.svg')
def init_anat_preproc_wf(skull_strip_ants, skull_strip_template, output_spaces, template, debug, freesurfer, omp_nthreads, hires, reportlets_dir, output_dir, name='anat_preproc_wf'): """T1w images preprocessing pipeline""" workflow = pe.Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=['t1w', 't2w', 'subjects_dir']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=[ 't1_preproc', 't1_brain', 't1_mask', 't1_seg', 't1_tpms', 't1_2_mni', 't1_2_mni_forward_transform', 't1_2_mni_reverse_transform', 'mni_mask', 'mni_seg', 'mni_tpms', 'subjects_dir', 'subject_id', 'fs_2_t1_transform', 'surfaces' ]), name='outputnode') def bidsinfo(in_file): from fmriprep.interfaces.bids import BIDS_NAME match = BIDS_NAME.search(in_file) params = match.groupdict() if match is not None else {} return tuple( map(params.get, [ 'subject_id', 'ses_id', 'task_id', 'acq_id', 'rec_id', 'run_id' ])) bids_info = pe.Node(niu.Function(function=bidsinfo, output_names=[ 'subject_id', 'ses_id', 'task_id', 'acq_id', 'rec_id', 'run_id' ]), name='bids_info', run_without_submitting=True) summary = pe.Node(AnatomicalSummary(output_spaces=output_spaces, template=template), name='summary') # 0. Reorient T1w image(s) to RAS and resample to common voxel space t1_conform = pe.Node(ConformSeries(), name='t1_conform') # 1. Align and merge if several T1w images are provided t1_merge = pe.Node( # StructuralReference is fs.RobustTemplate if > 1 volume, copying otherwise StructuralReference( auto_detect_sensitivity=True, initial_timepoint=1, fixed_timepoint=True, # Align to first image intensity_scaling=True, # 7-DOF (rigid + intensity) no_iteration=True, subsample_threshold=200, ), name='t1_merge') # 2. T1 Bias Field Correction # Bias field correction is handled in skull strip workflows. # 3. Skull-stripping #skullstrip_wf = init_skullstrip_afni_wf(name='skullstrip_afni_wf') skullstrip_wf = init_skullstrip_watershed_wf( name='skullstrip_watershed_wf') if skull_strip_ants: skullstrip_wf = init_skullstrip_ants_wf( name='skullstrip_ants_wf', debug=debug, omp_nthreads=omp_nthreads, skull_strip_template=skull_strip_template) # 4. Segmentation t1_seg = pe.Node(FASTRPT(generate_report=True, segments=True, no_bias=True, probability_maps=True), name='t1_seg') # 5. Spatial normalization (T1w to MNI registration) t1_2_mni = pe.Node(RobustMNINormalizationRPT( generate_report=True, num_threads=omp_nthreads, flavor='testing' if debug else 'precise', ), name='t1_2_mni') # should not be necessary but does not hurt - make sure the multiproc # scheduler knows the resource limits t1_2_mni.interface.num_threads = omp_nthreads # Resample the brain mask and the tissue probability maps into mni space mni_mask = pe.Node(ants.ApplyTransforms(dimension=3, default_value=0, float=True, interpolation='NearestNeighbor'), name='mni_mask') mni_seg = pe.Node(ants.ApplyTransforms(dimension=3, default_value=0, float=True, interpolation='NearestNeighbor'), name='mni_seg') mni_tpms = pe.MapNode(ants.ApplyTransforms(dimension=3, default_value=0, float=True, interpolation='Linear'), iterfield=['input_image'], name='mni_tpms') workflow.connect([ (inputnode, bids_info, [(('t1w', fix_multi_T1w_source_name), 'in_file') ]), (inputnode, t1_conform, [('t1w', 't1w_list')]), (t1_conform, t1_merge, [('t1w_list', 'in_files'), (('t1w_list', add_suffix, '_template'), 'out_file')]), (t1_merge, skullstrip_wf, [('out_file', 'inputnode.in_file')]), (skullstrip_wf, t1_seg, [('outputnode.out_file', 'in_files')]), (skullstrip_wf, outputnode, [('outputnode.bias_corrected', 't1_preproc'), ('outputnode.out_file', 't1_brain'), ('outputnode.out_mask', 't1_mask')]), (t1_seg, outputnode, [('tissue_class_map', 't1_seg'), ('probability_maps', 't1_tpms')]), (inputnode, summary, [('t1w', 't1w')]), ]) if 'template' in output_spaces: template_str = nid.TEMPLATE_MAP[template] ref_img = op.join(nid.get_dataset(template_str), '1mm_T1.nii.gz') t1_2_mni.inputs.template = template_str mni_mask.inputs.reference_image = ref_img mni_seg.inputs.reference_image = ref_img mni_tpms.inputs.reference_image = ref_img workflow.connect([ (skullstrip_wf, t1_2_mni, [('outputnode.bias_corrected', 'moving_image')]), (skullstrip_wf, t1_2_mni, [('outputnode.out_mask', 'moving_mask') ]), (skullstrip_wf, mni_mask, [('outputnode.out_mask', 'input_image') ]), (t1_2_mni, mni_mask, [('composite_transform', 'transforms')]), (t1_seg, mni_seg, [('tissue_class_map', 'input_image')]), (t1_2_mni, mni_seg, [('composite_transform', 'transforms')]), (t1_seg, mni_tpms, [('probability_maps', 'input_image')]), (t1_2_mni, mni_tpms, [('composite_transform', 'transforms')]), (t1_2_mni, outputnode, [('warped_image', 't1_2_mni'), ('composite_transform', 't1_2_mni_forward_transform'), ('inverse_composite_transform', 't1_2_mni_reverse_transform')]), (mni_mask, outputnode, [('output_image', 'mni_mask')]), (mni_seg, outputnode, [('output_image', 'mni_seg')]), (mni_tpms, outputnode, [('output_image', 'mni_tpms')]), ]) # 6. FreeSurfer reconstruction if freesurfer: surface_recon_wf = init_surface_recon_wf(name='surface_recon_wf', omp_nthreads=omp_nthreads, hires=hires) workflow.connect([ (inputnode, summary, [('subjects_dir', 'subjects_dir')]), (bids_info, summary, [('subject_id', 'subject_id')]), (inputnode, surface_recon_wf, [('t2w', 'inputnode.t2w'), ('subjects_dir', 'inputnode.subjects_dir')]), (summary, surface_recon_wf, [('subject_id', 'inputnode.subject_id') ]), (t1_merge, surface_recon_wf, [('out_file', 'inputnode.t1w')]), (skullstrip_wf, surface_recon_wf, [('outputnode.out_file', 'inputnode.skullstripped_t1')]), (surface_recon_wf, outputnode, [('outputnode.subjects_dir', 'subjects_dir'), ('outputnode.subject_id', 'subject_id'), ('outputnode.fs_2_t1_transform', 'fs_2_t1_transform'), ('outputnode.surfaces', 'surfaces')]), ]) anat_reports_wf = init_anat_reports_wf(reportlets_dir=reportlets_dir, skull_strip_ants=skull_strip_ants, output_spaces=output_spaces, template=template, freesurfer=freesurfer) workflow.connect([ (inputnode, anat_reports_wf, [(('t1w', fix_multi_T1w_source_name), 'inputnode.source_file')]), (t1_seg, anat_reports_wf, [('out_report', 'inputnode.t1_seg_report')]), (summary, anat_reports_wf, [('out_report', 'inputnode.summary_report') ]), ]) if skull_strip_ants: workflow.connect([(skullstrip_wf, anat_reports_wf, [ ('outputnode.out_report', 'inputnode.t1_skull_strip_report') ])]) if freesurfer: workflow.connect([(surface_recon_wf, anat_reports_wf, [ ('outputnode.out_report', 'inputnode.recon_report') ])]) if 'template' in output_spaces: workflow.connect([ (t1_2_mni, anat_reports_wf, [('out_report', 'inputnode.t1_2_mni_report')]), ]) anat_derivatives_wf = init_anat_derivatives_wf(output_dir=output_dir, output_spaces=output_spaces, template=template, freesurfer=freesurfer) workflow.connect([ (inputnode, anat_derivatives_wf, [(('t1w', fix_multi_T1w_source_name), 'inputnode.source_file')]), (outputnode, anat_derivatives_wf, [ ('t1_preproc', 'inputnode.t1_preproc'), ('t1_mask', 'inputnode.t1_mask'), ('t1_seg', 'inputnode.t1_seg'), ('t1_tpms', 'inputnode.t1_tpms'), ('t1_2_mni_forward_transform', 'inputnode.t1_2_mni_forward_transform'), ('t1_2_mni', 'inputnode.t1_2_mni'), ('mni_mask', 'inputnode.mni_mask'), ('mni_seg', 'inputnode.mni_seg'), ('mni_tpms', 'inputnode.mni_tpms'), ('surfaces', 'inputnode.surfaces'), ]), ]) return workflow
def test_RobustMNINormalizationRPT(self): """ the RobustMNINormalizationRPT report capable test """ ants_rpt = RobustMNINormalizationRPT(generate_report=True, moving_image=self.moving, testing=True) _smoke_test_report(ants_rpt, 'testRobustMNINormalizationRPT.svg')
def init_anat_preproc_wf(skull_strip_ants, output_spaces, template, debug, freesurfer, longitudinal, omp_nthreads, hires, reportlets_dir, output_dir, name='anat_preproc_wf'): r""" This workflow controls the anatomical preprocessing stages of FMRIPREP. This includes: - Creation of a structural template - Skull-stripping and bias correction - Tissue segmentation - Normalization - Surface reconstruction with FreeSurfer .. workflow:: :graph2use: orig :simple_form: yes from fmriprep.workflows.anatomical import init_anat_preproc_wf wf = init_anat_preproc_wf(omp_nthreads=1, reportlets_dir='.', output_dir='.', template='MNI152NLin2009cAsym', output_spaces=['T1w', 'fsnative', 'template', 'fsaverage5'], skull_strip_ants=True, freesurfer=True, longitudinal=False, debug=False, hires=True) **Parameters** skull_strip_ants : bool Use ANTs BrainExtraction.sh-based skull-stripping workflow. If ``False``, uses a faster AFNI-based workflow output_spaces : list List of output spaces functional images are to be resampled to. Some pipeline components will only be instantiated for some output spaces. Valid spaces: - T1w - template - fsnative - fsaverage (or other pre-existing FreeSurfer templates) template : str Name of template targeted by `'template'` output space debug : bool Enable debugging outputs freesurfer : bool Enable FreeSurfer surface reconstruction (may increase runtime) longitudinal : bool Create unbiased structural template, regardless of number of inputs (may increase runtime) omp_nthreads : int Maximum number of threads an individual process may use hires : bool Enable sub-millimeter preprocessing in FreeSurfer reportlets_dir : str Directory in which to save reportlets output_dir : str Directory in which to save derivatives name : str, optional Workflow name (default: anat_preproc_wf) **Inputs** t1w List of T1-weighted structural images t2w List of T2-weighted structural images subjects_dir FreeSurfer SUBJECTS_DIR **Outputs** t1_preproc Bias-corrected structural template, defining T1w space t1_brain Skull-stripped ``t1_preproc`` t1_mask Mask of the skull-stripped template image t1_seg Segmentation of preprocessed structural image, including gray-matter (GM), white-matter (WM) and cerebrospinal fluid (CSF) t1_tpms List of tissue probability maps in T1w space t1_2_mni T1w template, normalized to MNI space t1_2_mni_forward_transform ANTs-compatible affine-and-warp transform file t1_2_mni_reverse_transform ANTs-compatible affine-and-warp transform file (inverse) mni_mask Mask of skull-stripped template, in MNI space mni_seg Segmentation, resampled into MNI space mni_tpms List of tissue probability maps in MNI space subjects_dir FreeSurfer SUBJECTS_DIR subject_id FreeSurfer subject ID fs_2_t1_transform Affine transform from FreeSurfer subject space to T1w space surfaces GIFTI surfaces (gray/white boundary, midthickness, pial, inflated) **Subworkflows** * :py:func:`~fmriprep.workflows.anatomical.init_skullstrip_ants_wf` * :py:func:`~fmriprep.workflows.anatomical.init_surface_recon_wf` """ workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface( fields=['t1w', 't2w', 'subjects_dir', 'subject_id']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=[ 't1_preproc', 't1_brain', 't1_mask', 't1_seg', 't1_tpms', 't1_2_mni', 't1_2_mni_forward_transform', 't1_2_mni_reverse_transform', 'mni_mask', 'mni_seg', 'mni_tpms', 'subjects_dir', 'subject_id', 'fs_2_t1_transform', 'surfaces' ]), name='outputnode') # 0. Reorient T1w image(s) to RAS and resample to common voxel space t1_template_dimensions = pe.Node(TemplateDimensions(), name='t1_template_dimensions') t1_conform = pe.MapNode(Conform(), iterfield='in_file', name='t1_conform') # 1. Align and merge if several T1w images are provided t1_merge = pe.Node( # StructuralReference is fs.RobustTemplate if > 1 volume, copying otherwise StructuralReference( auto_detect_sensitivity=True, initial_timepoint=1, # For deterministic behavior intensity_scaling=True, # 7-DOF (rigid + intensity) subsample_threshold=200, ), name='t1_merge') # 1.5 Reorient template to RAS, if needed (mri_robust_template sets LIA) t1_reorient = pe.Node(Reorient(), name='t1_reorient') # 2. T1 Bias Field Correction # Bias field correction is handled in skull strip workflows. # 3. Skull-stripping skullstrip_wf = init_skullstrip_afni_wf(name='skullstrip_afni_wf') if skull_strip_ants: skullstrip_wf = init_skullstrip_ants_wf(name='skullstrip_ants_wf', debug=debug, omp_nthreads=omp_nthreads) # 4. Segmentation t1_seg = pe.Node(FASTRPT(generate_report=True, segments=True, no_bias=True, probability_maps=True), name='t1_seg', mem_gb=3) # 5. Spatial normalization (T1w to MNI registration) t1_2_mni = pe.Node(RobustMNINormalizationRPT( float=True, generate_report=True, num_threads=omp_nthreads, flavor='testing' if debug else 'precise', ), name='t1_2_mni', n_procs=omp_nthreads) # Resample the brain mask and the tissue probability maps into mni space mni_mask = pe.Node(ants.ApplyTransforms(dimension=3, default_value=0, float=True, interpolation='NearestNeighbor'), name='mni_mask') mni_seg = pe.Node(ants.ApplyTransforms(dimension=3, default_value=0, float=True, interpolation='NearestNeighbor'), name='mni_seg') mni_tpms = pe.MapNode(ants.ApplyTransforms(dimension=3, default_value=0, float=True, interpolation='Linear'), iterfield=['input_image'], name='mni_tpms') def set_threads(in_list, maximum): return min(len(in_list), maximum) def len_above_thresh(in_list, threshold, longitudinal): if longitudinal: return False return len(in_list) > threshold workflow.connect([ (inputnode, t1_template_dimensions, [('t1w', 't1w_list')]), (t1_template_dimensions, t1_conform, [('t1w_valid_list', 'in_file'), ('target_zooms', 'target_zooms'), ('target_shape', 'target_shape') ]), (t1_conform, t1_merge, [('out_file', 'in_files'), (('out_file', set_threads, omp_nthreads), 'num_threads'), (('out_file', len_above_thresh, 2, longitudinal), 'fixed_timepoint'), (('out_file', len_above_thresh, 2, longitudinal), 'no_iteration'), (('out_file', add_suffix, '_template'), 'out_file')]), (t1_merge, t1_reorient, [('out_file', 'in_file')]), (t1_reorient, skullstrip_wf, [('out_file', 'inputnode.in_file')]), (skullstrip_wf, t1_seg, [('outputnode.out_file', 'in_files')]), (skullstrip_wf, outputnode, [('outputnode.bias_corrected', 't1_preproc'), ('outputnode.out_file', 't1_brain'), ('outputnode.out_mask', 't1_mask')]), (t1_seg, outputnode, [('tissue_class_map', 't1_seg'), ('probability_maps', 't1_tpms')]), ]) if 'template' in output_spaces: template_str = nid.TEMPLATE_MAP[template] ref_img = op.join(nid.get_dataset(template_str), '1mm_T1.nii.gz') t1_2_mni.inputs.template = template_str mni_mask.inputs.reference_image = ref_img mni_seg.inputs.reference_image = ref_img mni_tpms.inputs.reference_image = ref_img workflow.connect([ (skullstrip_wf, t1_2_mni, [('outputnode.bias_corrected', 'moving_image')]), (skullstrip_wf, t1_2_mni, [('outputnode.out_mask', 'moving_mask') ]), (skullstrip_wf, mni_mask, [('outputnode.out_mask', 'input_image') ]), (t1_2_mni, mni_mask, [('composite_transform', 'transforms')]), (t1_seg, mni_seg, [('tissue_class_map', 'input_image')]), (t1_2_mni, mni_seg, [('composite_transform', 'transforms')]), (t1_seg, mni_tpms, [('probability_maps', 'input_image')]), (t1_2_mni, mni_tpms, [('composite_transform', 'transforms')]), (t1_2_mni, outputnode, [('warped_image', 't1_2_mni'), ('composite_transform', 't1_2_mni_forward_transform'), ('inverse_composite_transform', 't1_2_mni_reverse_transform')]), (mni_mask, outputnode, [('output_image', 'mni_mask')]), (mni_seg, outputnode, [('output_image', 'mni_seg')]), (mni_tpms, outputnode, [('output_image', 'mni_tpms')]), ]) # 6. FreeSurfer reconstruction if freesurfer: surface_recon_wf = init_surface_recon_wf(name='surface_recon_wf', omp_nthreads=omp_nthreads, hires=hires) workflow.connect([ (inputnode, surface_recon_wf, [('t2w', 'inputnode.t2w'), ('subjects_dir', 'inputnode.subjects_dir'), ('subject_id', 'inputnode.subject_id')]), (t1_reorient, surface_recon_wf, [('out_file', 'inputnode.t1w')]), (skullstrip_wf, surface_recon_wf, [('outputnode.out_file', 'inputnode.skullstripped_t1')]), (surface_recon_wf, outputnode, [('outputnode.subjects_dir', 'subjects_dir'), ('outputnode.subject_id', 'subject_id'), ('outputnode.fs_2_t1_transform', 'fs_2_t1_transform'), ('outputnode.surfaces', 'surfaces')]), ]) anat_reports_wf = init_anat_reports_wf(reportlets_dir=reportlets_dir, skull_strip_ants=skull_strip_ants, output_spaces=output_spaces, template=template, freesurfer=freesurfer) workflow.connect([ (inputnode, anat_reports_wf, [(('t1w', fix_multi_T1w_source_name), 'inputnode.source_file')]), (t1_template_dimensions, anat_reports_wf, [('out_report', 'inputnode.t1_conform_report')]), (t1_seg, anat_reports_wf, [('out_report', 'inputnode.t1_seg_report')]), ]) if skull_strip_ants: workflow.connect([(skullstrip_wf, anat_reports_wf, [ ('outputnode.out_report', 'inputnode.t1_skull_strip_report') ])]) if freesurfer: workflow.connect([(surface_recon_wf, anat_reports_wf, [ ('outputnode.out_report', 'inputnode.recon_report') ])]) if 'template' in output_spaces: workflow.connect([ (t1_2_mni, anat_reports_wf, [('out_report', 'inputnode.t1_2_mni_report')]), ]) anat_derivatives_wf = init_anat_derivatives_wf(output_dir=output_dir, output_spaces=output_spaces, template=template, freesurfer=freesurfer) workflow.connect([ (inputnode, anat_derivatives_wf, [(('t1w', fix_multi_T1w_source_name), 'inputnode.source_file')]), (outputnode, anat_derivatives_wf, [ ('t1_preproc', 'inputnode.t1_preproc'), ('t1_mask', 'inputnode.t1_mask'), ('t1_seg', 'inputnode.t1_seg'), ('t1_tpms', 'inputnode.t1_tpms'), ('t1_2_mni_forward_transform', 'inputnode.t1_2_mni_forward_transform'), ('t1_2_mni', 'inputnode.t1_2_mni'), ('mni_mask', 'inputnode.mni_mask'), ('mni_seg', 'inputnode.mni_seg'), ('mni_tpms', 'inputnode.mni_tpms'), ('surfaces', 'inputnode.surfaces'), ]), ]) return workflow
def init_anat_preproc_wf(skull_strip_ants, output_spaces, template, debug, freesurfer, longitudinal, omp_nthreads, hires, reportlets_dir, output_dir, name='anat_preproc_wf'): """T1w images preprocessing pipeline""" workflow = pe.Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=['t1w', 't2w', 'subjects_dir', 'subject_id']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['t1_preproc', 't1_brain', 't1_mask', 't1_seg', 't1_tpms', 't1_2_mni', 't1_2_mni_forward_transform', 't1_2_mni_reverse_transform', 'mni_mask', 'mni_seg', 'mni_tpms', 'subjects_dir', 'subject_id', 'fs_2_t1_transform', 'surfaces']), name='outputnode') # 0. Reorient T1w image(s) to RAS and resample to common voxel space t1_conform = pe.Node(ConformSeries(), name='t1_conform') # 1. Align and merge if several T1w images are provided t1_merge = pe.Node( # StructuralReference is fs.RobustTemplate if > 1 volume, copying otherwise StructuralReference(auto_detect_sensitivity=True, initial_timepoint=1, # For deterministic behavior intensity_scaling=True, # 7-DOF (rigid + intensity) subsample_threshold=200, ), name='t1_merge') # 1.5 Reorient template to RAS, if needed (mri_robust_template sets LIA) t1_reorient = pe.Node(ConformSeries(), name='t1_reorient') # 2. T1 Bias Field Correction # Bias field correction is handled in skull strip workflows. # 3. Skull-stripping skullstrip_wf = init_skullstrip_afni_wf(name='skullstrip_afni_wf') if skull_strip_ants: skullstrip_wf = init_skullstrip_ants_wf(name='skullstrip_ants_wf', debug=debug, omp_nthreads=omp_nthreads) # 4. Segmentation t1_seg = pe.Node(FASTRPT(generate_report=True, segments=True, no_bias=True, probability_maps=True), name='t1_seg', mem_gb=3) # 5. Spatial normalization (T1w to MNI registration) t1_2_mni = pe.Node( RobustMNINormalizationRPT( float=True, generate_report=True, num_threads=omp_nthreads, flavor='testing' if debug else 'precise', ), name='t1_2_mni', n_procs=omp_nthreads ) # Resample the brain mask and the tissue probability maps into mni space mni_mask = pe.Node( ants.ApplyTransforms(dimension=3, default_value=0, float=True, interpolation='NearestNeighbor'), name='mni_mask' ) mni_seg = pe.Node( ants.ApplyTransforms(dimension=3, default_value=0, float=True, interpolation='NearestNeighbor'), name='mni_seg' ) mni_tpms = pe.MapNode( ants.ApplyTransforms(dimension=3, default_value=0, float=True, interpolation='Linear'), iterfield=['input_image'], name='mni_tpms' ) def set_threads(in_list, maximum): return min(len(in_list), maximum) def len_above_thresh(in_list, threshold, longitudinal): if longitudinal: return False return len(in_list) > threshold workflow.connect([ (inputnode, t1_conform, [('t1w', 't1w_list')]), (t1_conform, t1_merge, [ ('t1w_list', 'in_files'), (('t1w_list', set_threads, omp_nthreads), 'num_threads'), (('t1w_list', len_above_thresh, 2, longitudinal), 'fixed_timepoint'), (('t1w_list', len_above_thresh, 2, longitudinal), 'no_iteration'), (('t1w_list', add_suffix, '_template'), 'out_file')]), (t1_merge, t1_reorient, [('out_file', 't1w_list')]), (t1_reorient, skullstrip_wf, [('t1w_list', 'inputnode.in_file')]), (skullstrip_wf, t1_seg, [('outputnode.out_file', 'in_files')]), (skullstrip_wf, outputnode, [('outputnode.bias_corrected', 't1_preproc'), ('outputnode.out_file', 't1_brain'), ('outputnode.out_mask', 't1_mask')]), (t1_seg, outputnode, [('tissue_class_map', 't1_seg'), ('probability_maps', 't1_tpms')]), ]) if 'template' in output_spaces: template_str = nid.TEMPLATE_MAP[template] ref_img = op.join(nid.get_dataset(template_str), '1mm_T1.nii.gz') t1_2_mni.inputs.template = template_str mni_mask.inputs.reference_image = ref_img mni_seg.inputs.reference_image = ref_img mni_tpms.inputs.reference_image = ref_img workflow.connect([ (skullstrip_wf, t1_2_mni, [('outputnode.bias_corrected', 'moving_image')]), (skullstrip_wf, t1_2_mni, [('outputnode.out_mask', 'moving_mask')]), (skullstrip_wf, mni_mask, [('outputnode.out_mask', 'input_image')]), (t1_2_mni, mni_mask, [('composite_transform', 'transforms')]), (t1_seg, mni_seg, [('tissue_class_map', 'input_image')]), (t1_2_mni, mni_seg, [('composite_transform', 'transforms')]), (t1_seg, mni_tpms, [('probability_maps', 'input_image')]), (t1_2_mni, mni_tpms, [('composite_transform', 'transforms')]), (t1_2_mni, outputnode, [ ('warped_image', 't1_2_mni'), ('composite_transform', 't1_2_mni_forward_transform'), ('inverse_composite_transform', 't1_2_mni_reverse_transform')]), (mni_mask, outputnode, [('output_image', 'mni_mask')]), (mni_seg, outputnode, [('output_image', 'mni_seg')]), (mni_tpms, outputnode, [('output_image', 'mni_tpms')]), ]) # 6. FreeSurfer reconstruction if freesurfer: surface_recon_wf = init_surface_recon_wf(name='surface_recon_wf', omp_nthreads=omp_nthreads, hires=hires) workflow.connect([ (inputnode, surface_recon_wf, [ ('t2w', 'inputnode.t2w'), ('subjects_dir', 'inputnode.subjects_dir'), ('subject_id', 'inputnode.subject_id')]), (t1_reorient, surface_recon_wf, [('t1w_list', 'inputnode.t1w')]), (skullstrip_wf, surface_recon_wf, [ ('outputnode.out_file', 'inputnode.skullstripped_t1')]), (surface_recon_wf, outputnode, [ ('outputnode.subjects_dir', 'subjects_dir'), ('outputnode.subject_id', 'subject_id'), ('outputnode.fs_2_t1_transform', 'fs_2_t1_transform'), ('outputnode.surfaces', 'surfaces')]), ]) anat_reports_wf = init_anat_reports_wf( reportlets_dir=reportlets_dir, skull_strip_ants=skull_strip_ants, output_spaces=output_spaces, template=template, freesurfer=freesurfer) workflow.connect([ (inputnode, anat_reports_wf, [ (('t1w', fix_multi_T1w_source_name), 'inputnode.source_file')]), (t1_conform, anat_reports_wf, [('out_report', 'inputnode.t1_conform_report')]), (t1_seg, anat_reports_wf, [('out_report', 'inputnode.t1_seg_report')]), ]) if skull_strip_ants: workflow.connect([ (skullstrip_wf, anat_reports_wf, [ ('outputnode.out_report', 'inputnode.t1_skull_strip_report')]) ]) if freesurfer: workflow.connect([ (surface_recon_wf, anat_reports_wf, [ ('outputnode.out_report', 'inputnode.recon_report')]) ]) if 'template' in output_spaces: workflow.connect([ (t1_2_mni, anat_reports_wf, [('out_report', 'inputnode.t1_2_mni_report')]), ]) anat_derivatives_wf = init_anat_derivatives_wf(output_dir=output_dir, output_spaces=output_spaces, template=template, freesurfer=freesurfer) workflow.connect([ (inputnode, anat_derivatives_wf, [ (('t1w', fix_multi_T1w_source_name), 'inputnode.source_file')]), (outputnode, anat_derivatives_wf, [ ('t1_preproc', 'inputnode.t1_preproc'), ('t1_mask', 'inputnode.t1_mask'), ('t1_seg', 'inputnode.t1_seg'), ('t1_tpms', 'inputnode.t1_tpms'), ('t1_2_mni_forward_transform', 'inputnode.t1_2_mni_forward_transform'), ('t1_2_mni', 'inputnode.t1_2_mni'), ('mni_mask', 'inputnode.mni_mask'), ('mni_seg', 'inputnode.mni_seg'), ('mni_tpms', 'inputnode.mni_tpms'), ('surfaces', 'inputnode.surfaces'), ]), ]) return workflow
def init_anat_preproc_wf( bids_root, freesurfer, fs_spaces, hires, longitudinal, omp_nthreads, output_dir, num_t1w, reportlets_dir, skull_strip_template, template, debug=False, name='anat_preproc_wf', skull_strip_fixed_seed=False): r""" This workflow controls the anatomical preprocessing stages of smriprep. This includes: - Creation of a structural template - Skull-stripping and bias correction - Tissue segmentation - Normalization - Surface reconstruction with FreeSurfer .. workflow:: :graph2use: orig :simple_form: yes from smriprep.workflows.anatomical import init_anat_preproc_wf wf = init_anat_preproc_wf( bids_root='.', freesurfer=True, fs_spaces=['T1w', 'fsnative', 'template', 'fsaverage5'], hires=True, longitudinal=False, omp_nthreads=1, output_dir='.', num_t1w=1, reportlets_dir='.', skull_strip_template='MNI152NLin2009cAsym', template='MNI152NLin2009cAsym', ) **Parameters** bids_root : str Path of the input BIDS dataset root debug : bool Enable debugging outputs freesurfer : bool Enable FreeSurfer surface reconstruction (increases runtime by 6h, at the very least) fs_spaces : list List of output spaces functional images are to be resampled to. Some pipeline components will only be instantiated for some output spaces. Valid spaces: - T1w - template - fsnative - fsaverage (or other pre-existing FreeSurfer templates) hires : bool Enable sub-millimeter preprocessing in FreeSurfer longitudinal : bool Create unbiased structural template, regardless of number of inputs (may increase runtime) name : str, optional Workflow name (default: anat_preproc_wf) omp_nthreads : int Maximum number of threads an individual process may use output_dir : str Directory in which to save derivatives reportlets_dir : str Directory in which to save reportlets skull_strip_fixed_seed : bool Do not use a random seed for skull-stripping - will ensure run-to-run replicability when used with --omp-nthreads 1 (default: ``False``) skull_strip_template : str Name of ANTs skull-stripping template ('MNI152NLin2009cAsym', 'OASIS30ANTs' or 'NKI') template : str Name of template targeted by ``template`` output space **Inputs** t1w List of T1-weighted structural images t2w List of T2-weighted structural images flair List of FLAIR images subjects_dir FreeSurfer SUBJECTS_DIR **Outputs** t1_preproc Bias-corrected structural template, defining T1w space t1_brain Skull-stripped ``t1_preproc`` t1_mask Mask of the skull-stripped template image t1_seg Segmentation of preprocessed structural image, including gray-matter (GM), white-matter (WM) and cerebrospinal fluid (CSF) t1_tpms List of tissue probability maps in T1w space t1_2_mni T1w template, normalized to MNI space t1_2_mni_forward_transform ANTs-compatible affine-and-warp transform file t1_2_mni_reverse_transform ANTs-compatible affine-and-warp transform file (inverse) mni_mask Mask of skull-stripped template, in MNI space mni_seg Segmentation, resampled into MNI space mni_tpms List of tissue probability maps in MNI space subjects_dir FreeSurfer SUBJECTS_DIR subject_id FreeSurfer subject ID t1_2_fsnative_forward_transform LTA-style affine matrix translating from T1w to FreeSurfer-conformed subject space t1_2_fsnative_reverse_transform LTA-style affine matrix translating from FreeSurfer-conformed subject space to T1w surfaces GIFTI surfaces (gray/white boundary, midthickness, pial, inflated) **Subworkflows** * :py:func:`~niworkflows.anat.ants.init_brain_extraction_wf` * :py:func:`~smriprep.workflows.surfaces.init_surface_recon_wf` """ if isinstance(template, list): # THIS SHOULD BE DELETED template = template[0] template_meta = get_metadata(template) template_refs = ['@%s' % template.lower()] if template_meta.get('RRID', None): template_refs += ['RRID:%s' % template_meta['RRID']] workflow = Workflow(name=name) workflow.__postdesc__ = """\ Spatial normalization to the *{template_name}* [{template_refs}] was performed through nonlinear registration with `antsRegistration` (ANTs {ants_ver}), using brain-extracted versions of both T1w volume and template. Brain tissue segmentation of cerebrospinal fluid (CSF), white-matter (WM) and gray-matter (GM) was performed on the brain-extracted T1w using `fast` [FSL {fsl_ver}, RRID:SCR_002823, @fsl_fast]. """.format( ants_ver=ANTsInfo.version() or '<ver>', fsl_ver=fsl.FAST().version or '<ver>', template_name=template_meta['Name'], template_refs=', '.join(template_refs), ) desc = """Anatomical data preprocessing : """ desc += """\ A total of {num_t1w} T1-weighted (T1w) images were found within the input BIDS dataset. All of them were corrected for intensity non-uniformity (INU) """ if num_t1w > 1 else """\ The T1-weighted (T1w) image was corrected for intensity non-uniformity (INU) """ desc += """\ with `N4BiasFieldCorrection` [@n4], distributed with ANTs {ants_ver} \ [@ants, RRID:SCR_004757]""" desc += '.\n' if num_t1w > 1 else ", and used as T1w-reference throughout the workflow.\n" desc += """\ The T1w-reference was then skull-stripped with a *Nipype* implementation of the `antsBrainExtraction.sh` workflow (from ANTs), using {skullstrip_tpl} as target template. """.format(skullstrip_tpl=skull_strip_template) workflow.__desc__ = desc.format( num_t1w=num_t1w, ants_ver=ANTsInfo.version() or '<ver>' ) inputnode = pe.Node( niu.IdentityInterface(fields=['t1w', 't2w', 'roi', 'flair', 'subjects_dir', 'subject_id']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['t1_preproc', 't1_brain', 't1_mask', 't1_seg', 't1_tpms', 't1_2_mni', 't1_2_mni_forward_transform', 't1_2_mni_reverse_transform', 'mni_mask', 'mni_seg', 'mni_tpms', 'template_transforms', 'subjects_dir', 'subject_id', 't1_2_fsnative_forward_transform', 't1_2_fsnative_reverse_transform', 'surfaces', 't1_aseg', 't1_aparc']), name='outputnode') buffernode = pe.Node(niu.IdentityInterface( fields=['t1_brain', 't1_mask']), name='buffernode') anat_template_wf = init_anat_template_wf(longitudinal=longitudinal, omp_nthreads=omp_nthreads, num_t1w=num_t1w) # 3. Skull-stripping # Bias field correction is handled in skull strip workflows. brain_extraction_wf = init_brain_extraction_wf( in_template=skull_strip_template, atropos_use_random_seed=not skull_strip_fixed_seed, omp_nthreads=omp_nthreads, normalization_quality='precise' if not debug else 'testing') workflow.connect([ (inputnode, anat_template_wf, [('t1w', 'inputnode.t1w')]), (anat_template_wf, brain_extraction_wf, [ ('outputnode.t1_template', 'inputnode.in_files')]), (brain_extraction_wf, outputnode, [ ('outputnode.bias_corrected', 't1_preproc')]), (anat_template_wf, outputnode, [ ('outputnode.template_transforms', 't1_template_transforms')]), (buffernode, outputnode, [('t1_brain', 't1_brain'), ('t1_mask', 't1_mask')]), ]) # 4. Surface reconstruction if freesurfer: surface_recon_wf = init_surface_recon_wf(name='surface_recon_wf', omp_nthreads=omp_nthreads, hires=hires) applyrefined = pe.Node(fsl.ApplyMask(), name='applyrefined') workflow.connect([ (inputnode, surface_recon_wf, [ ('t2w', 'inputnode.t2w'), ('flair', 'inputnode.flair'), ('subjects_dir', 'inputnode.subjects_dir'), ('subject_id', 'inputnode.subject_id')]), (anat_template_wf, surface_recon_wf, [('outputnode.t1_template', 'inputnode.t1w')]), (brain_extraction_wf, surface_recon_wf, [ (('outputnode.out_file', _pop), 'inputnode.skullstripped_t1'), ('outputnode.out_segm', 'inputnode.ants_segs'), (('outputnode.bias_corrected', _pop), 'inputnode.corrected_t1')]), (brain_extraction_wf, applyrefined, [ (('outputnode.bias_corrected', _pop), 'in_file')]), (surface_recon_wf, applyrefined, [ ('outputnode.out_brainmask', 'mask_file')]), (surface_recon_wf, outputnode, [ ('outputnode.subjects_dir', 'subjects_dir'), ('outputnode.subject_id', 'subject_id'), ('outputnode.t1_2_fsnative_forward_transform', 't1_2_fsnative_forward_transform'), ('outputnode.t1_2_fsnative_reverse_transform', 't1_2_fsnative_reverse_transform'), ('outputnode.surfaces', 'surfaces'), ('outputnode.out_aseg', 't1_aseg'), ('outputnode.out_aparc', 't1_aparc')]), (applyrefined, buffernode, [('out_file', 't1_brain')]), (surface_recon_wf, buffernode, [ ('outputnode.out_brainmask', 't1_mask')]), ]) else: workflow.connect([ (brain_extraction_wf, buffernode, [ (('outputnode.out_file', _pop), 't1_brain'), ('outputnode.out_mask', 't1_mask')]), ]) # 5. Segmentation t1_seg = pe.Node(fsl.FAST(segments=True, no_bias=True, probability_maps=True), name='t1_seg', mem_gb=3) workflow.connect([ (buffernode, t1_seg, [('t1_brain', 'in_files')]), (t1_seg, outputnode, [('tissue_class_map', 't1_seg'), ('probability_maps', 't1_tpms')]), ]) # 6. Spatial normalization (T1w to MNI registration) t1_2_mni = pe.Node( RobustMNINormalizationRPT( float=True, generate_report=True, flavor='testing' if debug else 'precise', ), name='t1_2_mni', n_procs=omp_nthreads, mem_gb=2 ) # Resample the brain mask and the tissue probability maps into mni space mni_mask = pe.Node( ApplyTransforms(dimension=3, default_value=0, float=True, interpolation='MultiLabel'), name='mni_mask' ) mni_seg = pe.Node( ApplyTransforms(dimension=3, default_value=0, float=True, interpolation='MultiLabel'), name='mni_seg' ) mni_tpms = pe.MapNode( ApplyTransforms(dimension=3, default_value=0, float=True, interpolation='Linear'), iterfield=['input_image'], name='mni_tpms' ) # TODO isolate the spatial normalization workflow ############# ref_img = str(get_template(template, resolution=1, desc=None, suffix='T1w', extensions=['.nii', '.nii.gz'])) t1_2_mni.inputs.template = template mni_mask.inputs.reference_image = ref_img mni_seg.inputs.reference_image = ref_img mni_tpms.inputs.reference_image = ref_img workflow.connect([ (inputnode, t1_2_mni, [('roi', 'lesion_mask')]), (brain_extraction_wf, t1_2_mni, [ (('outputnode.bias_corrected', _pop), 'moving_image')]), (buffernode, t1_2_mni, [('t1_mask', 'moving_mask')]), (buffernode, mni_mask, [('t1_mask', 'input_image')]), (t1_2_mni, mni_mask, [('composite_transform', 'transforms')]), (t1_seg, mni_seg, [('tissue_class_map', 'input_image')]), (t1_2_mni, mni_seg, [('composite_transform', 'transforms')]), (t1_seg, mni_tpms, [('probability_maps', 'input_image')]), (t1_2_mni, mni_tpms, [('composite_transform', 'transforms')]), (t1_2_mni, outputnode, [ ('warped_image', 't1_2_mni'), ('composite_transform', 't1_2_mni_forward_transform'), ('inverse_composite_transform', 't1_2_mni_reverse_transform')]), (mni_mask, outputnode, [('output_image', 'mni_mask')]), (mni_seg, outputnode, [('output_image', 'mni_seg')]), (mni_tpms, outputnode, [('output_image', 'mni_tpms')]), ]) # spatial normalization ends here ############################### seg_rpt = pe.Node(ROIsPlot(colors=['magenta', 'b'], levels=[1.5, 2.5]), name='seg_rpt') anat_reports_wf = init_anat_reports_wf( reportlets_dir=reportlets_dir, template=template, freesurfer=freesurfer) workflow.connect([ (inputnode, anat_reports_wf, [ (('t1w', fix_multi_T1w_source_name), 'inputnode.source_file')]), (anat_template_wf, anat_reports_wf, [ ('outputnode.out_report', 'inputnode.t1_conform_report')]), (anat_template_wf, seg_rpt, [ ('outputnode.t1_template', 'in_file')]), (t1_seg, seg_rpt, [('tissue_class_map', 'in_rois')]), (outputnode, seg_rpt, [('t1_mask', 'in_mask')]), (seg_rpt, anat_reports_wf, [('out_report', 'inputnode.seg_report')]), (t1_2_mni, anat_reports_wf, [('out_report', 'inputnode.t1_2_mni_report')]), ]) if freesurfer: workflow.connect([ (surface_recon_wf, anat_reports_wf, [ ('outputnode.out_report', 'inputnode.recon_report')]), ]) anat_derivatives_wf = init_anat_derivatives_wf( bids_root=bids_root, freesurfer=freesurfer, output_dir=output_dir, template=template, ) workflow.connect([ (anat_template_wf, anat_derivatives_wf, [ ('outputnode.t1w_valid_list', 'inputnode.source_files')]), (outputnode, anat_derivatives_wf, [ ('t1_template_transforms', 'inputnode.t1_template_transforms'), ('t1_preproc', 'inputnode.t1_preproc'), ('t1_mask', 'inputnode.t1_mask'), ('t1_seg', 'inputnode.t1_seg'), ('t1_tpms', 'inputnode.t1_tpms'), ('t1_2_mni_forward_transform', 'inputnode.t1_2_mni_forward_transform'), ('t1_2_mni_reverse_transform', 'inputnode.t1_2_mni_reverse_transform'), ('t1_2_mni', 'inputnode.t1_2_mni'), ('mni_mask', 'inputnode.mni_mask'), ('mni_seg', 'inputnode.mni_seg'), ('mni_tpms', 'inputnode.mni_tpms'), ('t1_2_fsnative_forward_transform', 'inputnode.t1_2_fsnative_forward_transform'), ('surfaces', 'inputnode.surfaces'), ]), ]) if freesurfer: workflow.connect([ (surface_recon_wf, anat_derivatives_wf, [ ('outputnode.out_aseg', 'inputnode.t1_fs_aseg'), ('outputnode.out_aparc', 'inputnode.t1_fs_aparc'), ]), ]) return workflow
def init_anat_preproc_wf(skull_strip_template, output_spaces, template, debug, freesurfer, longitudinal, omp_nthreads, hires, reportlets_dir, output_dir, num_t1w, name='anat_preproc_wf'): r""" This workflow controls the anatomical preprocessing stages of FMRIPREP. This includes: - Creation of a structural template - Skull-stripping and bias correction - Tissue segmentation - Normalization - Surface reconstruction with FreeSurfer .. workflow:: :graph2use: orig :simple_form: yes from fmriprep.workflows.anatomical import init_anat_preproc_wf wf = init_anat_preproc_wf(omp_nthreads=1, reportlets_dir='.', output_dir='.', template='MNI152NLin2009cAsym', output_spaces=['T1w', 'fsnative', 'template', 'fsaverage5'], skull_strip_template='OASIS', freesurfer=True, longitudinal=False, debug=False, hires=True, num_t1w=1) **Parameters** skull_strip_template : str Name of ANTs skull-stripping template ('OASIS' or 'NKI') output_spaces : list List of output spaces functional images are to be resampled to. Some pipeline components will only be instantiated for some output spaces. Valid spaces: - T1w - template - fsnative - fsaverage (or other pre-existing FreeSurfer templates) template : str Name of template targeted by `'template'` output space debug : bool Enable debugging outputs freesurfer : bool Enable FreeSurfer surface reconstruction (may increase runtime) longitudinal : bool Create unbiased structural template, regardless of number of inputs (may increase runtime) omp_nthreads : int Maximum number of threads an individual process may use hires : bool Enable sub-millimeter preprocessing in FreeSurfer reportlets_dir : str Directory in which to save reportlets output_dir : str Directory in which to save derivatives name : str, optional Workflow name (default: anat_preproc_wf) **Inputs** t1w List of T1-weighted structural images t2w List of T2-weighted structural images subjects_dir FreeSurfer SUBJECTS_DIR **Outputs** t1_preproc Bias-corrected structural template, defining T1w space t1_brain Skull-stripped ``t1_preproc`` t1_mask Mask of the skull-stripped template image t1_seg Segmentation of preprocessed structural image, including gray-matter (GM), white-matter (WM) and cerebrospinal fluid (CSF) t1_tpms List of tissue probability maps in T1w space t1_2_mni T1w template, normalized to MNI space t1_2_mni_forward_transform ANTs-compatible affine-and-warp transform file t1_2_mni_reverse_transform ANTs-compatible affine-and-warp transform file (inverse) mni_mask Mask of skull-stripped template, in MNI space mni_seg Segmentation, resampled into MNI space mni_tpms List of tissue probability maps in MNI space subjects_dir FreeSurfer SUBJECTS_DIR subject_id FreeSurfer subject ID t1_2_fsnative_forward_transform LTA-style affine matrix translating from T1w to FreeSurfer-conformed subject space t1_2_fsnative_reverse_transform LTA-style affine matrix translating from FreeSurfer-conformed subject space to T1w surfaces GIFTI surfaces (gray/white boundary, midthickness, pial, inflated) **Subworkflows** * :py:func:`~fmriprep.workflows.anatomical.init_skullstrip_ants_wf` * :py:func:`~fmriprep.workflows.anatomical.init_surface_recon_wf` """ workflow = pe.Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=['t1w', 't2w', 'subjects_dir', 'subject_id']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['t1_preproc', 't1_brain', 't1_mask', 't1_seg', 't1_tpms', 't1_2_mni', 't1_2_mni_forward_transform', 't1_2_mni_reverse_transform', 'mni_mask', 'mni_seg', 'mni_tpms', 'template_transforms', 'subjects_dir', 'subject_id', 't1_2_fsnative_forward_transform', 't1_2_fsnative_reverse_transform', 'surfaces']), name='outputnode') buffernode = pe.Node(niu.IdentityInterface( fields=['t1_brain', 't1_mask']), name='buffernode') anat_template_wf = init_anat_template_wf(longitudinal=longitudinal, omp_nthreads=omp_nthreads, num_t1w=num_t1w) # 3. Skull-stripping # Bias field correction is handled in skull strip workflows. skullstrip_ants_wf = init_skullstrip_ants_wf(name='skullstrip_ants_wf', skull_strip_template=skull_strip_template, debug=debug, omp_nthreads=omp_nthreads) workflow.connect([ (inputnode, anat_template_wf, [('t1w', 'inputnode.t1w')]), (anat_template_wf, skullstrip_ants_wf, [('outputnode.t1_template', 'inputnode.in_file')]), (skullstrip_ants_wf, outputnode, [('outputnode.bias_corrected', 't1_preproc')]), (anat_template_wf, outputnode, [ ('outputnode.template_transforms', 't1_template_transforms')]), (buffernode, outputnode, [('t1_brain', 't1_brain'), ('t1_mask', 't1_mask')]), ]) # 4. Surface reconstruction if freesurfer: surface_recon_wf = init_surface_recon_wf(name='surface_recon_wf', omp_nthreads=omp_nthreads, hires=hires) applyrefined = pe.Node(fsl.ApplyMask(), name='applyrefined') workflow.connect([ (inputnode, surface_recon_wf, [ ('t2w', 'inputnode.t2w'), ('subjects_dir', 'inputnode.subjects_dir'), ('subject_id', 'inputnode.subject_id')]), (anat_template_wf, surface_recon_wf, [('outputnode.t1_template', 'inputnode.t1w')]), (skullstrip_ants_wf, surface_recon_wf, [ ('outputnode.out_file', 'inputnode.skullstripped_t1'), ('outputnode.out_segs', 'inputnode.ants_segs'), ('outputnode.bias_corrected', 'inputnode.corrected_t1')]), (skullstrip_ants_wf, applyrefined, [ ('outputnode.bias_corrected', 'in_file')]), (surface_recon_wf, applyrefined, [ ('outputnode.out_brainmask', 'mask_file')]), (surface_recon_wf, outputnode, [ ('outputnode.subjects_dir', 'subjects_dir'), ('outputnode.subject_id', 'subject_id'), ('outputnode.t1_2_fsnative_forward_transform', 't1_2_fsnative_forward_transform'), ('outputnode.t1_2_fsnative_reverse_transform', 't1_2_fsnative_reverse_transform'), ('outputnode.surfaces', 'surfaces')]), (applyrefined, buffernode, [('out_file', 't1_brain')]), (surface_recon_wf, buffernode, [ ('outputnode.out_brainmask', 't1_mask')]), ]) else: workflow.connect([ (skullstrip_ants_wf, buffernode, [ ('outputnode.out_file', 't1_brain'), ('outputnode.out_mask', 't1_mask')]), ]) # 5. Segmentation t1_seg = pe.Node(fsl.FAST(segments=True, no_bias=True, probability_maps=True), name='t1_seg', mem_gb=3) workflow.connect([ (buffernode, t1_seg, [('t1_brain', 'in_files')]), (t1_seg, outputnode, [('tissue_class_map', 't1_seg'), ('probability_maps', 't1_tpms')]), ]) # 6. Spatial normalization (T1w to MNI registration) t1_2_mni = pe.Node( RobustMNINormalizationRPT( float=True, generate_report=True, flavor='testing' if debug else 'precise', ), name='t1_2_mni', n_procs=omp_nthreads, mem_gb=2 ) # Resample the brain mask and the tissue probability maps into mni space mni_mask = pe.Node( ApplyTransforms(dimension=3, default_value=0, float=True, interpolation='NearestNeighbor'), name='mni_mask' ) mni_seg = pe.Node( ApplyTransforms(dimension=3, default_value=0, float=True, interpolation='NearestNeighbor'), name='mni_seg' ) mni_tpms = pe.MapNode( ApplyTransforms(dimension=3, default_value=0, float=True, interpolation='Linear'), iterfield=['input_image'], name='mni_tpms' ) if 'template' in output_spaces: template_str = nid.TEMPLATE_MAP[template] ref_img = op.join(nid.get_dataset(template_str), '1mm_T1.nii.gz') t1_2_mni.inputs.template = template_str mni_mask.inputs.reference_image = ref_img mni_seg.inputs.reference_image = ref_img mni_tpms.inputs.reference_image = ref_img workflow.connect([ (skullstrip_ants_wf, t1_2_mni, [('outputnode.bias_corrected', 'moving_image')]), (buffernode, t1_2_mni, [('t1_mask', 'moving_mask')]), (buffernode, mni_mask, [('t1_mask', 'input_image')]), (t1_2_mni, mni_mask, [('composite_transform', 'transforms')]), (t1_seg, mni_seg, [('tissue_class_map', 'input_image')]), (t1_2_mni, mni_seg, [('composite_transform', 'transforms')]), (t1_seg, mni_tpms, [('probability_maps', 'input_image')]), (t1_2_mni, mni_tpms, [('composite_transform', 'transforms')]), (t1_2_mni, outputnode, [ ('warped_image', 't1_2_mni'), ('composite_transform', 't1_2_mni_forward_transform'), ('inverse_composite_transform', 't1_2_mni_reverse_transform')]), (mni_mask, outputnode, [('output_image', 'mni_mask')]), (mni_seg, outputnode, [('output_image', 'mni_seg')]), (mni_tpms, outputnode, [('output_image', 'mni_tpms')]), ]) seg2msks = pe.Node(niu.Function(function=_seg2msks), name='seg2msks') seg_rpt = pe.Node(ROIsPlot(colors=['r', 'magenta', 'b', 'g']), name='seg_rpt') anat_reports_wf = init_anat_reports_wf( reportlets_dir=reportlets_dir, output_spaces=output_spaces, template=template, freesurfer=freesurfer) workflow.connect([ (inputnode, anat_reports_wf, [ (('t1w', fix_multi_T1w_source_name), 'inputnode.source_file')]), (anat_template_wf, anat_reports_wf, [ ('outputnode.out_report', 'inputnode.t1_conform_report')]), (anat_template_wf, seg_rpt, [ ('outputnode.t1_template', 'in_file')]), (t1_seg, seg2msks, [('tissue_class_map', 'in_file')]), (seg2msks, seg_rpt, [('out', 'in_rois')]), (outputnode, seg_rpt, [('t1_mask', 'in_mask')]), (seg_rpt, anat_reports_wf, [('out_report', 'inputnode.seg_report')]), ]) if freesurfer: workflow.connect([ (surface_recon_wf, anat_reports_wf, [ ('outputnode.out_report', 'inputnode.recon_report')]) ]) if 'template' in output_spaces: workflow.connect([ (t1_2_mni, anat_reports_wf, [('out_report', 'inputnode.t1_2_mni_report')]), ]) anat_derivatives_wf = init_anat_derivatives_wf(output_dir=output_dir, output_spaces=output_spaces, template=template, freesurfer=freesurfer) workflow.connect([ (anat_template_wf, anat_derivatives_wf, [ ('outputnode.t1w_valid_list', 'inputnode.source_files')]), (outputnode, anat_derivatives_wf, [ ('t1_template_transforms', 'inputnode.t1_template_transforms'), ('t1_preproc', 'inputnode.t1_preproc'), ('t1_mask', 'inputnode.t1_mask'), ('t1_seg', 'inputnode.t1_seg'), ('t1_tpms', 'inputnode.t1_tpms'), ('t1_2_mni_forward_transform', 'inputnode.t1_2_mni_forward_transform'), ('t1_2_mni_reverse_transform', 'inputnode.t1_2_mni_reverse_transform'), ('t1_2_mni', 'inputnode.t1_2_mni'), ('mni_mask', 'inputnode.mni_mask'), ('mni_seg', 'inputnode.mni_seg'), ('mni_tpms', 'inputnode.mni_tpms'), ('t1_2_fsnative_forward_transform', 'inputnode.t1_2_fsnative_forward_transform'), ('surfaces', 'inputnode.surfaces'), ]), ]) return workflow