def init_enhance_and_skullstrip_bold_wf(name='enhance_and_skullstrip_bold_wf', omp_nthreads=1): workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=['in_file']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=[ 'mask_file', 'skull_stripped_file', 'bias_corrected_file', 'out_report' ]), name='outputnode') n4_correct = pe.Node(ants.N4BiasFieldCorrection(dimension=3, copy_header=True, num_threads=omp_nthreads), name='n4_correct', n_procs=omp_nthreads) skullstrip_first_pass = pe.Node(fsl.BET(frac=0.2, mask=True), name='skullstrip_first_pass') unifize = pe.Node(afni.Unifize(t2=True, outputtype='NIFTI_GZ', args='-clfrac 0.4', out_file="uni.nii.gz"), name='unifize') skullstrip_second_pass = pe.Node(afni.Automask(dilate=1, outputtype='NIFTI_GZ'), name='skullstrip_second_pass') combine_masks = pe.Node(fsl.BinaryMaths(operation='mul'), name='combine_masks') apply_mask = pe.Node(fsl.ApplyMask(), name='apply_mask') mask_reportlet = pe.Node(SimpleShowMaskRPT(), name='mask_reportlet') workflow.connect([ (inputnode, n4_correct, [('in_file', 'input_image')]), (n4_correct, skullstrip_first_pass, [('output_image', 'in_file')]), (skullstrip_first_pass, unifize, [('out_file', 'in_file')]), (unifize, skullstrip_second_pass, [('out_file', 'in_file')]), (skullstrip_first_pass, combine_masks, [('mask_file', 'in_file')]), (skullstrip_second_pass, combine_masks, [('out_file', 'operand_file') ]), (unifize, apply_mask, [('out_file', 'in_file')]), (combine_masks, apply_mask, [('out_file', 'mask_file')]), (n4_correct, mask_reportlet, [('output_image', 'background_file')]), (combine_masks, mask_reportlet, [('out_file', 'mask_file')]), (combine_masks, outputnode, [('out_file', 'mask_file')]), (mask_reportlet, outputnode, [('out_report', 'out_report')]), (apply_mask, outputnode, [('out_file', 'skull_stripped_file')]), (n4_correct, outputnode, [('output_image', 'bias_corrected_file')]), ]) return workflow
def init_skullstrip_epi_wf(name='skullstrip_epi_wf'): workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=['in_file']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['mask_file', 'skull_stripped_file', 'out_report']), name='outputnode') skullstrip_first_pass = pe.Node(fsl.BET(frac=0.2, mask=True), name='skullstrip_first_pass') skullstrip_second_pass = pe.Node(afni.Automask(dilate=1, outputtype='NIFTI_GZ'), name='skullstrip_second_pass') combine_masks = pe.Node(fsl.BinaryMaths(operation='mul'), name='combine_masks') apply_mask = pe.Node(fsl.ApplyMask(), name='apply_mask') mask_reportlet = pe.Node(SimpleShowMaskRPT(), name='mask_reportlet') workflow.connect([ (inputnode, skullstrip_first_pass, [('in_file', 'in_file')]), (skullstrip_first_pass, skullstrip_second_pass, [('out_file', 'in_file')]), (skullstrip_first_pass, combine_masks, [('mask_file', 'in_file')]), (skullstrip_second_pass, combine_masks, [('out_file', 'operand_file') ]), (combine_masks, outputnode, [('out_file', 'mask_file')]), # Masked file (inputnode, apply_mask, [('in_file', 'in_file')]), (combine_masks, apply_mask, [('out_file', 'mask_file')]), (apply_mask, outputnode, [('out_file', 'skull_stripped_file')]), # Reportlet (inputnode, mask_reportlet, [('in_file', 'background_file')]), (combine_masks, mask_reportlet, [('out_file', 'mask_file')]), (mask_reportlet, outputnode, [('out_report', 'out_report')]), ]) return workflow
def init_sdc_unwarp_wf(reportlets_dir, omp_nthreads, fmap_bspline, fmap_demean, debug, name='sdc_unwarp_wf'): """ This workflow takes in a displacements fieldmap and calculates the corresponding displacements field (in other words, an ANTs-compatible warp file). It also calculates a new mask for the input dataset that takes into account the distortions. The mask is restricted to the field of view of the fieldmap since outside of it corrections could not be performed. .. workflow :: :graph2use: orig :simple_form: yes from fmriprep.workflows.fieldmap.unwarp import init_sdc_unwarp_wf wf = init_sdc_unwarp_wf(reportlets_dir='.', omp_nthreads=8, fmap_bspline=False, fmap_demean=True, debug=False) Inputs in_reference the reference image in_mask a brain mask corresponding to ``in_reference`` name_source path to the original _bold file being unwarped fmap the fieldmap in Hz fmap_ref the reference (anatomical) image corresponding to ``fmap`` fmap_mask a brain mask corresponding to ``fmap`` Outputs out_reference the ``in_reference`` after unwarping out_reference_brain the ``in_reference`` after unwarping and skullstripping out_warp the corresponding :abbr:`DFM (displacements field map)` compatible with ANTs out_jacobian the jacobian of the field (for drop-out alleviation) out_mask mask of the unwarped input file out_mask_report reportled for the skullstripping """ workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=[ 'in_reference', 'in_reference_brain', 'in_mask', 'name_source', 'fmap_ref', 'fmap_mask', 'fmap' ]), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=[ 'out_reference', 'out_reference_brain', 'out_warp', 'out_mask', 'out_jacobian', 'out_mask_report' ]), name='outputnode') meta = pe.Node(ReadSidecarJSON(), name='meta') # Register the reference of the fieldmap to the reference # of the target image (the one that shall be corrected) ants_settings = pkgr.resource_filename('fmriprep', 'data/fmap-any_registration.json') if debug: ants_settings = pkgr.resource_filename( 'fmriprep', 'data/fmap-any_registration_testing.json') fmap2ref_reg = pe.Node(ANTSRegistrationRPT( generate_report=True, from_file=ants_settings, output_inverse_warped_image=True, output_warped_image=True, num_threads=omp_nthreads), name='fmap2ref_reg') fmap2ref_reg.interface.num_threads = omp_nthreads ds_reg = pe.Node(DerivativesDataSink(base_directory=reportlets_dir, suffix='fmap_reg'), name='ds_reg') # Map the VSM into the EPI space fmap2ref_apply = pe.Node(ANTSApplyTransformsRPT(generate_report=True, dimension=3, interpolation='BSpline', float=True), name='fmap2ref_apply') fmap_mask2ref_apply = pe.Node(ANTSApplyTransformsRPT( generate_report=False, dimension=3, interpolation='NearestNeighbor', float=True), name='fmap_mask2ref_apply') ds_reg_vsm = pe.Node(DerivativesDataSink(base_directory=reportlets_dir, suffix='fmap_reg_vsm'), name='ds_reg_vsm') # Fieldmap to rads and then to voxels (VSM - voxel shift map) torads = pe.Node(niu.Function(function=_hz2rads), name='torads') gen_vsm = pe.Node(fsl.FUGUE(save_unmasked_shift=True), name='gen_vsm') # Convert the VSM into a DFM (displacements field map) # or: FUGUE shift to ANTS warping. vsm2dfm = pe.Node(itk.FUGUEvsm2ANTSwarp(), name='vsm2dfm') jac_dfm = pe.Node(ants.CreateJacobianDeterminantImage( imageDimension=3, outputImage='jacobian.nii.gz'), name='jac_dfm') unwarp_reference = pe.Node(ANTSApplyTransformsRPT( dimension=3, generate_report=False, float=True, interpolation='LanczosWindowedSinc'), name='unwarp_reference') fieldmap_fov_mask = pe.Node(niu.Function(function=_fill_with_ones), name='fieldmap_fov_mask') fmap_fov2ref_apply = pe.Node(ANTSApplyTransformsRPT( generate_report=False, dimension=3, interpolation='NearestNeighbor', float=True), name='fmap_fov2ref_apply') apply_fov_mask = pe.Node(fsl.ApplyMask(), name="apply_fov_mask") enhance_and_skullstrip_epi_wf = init_enhance_and_skullstrip_epi_wf() workflow.connect([ (inputnode, meta, [('name_source', 'in_file')]), (inputnode, fmap2ref_reg, [('fmap_ref', 'moving_image')]), (inputnode, fmap2ref_apply, [('in_reference', 'reference_image')]), (fmap2ref_reg, fmap2ref_apply, [('composite_transform', 'transforms') ]), (inputnode, fmap_mask2ref_apply, [('in_reference', 'reference_image') ]), (fmap2ref_reg, fmap_mask2ref_apply, [('composite_transform', 'transforms')]), (inputnode, ds_reg_vsm, [('name_source', 'source_file')]), (fmap2ref_apply, ds_reg_vsm, [('out_report', 'in_file')]), (inputnode, fmap2ref_reg, [('in_reference_brain', 'fixed_image')]), (inputnode, ds_reg, [('name_source', 'source_file')]), (fmap2ref_reg, ds_reg, [('out_report', 'in_file')]), (inputnode, fmap2ref_apply, [('fmap', 'input_image')]), (inputnode, fmap_mask2ref_apply, [('fmap_mask', 'input_image')]), (fmap2ref_apply, torads, [('output_image', 'in_file')]), (meta, gen_vsm, [(('out_dict', _get_ec), 'dwell_time'), (('out_dict', _get_pedir_fugue), 'unwarp_direction') ]), (meta, vsm2dfm, [(('out_dict', _get_pedir_bids), 'pe_dir')]), (torads, gen_vsm, [('out', 'fmap_in_file')]), (vsm2dfm, unwarp_reference, [('out_file', 'transforms')]), (inputnode, unwarp_reference, [('in_reference', 'reference_image')]), (inputnode, unwarp_reference, [('in_reference', 'input_image')]), (vsm2dfm, outputnode, [('out_file', 'out_warp')]), (vsm2dfm, jac_dfm, [('out_file', 'deformationField')]), (inputnode, fieldmap_fov_mask, [('fmap_ref', 'in_file')]), (fieldmap_fov_mask, fmap_fov2ref_apply, [('out', 'input_image')]), (inputnode, fmap_fov2ref_apply, [('in_reference', 'reference_image')]), (fmap2ref_reg, fmap_fov2ref_apply, [('composite_transform', 'transforms')]), (fmap_fov2ref_apply, apply_fov_mask, [('output_image', 'mask_file')]), (unwarp_reference, apply_fov_mask, [('output_image', 'in_file')]), (apply_fov_mask, enhance_and_skullstrip_epi_wf, [('out_file', 'inputnode.in_file')]), (apply_fov_mask, outputnode, [('out_file', 'out_reference')]), (enhance_and_skullstrip_epi_wf, outputnode, [('outputnode.mask_file', 'out_mask'), ('outputnode.out_report', 'out_mask_report'), ('outputnode.skull_stripped_file', 'out_reference_brain')]), (jac_dfm, outputnode, [('jacobian_image', 'out_jacobian')]), ]) if not fmap_bspline: workflow.connect([(fmap_mask2ref_apply, gen_vsm, [('output_image', 'mask_file')])]) if fmap_demean: # Demean within mask demean = pe.Node(niu.Function(function=_demean), name='demean') workflow.connect([ (gen_vsm, demean, [('shift_out_file', 'in_file')]), (fmap_mask2ref_apply, demean, [('output_image', 'in_mask')]), (demean, vsm2dfm, [('out', 'in_file')]), ]) else: workflow.connect([ (gen_vsm, vsm2dfm, [('shift_out_file', 'in_file')]), ]) return workflow
def init_skullstrip_bold_wf(name='skullstrip_bold_wf'): """ This workflow applies skull-stripping to a BOLD image. It is intended to be used on an image that has previously been bias-corrected with :py:func:`~fmriprep.workflows.bold.util.init_enhance_and_skullstrip_bold_wf` .. workflow :: :graph2use: orig :simple_form: yes from fmriprep.workflows.bold.util import init_skullstrip_bold_wf wf = init_skullstrip_bold_wf() Inputs in_file BOLD image (single volume) Outputs skull_stripped_file the ``in_file`` after skull-stripping mask_file mask of the skull-stripped input file out_report reportlet for the skull-stripping """ workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=['in_file']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['mask_file', 'skull_stripped_file', 'out_report']), name='outputnode') skullstrip_first_pass = pe.Node(fsl.BET(frac=0.2, mask=True), name='skullstrip_first_pass') skullstrip_second_pass = pe.Node(afni.Automask(dilate=1, outputtype='NIFTI_GZ'), name='skullstrip_second_pass') combine_masks = pe.Node(fsl.BinaryMaths(operation='mul'), name='combine_masks') apply_mask = pe.Node(fsl.ApplyMask(), name='apply_mask') mask_reportlet = pe.Node(SimpleShowMaskRPT(), name='mask_reportlet') workflow.connect([ (inputnode, skullstrip_first_pass, [('in_file', 'in_file')]), (skullstrip_first_pass, skullstrip_second_pass, [('out_file', 'in_file')]), (skullstrip_first_pass, combine_masks, [('mask_file', 'in_file')]), (skullstrip_second_pass, combine_masks, [('out_file', 'operand_file') ]), (combine_masks, outputnode, [('out_file', 'mask_file')]), # Masked file (inputnode, apply_mask, [('in_file', 'in_file')]), (combine_masks, apply_mask, [('out_file', 'mask_file')]), (apply_mask, outputnode, [('out_file', 'skull_stripped_file')]), # Reportlet (inputnode, mask_reportlet, [('in_file', 'background_file')]), (combine_masks, mask_reportlet, [('out_file', 'mask_file')]), (mask_reportlet, outputnode, [('out_report', 'out_report')]), ]) return workflow
def init_enhance_and_skullstrip_bold_wf(name='enhance_and_skullstrip_bold_wf', omp_nthreads=1): """ This workflow takes in a BOLD volume, and attempts to enhance the contrast between gray and white matter, and skull-stripping the result. .. workflow :: :graph2use: orig :simple_form: yes from fmriprep.workflows.bold.util import init_enhance_and_skullstrip_bold_wf wf = init_enhance_and_skullstrip_bold_wf(omp_nthreads=1) Inputs in_file BOLD image (single volume) 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 = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=['in_file']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=[ 'mask_file', 'skull_stripped_file', 'bias_corrected_file', 'out_report' ]), name='outputnode') n4_correct = pe.Node(ants.N4BiasFieldCorrection(dimension=3, copy_header=True), name='n4_correct', n_procs=omp_nthreads) skullstrip_first_pass = pe.Node(fsl.BET(frac=0.2, mask=True), name='skullstrip_first_pass') unifize = pe.Node(afni.Unifize(t2=True, outputtype='NIFTI_GZ', args='-clfrac 0.4', out_file="uni.nii.gz"), name='unifize') skullstrip_second_pass = pe.Node(afni.Automask(dilate=1, outputtype='NIFTI_GZ'), name='skullstrip_second_pass') combine_masks = pe.Node(fsl.BinaryMaths(operation='mul'), name='combine_masks') apply_mask = pe.Node(fsl.ApplyMask(), name='apply_mask') copy_xform = pe.Node(CopyXForm(), name='copy_xform', mem_gb=0.1, run_without_submitting=True) mask_reportlet = pe.Node(SimpleShowMaskRPT(), name='mask_reportlet') workflow.connect([ (inputnode, n4_correct, [('in_file', 'input_image')]), (inputnode, copy_xform, [('in_file', 'hdr_file')]), (n4_correct, skullstrip_first_pass, [('output_image', 'in_file')]), (skullstrip_first_pass, unifize, [('out_file', 'in_file')]), (unifize, skullstrip_second_pass, [('out_file', 'in_file')]), (skullstrip_first_pass, combine_masks, [('mask_file', 'in_file')]), (skullstrip_second_pass, combine_masks, [('out_file', 'operand_file') ]), (unifize, apply_mask, [('out_file', 'in_file')]), (combine_masks, apply_mask, [('out_file', 'mask_file')]), (n4_correct, mask_reportlet, [('output_image', 'background_file')]), (combine_masks, mask_reportlet, [('out_file', 'mask_file')]), (combine_masks, outputnode, [('out_file', 'mask_file')]), (mask_reportlet, outputnode, [('out_report', 'out_report')]), (apply_mask, copy_xform, [('out_file', 'in_file')]), (copy_xform, outputnode, [('out_file', 'skull_stripped_file')]), (n4_correct, outputnode, [('output_image', 'bias_corrected_file')]), ]) return workflow
def epi_mni_align(settings, name='SpatialNormalization'): """ Uses FSL FLIRT with the BBR cost function to find the transform that maps the EPI space into the MNI152-nonlinear-symmetric atlas. 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 wf = epi_mni_align({}) """ from niworkflows.data import get_mni_icbm152_nlin_asym_09c as get_template from niworkflows.interfaces.registration import (RobustMNINormalizationRPT as RobustMNINormalization) from pkg_resources import resource_filename as pkgrf # Get settings testing = settings.get('testing', False) n_procs = settings.get('n_procs', 1) ants_nthreads = settings.get('ants_nthreads', DEFAULTS['ants_nthreads']) # Init template mni_template = get_template() 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') epimask = pe.Node(fsl.ApplyMask(), name='EPIApplyMask') n4itk = pe.Node(ants.N4BiasFieldCorrection(dimension=3), name='SharpenEPI') norm = pe.Node(RobustMNINormalization( num_threads=ants_nthreads, float=settings.get('ants_float', False), template='mni_icbm152_nlin_asym_09c', reference_image=pkgrf('mriqc', 'data/mni/2mm_T2_brain.nii.gz'), flavor='testing' if testing else 'precise', moving='EPI', generate_report=True, ), name='EPI2MNI', num_threads=n_procs, mem_gb=3) # Warp segmentation into EPI space invt = pe.Node(ants.ApplyTransforms(float=True, input_image=op.join( mni_template, '1mm_parc.nii.gz'), dimension=3, default_value=0, interpolation='NearestNeighbor'), name='ResampleSegmentation') workflow.connect([ (inputnode, invt, [('epi_mean', 'reference_image')]), (inputnode, n4itk, [('epi_mean', 'input_image')]), (inputnode, epimask, [('epi_mask', 'mask_file')]), (n4itk, epimask, [('output_image', 'in_file')]), (epimask, norm, [('out_file', '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
def init_enhance_and_skullstrip_bold_wf(name='enhance_and_skullstrip_bold_wf', omp_nthreads=1, enhance_t2=False): """ 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 conservative mask using Nilearn's ``create_epi_mask``. 2. 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. 3. Calculate a loose mask using FSL's ``bet``, with one mathematical morphology dilation of one iteration and a sphere of 6mm as structuring element. 4. 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. 5. Calculate a mask using AFNI's ``3dAutomask`` after the contrast enhancement of 4). 6. Calculate a final mask as the intersection of 3) and 5). 7. Apply final mask on the enhanced reference. .. workflow :: :graph2use: orig :simple_form: yes from fmriprep.workflows.bold.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``) omp_nthreads : int number of threads available to parallel nodes enhance_t2 : bool perform logarithmic transform of input BOLD image to improve contrast before calculating the preliminary mask **Inputs** in_file BOLD image (single volume) **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 = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=['in_file']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['mask_file', 'skull_stripped_file', 'bias_corrected_file']), name='outputnode') # Create a loose mask to avoid N4 internal's Otsu mask n4_mask = pe.Node(MaskEPI(upper_cutoff=0.75, enhance_t2=enhance_t2, opening=1, no_sanitize=True), name='n4_mask') # 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), 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') workflow.connect([ (inputnode, n4_mask, [('in_file', 'in_files')]), (inputnode, n4_correct, [('in_file', 'input_image')]), (inputnode, fixhdr_unifize, [('in_file', 'hdr_file')]), (inputnode, fixhdr_skullstrip2, [('in_file', 'hdr_file')]), (n4_mask, n4_correct, [('out_mask', 'mask_image')]), (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
def init_fmap_wf(reportlets_dir, omp_nthreads, fmap_bspline, name='fmap_wf'): """ Fieldmap workflow - when we have a sequence that directly measures the fieldmap we just need to mask it (using the corresponding magnitude image) to remove the noise in the surrounding air region, and ensure that units are Hz. .. workflow :: :graph2use: orig :simple_form: yes from fmriprep.workflows.fieldmap.fmap import init_fmap_wf wf = init_fmap_wf(reportlets_dir='.', omp_nthreads=6, fmap_bspline=False) """ workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface( fields=['magnitude', 'fieldmap']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=['fmap', 'fmap_ref', 'fmap_mask']), name='outputnode') # Merge input magnitude images magmrg = pe.Node(IntraModalMerge(), name='magmrg') # Merge input fieldmap images fmapmrg = pe.Node(IntraModalMerge(zero_based_avg=False, hmc=False), name='fmapmrg') # de-gradient the fields ("bias/illumination artifact") n4_correct = pe.Node(ants.N4BiasFieldCorrection(dimension=3, copy_header=True), name='n4_correct', n_procs=omp_nthreads) bet = pe.Node(BETRPT(generate_report=True, frac=0.6, mask=True), name='bet') ds_fmap_mask = pe.Node(DerivativesDataSink( base_directory=reportlets_dir, suffix='fmap_mask'), name='ds_fmap_mask', run_without_submitting=True) workflow.connect([ (inputnode, magmrg, [('magnitude', 'in_files')]), (inputnode, fmapmrg, [('fieldmap', 'in_files')]), (magmrg, n4_correct, [('out_file', 'input_image')]), (n4_correct, bet, [('output_image', 'in_file')]), (bet, outputnode, [('mask_file', 'fmap_mask'), ('out_file', 'fmap_ref')]), (inputnode, ds_fmap_mask, [('fieldmap', 'source_file')]), (bet, ds_fmap_mask, [('out_report', 'in_file')]), ]) if fmap_bspline: # despike_threshold=1.0, mask_erode=1), fmapenh = pe.Node(FieldEnhance(unwrap=False, despike=False), name='fmapenh', mem_gb=4, n_procs=omp_nthreads) workflow.connect([ (bet, fmapenh, [('mask_file', 'in_mask'), ('out_file', 'in_magnitude')]), (fmapmrg, fmapenh, [('out_file', 'in_file')]), (fmapenh, outputnode, [('out_file', 'fmap')]), ]) else: torads = pe.Node(niu.Function(output_names=['out_file', 'cutoff_hz'], function=_torads), name='torads') prelude = pe.Node(fsl.PRELUDE(), name='prelude') tohz = pe.Node(niu.Function(function=_tohz), name='tohz') denoise = pe.Node(fsl.SpatialFilter(operation='median', kernel_shape='sphere', kernel_size=3), name='denoise') demean = pe.Node(niu.Function(function=demean_image), name='demean') cleanup_wf = cleanup_edge_pipeline(name='cleanup_wf') applymsk = pe.Node(fsl.ApplyMask(), name='applymsk') workflow.connect([ (bet, prelude, [('mask_file', 'mask_file'), ('out_file', 'magnitude_file')]), (fmapmrg, torads, [('out_file', 'in_file')]), (torads, tohz, [('cutoff_hz', 'cutoff_hz')]), (torads, prelude, [('out_file', 'phase_file')]), (prelude, tohz, [('unwrapped_phase_file', 'in_file')]), (tohz, denoise, [('out', 'in_file')]), (denoise, demean, [('out_file', 'in_file')]), (demean, cleanup_wf, [('out', 'inputnode.in_file')]), (bet, cleanup_wf, [('mask_file', 'inputnode.in_mask')]), (cleanup_wf, applymsk, [('outputnode.out_file', 'in_file')]), (bet, applymsk, [('mask_file', 'mask_file')]), (applymsk, outputnode, [('out_file', 'fmap')]), ]) 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