def create_wf_c3d_fsl_to_itk(map_node, input_image_type=0, name='create_wf_c3d_fsl_to_itk'): """ Converts an FSL-format output matrix to an ITK-format (ANTS) matrix for use with ANTS registration tools. Parameters ---------- name : string, optional Name of the workflow. Returns ------- fsl_to_itk_conversion : nipype.pipeline.engine.Workflow Notes ----- Workflow Inputs:: inputspec.affine_file : string (nifti file) Output matrix of FSL-based functional to anatomical registration inputspec.reference_file : string (nifti file) File of skull-stripped anatomical brain to be used in affine conversion inputspec.source_file : string (nifti file) Should match the input of the apply warp (in_file) unless you are applying the warp to a 4-d file, in which case this file should be a mean_functional file Workflow Outputs:: outputspec.itk_transform : string (nifti file) Converted affine transform in ITK format usable with ANTS """ import nipype.interfaces.c3 as c3 from nipype.interfaces.utility import Function from CPAC.registration.utils import change_itk_transform_type from nipype.interfaces.afni import preprocess fsl_to_itk_conversion = pe.Workflow(name=name) inputspec = pe.Node(util.IdentityInterface(fields=['affine_file', 'reference_file', 'source_file']), name='inputspec') # converts FSL-format .mat affine xfm into ANTS-format .txt # .mat affine comes from Func->Anat registration if map_node == 0: fsl_reg_2_itk = pe.Node(c3.C3dAffineTool(), name='fsl_reg_2_itk') elif map_node == 1: fsl_reg_2_itk = pe.MapNode(c3.C3dAffineTool(), name='fsl_reg_2_itk_mapnode', iterfield=['source_file']) fsl_reg_2_itk.inputs.itk_transform = True fsl_reg_2_itk.inputs.fsl2ras = True itk_imports = ['import os'] if map_node == 0: change_transform = pe.Node(util.Function( input_names=['input_affine_file'], output_names=['updated_affine_file'], function=change_itk_transform_type, imports=itk_imports), name='change_transform_type') elif map_node == 1: change_transform = pe.MapNode(util.Function( input_names=['input_affine_file'], output_names=['updated_affine_file'], function=change_itk_transform_type, imports=itk_imports), name='change_transform_type', iterfield=['input_affine_file']) outputspec = pe.Node(util.IdentityInterface(fields=['itk_transform']), name='outputspec') fsl_to_itk_conversion.connect(inputspec, 'affine_file', fsl_reg_2_itk, 'transform_file') fsl_to_itk_conversion.connect(inputspec, 'reference_file', fsl_reg_2_itk, 'reference_file') # source_file input of the conversion must be a 3D file, so if the source # file is 4D (input_image_type=3), average it into a 3D file first if input_image_type == 0: fsl_to_itk_conversion.connect(inputspec, 'source_file', fsl_reg_2_itk, 'source_file') elif input_image_type == 3: try: tstat_source = pe.Node(interface=preprocess.TStat(), name='fsl_to_itk_tcat_source') except AttributeError: from nipype.interfaces.afni import utils as afni_utils tstat_source = pe.Node(interface=afni_utils.TStat(), name='fsl_to_itk_tcat_source') tstat_source.inputs.outputtype = 'NIFTI_GZ' tstat_source.inputs.options = '-mean' fsl_to_itk_conversion.connect(inputspec, 'source_file', tstat_source, 'in_file') fsl_to_itk_conversion.connect(tstat_source, 'out_file', fsl_reg_2_itk, 'source_file') fsl_to_itk_conversion.connect(fsl_reg_2_itk, 'itk_transform', change_transform, 'input_affine_file') fsl_to_itk_conversion.connect(change_transform, 'updated_affine_file', outputspec, 'itk_transform') return fsl_to_itk_conversion
def create_func_preproc(use_bet=False, wf_name='func_preproc'): """ The main purpose of this workflow is to process functional data. Raw rest file is deobliqued and reoriented into RPI. Then take the mean intensity values over all time points for each voxel and use this image to calculate motion parameters. The image is then skullstripped, normalized and a processed mask is obtained to use it further in Image analysis. Parameters ---------- wf_name : string Workflow name Returns ------- func_preproc : workflow object Functional Preprocessing workflow object Notes ----- `Source <https://github.com/FCP-INDI/C-PAC/blob/master/CPAC/func_preproc/func_preproc.py>`_ Workflow Inputs:: inputspec.rest : func/rest file or a list of func/rest nifti file User input functional(T2) Image, in any of the 8 orientations scan_params.tr : string Subject TR scan_params.acquistion : string Acquisition pattern (interleaved/sequential, ascending/descending) scan_params.ref_slice : integer Reference slice for slice timing correction Workflow Outputs:: outputspec.refit : string (nifti file) Path to deobliqued anatomical data outputspec.reorient : string (nifti file) Path to RPI oriented anatomical data outputspec.motion_correct_ref : string (nifti file) Path to Mean intensity Motion corrected image (base reference image for the second motion correction run) outputspec.motion_correct : string (nifti file) Path to motion corrected output file outputspec.max_displacement : string (Mat file) Path to maximum displacement (in mm) for brain voxels in each volume outputspec.movement_parameters : string (Mat file) Path to 1D file containing six movement/motion parameters(3 Translation, 3 Rotations) in different columns (roll pitch yaw dS dL dP) outputspec.skullstrip : string (nifti file) Path to skull stripped Motion Corrected Image outputspec.mask : string (nifti file) Path to brain-only mask outputspec.example_func : string (nifti file) Mean, Skull Stripped, Motion Corrected output T2 Image path (Image with mean intensity values across voxels) outputpsec.preprocessed : string (nifti file) output skull stripped, motion corrected T2 image with normalized intensity values outputspec.preprocessed_mask : string (nifti file) Mask obtained from normalized preprocessed image Order of commands: - Deobliqing the scans. For details see `3drefit <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3drefit.html>`_:: 3drefit -deoblique rest_3dc.nii.gz - Re-orienting the Image into Right-to-Left Posterior-to-Anterior Inferior-to-Superior (RPI) orientation. For details see `3dresample <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dresample.html>`_:: 3dresample -orient RPI -prefix rest_3dc_RPI.nii.gz -inset rest_3dc.nii.gz - Calculate voxel wise statistics. Get the RPI Image with mean intensity values over all timepoints for each voxel. For details see `3dTstat <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dTstat.html>`_:: 3dTstat -mean -prefix rest_3dc_RPI_3dT.nii.gz rest_3dc_RPI.nii.gz - Motion Correction. For details see `3dvolreg <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dvolreg.html>`_:: 3dvolreg -Fourier -twopass -base rest_3dc_RPI_3dT.nii.gz/ -zpad 4 -maxdisp1D rest_3dc_RPI_3dvmd1D.1D -1Dfile rest_3dc_RPI_3dv1D.1D -prefix rest_3dc_RPI_3dv.nii.gz rest_3dc_RPI.nii.gz The base image or the reference image is the mean intensity RPI image obtained in the above the step.For each volume in RPI-oriented T2 image, the command, aligns the image with the base mean image and calculates the motion, displacement and movement parameters. It also outputs the aligned 4D volume and movement and displacement parameters for each volume. - Calculate voxel wise statistics. Get the motion corrected output Image from the above step, with mean intensity values over all timepoints for each voxel. For details see `3dTstat <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dTstat.html>`_:: 3dTstat -mean -prefix rest_3dc_RPI_3dv_3dT.nii.gz rest_3dc_RPI_3dv.nii.gz - Motion Correction and get motion, movement and displacement parameters. For details see `3dvolreg <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dvolreg.html>`_:: 3dvolreg -Fourier -twopass -base rest_3dc_RPI_3dv_3dT.nii.gz -zpad 4 -maxdisp1D rest_3dc_RPI_3dvmd1D.1D -1Dfile rest_3dc_RPI_3dv1D.1D -prefix rest_3dc_RPI_3dv.nii.gz rest_3dc_RPI.nii.gz The base image or the reference image is the mean intensity motion corrected image obtained from the above the step (first 3dvolreg run). For each volume in RPI-oriented T2 image, the command, aligns the image with the base mean image and calculates the motion, displacement and movement parameters. It also outputs the aligned 4D volume and movement and displacement parameters for each volume. - Create a brain-only mask. For details see `3dautomask <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dAutomask.html>`_:: 3dAutomask -prefix rest_3dc_RPI_3dv_automask.nii.gz rest_3dc_RPI_3dv.nii.gz - Edge Detect(remove skull) and get the brain only. For details see `3dcalc <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dcalc.html>`_:: 3dcalc -a rest_3dc_RPI_3dv.nii.gz -b rest_3dc_RPI_3dv_automask.nii.gz -expr 'a*b' -prefix rest_3dc_RPI_3dv_3dc.nii.gz - Normalizing the image intensity values. For details see `fslmaths <http://www.fmrib.ox.ac.uk/fsl/avwutils/index.html>`_:: fslmaths rest_3dc_RPI_3dv_3dc.nii.gz -ing 10000 rest_3dc_RPI_3dv_3dc_maths.nii.gz -odt float Normalized intensity = (TrueValue*10000)/global4Dmean - Calculate mean of skull stripped image. For details see `3dTstat <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dTstat.html>`_:: 3dTstat -mean -prefix rest_3dc_RPI_3dv_3dc_3dT.nii.gz rest_3dc_RPI_3dv_3dc.nii.gz - Create Mask (Generate mask from Normalized data). For details see `fslmaths <http://www.fmrib.ox.ac.uk/fsl/avwutils/index.html>`_:: fslmaths rest_3dc_RPI_3dv_3dc_maths.nii.gz -Tmin -bin rest_3dc_RPI_3dv_3dc_maths_maths.nii.gz -odt char High Level Workflow Graph: .. image:: ../images/func_preproc.dot.png :width: 1000 Detailed Workflow Graph: .. image:: ../images/func_preproc_detailed.dot.png :width: 1000 Examples -------- >>> import func_preproc >>> preproc = create_func_preproc(bet=True) >>> preproc.inputs.inputspec.func='sub1/func/rest.nii.gz' >>> preproc.run() #doctest: +SKIP >>> import func_preproc >>> preproc = create_func_preproc(bet=False) >>> preproc.inputs.inputspec.func='sub1/func/rest.nii.gz' >>> preproc.run() #doctest: +SKIP """ preproc = pe.Workflow(name=wf_name) inputNode = pe.Node(util.IdentityInterface(fields=['func']), name='inputspec') outputNode = pe.Node( util.IdentityInterface(fields=[ 'refit', 'reorient', 'reorient_mean', 'motion_correct', 'motion_correct_ref', 'movement_parameters', 'max_displacement', # 'xform_matrix', 'mask', 'skullstrip', 'example_func', 'preprocessed', 'preprocessed_mask', 'slice_time_corrected', 'oned_matrix_save' ]), name='outputspec') try: from nipype.interfaces.afni import utils as afni_utils func_deoblique = pe.Node(interface=afni_utils.Refit(), name='func_deoblique') except ImportError: func_deoblique = pe.Node(interface=preprocess.Refit(), name='func_deoblique') func_deoblique.inputs.deoblique = True preproc.connect(inputNode, 'func', func_deoblique, 'in_file') try: func_reorient = pe.Node(interface=afni_utils.Resample(), name='func_reorient') except UnboundLocalError: func_reorient = pe.Node(interface=preprocess.Resample(), name='func_reorient') func_reorient.inputs.orientation = 'RPI' func_reorient.inputs.outputtype = 'NIFTI_GZ' preproc.connect(func_deoblique, 'out_file', func_reorient, 'in_file') preproc.connect(func_reorient, 'out_file', outputNode, 'reorient') try: func_get_mean_RPI = pe.Node(interface=afni_utils.TStat(), name='func_get_mean_RPI') except UnboundLocalError: func_get_mean_RPI = pe.Node(interface=preprocess.TStat(), name='func_get_mean_RPI') func_get_mean_RPI.inputs.options = '-mean' func_get_mean_RPI.inputs.outputtype = 'NIFTI_GZ' preproc.connect(func_reorient, 'out_file', func_get_mean_RPI, 'in_file') # calculate motion parameters func_motion_correct = pe.Node(interface=preprocess.Volreg(), name='func_motion_correct') func_motion_correct.inputs.args = '-Fourier -twopass' func_motion_correct.inputs.zpad = 4 func_motion_correct.inputs.outputtype = 'NIFTI_GZ' preproc.connect(func_reorient, 'out_file', func_motion_correct, 'in_file') preproc.connect(func_get_mean_RPI, 'out_file', func_motion_correct, 'basefile') func_get_mean_motion = func_get_mean_RPI.clone('func_get_mean_motion') preproc.connect(func_motion_correct, 'out_file', func_get_mean_motion, 'in_file') preproc.connect(func_get_mean_motion, 'out_file', outputNode, 'motion_correct_ref') func_motion_correct_A = func_motion_correct.clone('func_motion_correct_A') func_motion_correct_A.inputs.md1d_file = 'max_displacement.1D' preproc.connect(func_reorient, 'out_file', func_motion_correct_A, 'in_file') preproc.connect(func_get_mean_motion, 'out_file', func_motion_correct_A, 'basefile') preproc.connect(func_motion_correct_A, 'out_file', outputNode, 'motion_correct') preproc.connect(func_motion_correct_A, 'md1d_file', outputNode, 'max_displacement') preproc.connect(func_motion_correct_A, 'oned_file', outputNode, 'movement_parameters') preproc.connect(func_motion_correct_A, 'oned_matrix_save', outputNode, 'oned_matrix_save') if not use_bet: func_get_brain_mask = pe.Node(interface=preprocess.Automask(), name='func_get_brain_mask') func_get_brain_mask.inputs.outputtype = 'NIFTI_GZ' preproc.connect(func_motion_correct_A, 'out_file', func_get_brain_mask, 'in_file') preproc.connect(func_get_brain_mask, 'out_file', outputNode, 'mask') else: func_get_brain_mask = pe.Node(interface=fsl.BET(), name='func_get_brain_mask_BET') func_get_brain_mask.inputs.mask = True func_get_brain_mask.inputs.functional = True erode_one_voxel = pe.Node(interface=fsl.ErodeImage(), name='erode_one_voxel') erode_one_voxel.inputs.kernel_shape = 'box' erode_one_voxel.inputs.kernel_size = 1.0 preproc.connect(func_motion_correct_A, 'out_file', func_get_brain_mask, 'in_file') preproc.connect(func_get_brain_mask, 'mask_file', erode_one_voxel, 'in_file') preproc.connect(erode_one_voxel, 'out_file', outputNode, 'mask') try: func_edge_detect = pe.Node(interface=afni_utils.Calc(), name='func_edge_detect') except UnboundLocalError: func_edge_detect = pe.Node(interface=preprocess.Calc(), name='func_edge_detect') func_edge_detect.inputs.expr = 'a*b' func_edge_detect.inputs.outputtype = 'NIFTI_GZ' preproc.connect(func_motion_correct_A, 'out_file', func_edge_detect, 'in_file_a') if not use_bet: preproc.connect(func_get_brain_mask, 'out_file', func_edge_detect, 'in_file_b') else: preproc.connect(erode_one_voxel, 'out_file', func_edge_detect, 'in_file_b') preproc.connect(func_edge_detect, 'out_file', outputNode, 'skullstrip') try: func_mean_skullstrip = pe.Node(interface=afni_utils.TStat(), name='func_mean_skullstrip') except UnboundLocalError: func_mean_skullstrip = pe.Node(interface=preprocess.TStat(), name='func_mean_skullstrip') func_mean_skullstrip.inputs.options = '-mean' func_mean_skullstrip.inputs.outputtype = 'NIFTI_GZ' preproc.connect(func_edge_detect, 'out_file', func_mean_skullstrip, 'in_file') preproc.connect(func_mean_skullstrip, 'out_file', outputNode, 'example_func') func_normalize = pe.Node(interface=fsl.ImageMaths(), name='func_normalize') func_normalize.inputs.op_string = '-ing 10000' func_normalize.inputs.out_data_type = 'float' preproc.connect(func_edge_detect, 'out_file', func_normalize, 'in_file') preproc.connect(func_normalize, 'out_file', outputNode, 'preprocessed') func_mask_normalize = pe.Node(interface=fsl.ImageMaths(), name='func_mask_normalize') func_mask_normalize.inputs.op_string = '-Tmin -bin' func_mask_normalize.inputs.out_data_type = 'char' preproc.connect(func_normalize, 'out_file', func_mask_normalize, 'in_file') preproc.connect(func_mask_normalize, 'out_file', outputNode, 'preprocessed_mask') return preproc
def create_alff(wf_name='alff_workflow'): """ Calculate Amplitude of low frequency oscillations (ALFF) and fractional ALFF maps Parameters ---------- wf_name : string Workflow name Returns ------- alff_workflow : workflow object ALFF workflow Notes ----- `Source <https://github.com/FCP-INDI/C-PAC/blob/master/CPAC/alff/alff.py>`_ Workflow Inputs:: hp_input.hp : list of float high pass frequencies lp_input.lp : list of float low pass frequencies inputspec.rest_res : string Path to existing Nifti file. Nuisance signal regressed functional image. inputspec.rest_mask : string Path to existing Nifti file. A mask volume(derived by dilating the motion corrected functional volume) in native space Workflow Outputs:: outputspec.alff_img : string Path to Nifti file. Image containing the sum of the amplitudes in the low frequency band outputspec.falff_img : string Path to Nifti file. Image containing the sum of the amplitudes in the low frequency band divided by the amplitude of the total frequency outputspec.alff_Z_img : string Path to Nifti file. Image containing Normalized ALFF Z scores across full brain in native space outputspec.falff_Z_img : string Path to Nifti file. Image containing Normalized fALFF Z scores across full brain in native space Order of Commands: - Filter the input file rest file( slice-time, motion corrected and nuisance regressed) :: 3dBandpass -prefix residual_filtered.nii.gz 0.009 0.08 residual.nii.gz - Calculate ALFF by taking the standard deviation of the filtered file :: 3dTstat -stdev -mask rest_mask.nii.gz -prefix residual_filtered_3dT.nii.gz residual_filtered.nii.gz - Calculate the standard deviation of the unfiltered file :: 3dTstat -stdev -mask rest_mask.nii.gz -prefix residual_3dT.nii.gz residual.nii.gz - Calculate fALFF :: 3dcalc -a rest_mask.nii.gz -b residual_filtered_3dT.nii.gz -c residual_3dT.nii.gz -expr '(1.0*bool(a))*((1.0*b)/(1.0*c))' -float - Normalize ALFF/fALFF to Z-score across full brain :: fslstats ALFF.nii.gz -k rest_mask.nii.gz -m > mean_ALFF.txt ; mean=$( cat mean_ALFF.txt ) fslstats ALFF.nii.gz -k rest_mask.nii.gz -s > std_ALFF.txt ; std=$( cat std_ALFF.txt ) fslmaths ALFF.nii.gz -sub ${mean} -div ${std} -mas rest_mask.nii.gz ALFF_Z.nii.gz fslstats fALFF.nii.gz -k rest_mask.nii.gz -m > mean_fALFF.txt ; mean=$( cat mean_fALFF.txt ) fslstats fALFF.nii.gz -k rest_mask.nii.gz -s > std_fALFF.txt std=$( cat std_fALFF.txt ) fslmaths fALFF.nii.gz -sub ${mean} -div ${std} -mas rest_mask.nii.gz fALFF_Z.nii.gz High Level Workflow Graph: .. image:: ../images/alff.dot.png :width: 500 Detailed Workflow Graph: .. image:: ../images/alff_detailed.dot.png :width: 500 References ---------- .. [1] Zou, Q.-H., Zhu, C.-Z., Yang, Y., Zuo, X.-N., Long, X.-Y., Cao, Q.-J., Wang, Y.-F., et al. (2008). An improved approach to detection of amplitude of low-frequency fluctuation (ALFF) for resting-state fMRI: fractional ALFF. Journal of neuroscience methods, 172(1), 137-41. doi:10.10 Examples -------- >>> alff_w = create_alff() >>> alff_w.inputs.hp_input.hp = [0.01] >>> alff_w.inputs.lp_input.lp = [0.1] >>> alff_w.get_node('hp_input').iterables = ('hp', [0.01]) >>> alff_w.get_node('lp_input').iterables = ('lp', [0.1]) >>> alff_w.inputs.inputspec.rest_res = '/home/data/subject/func/rest_bandpassed.nii.gz' >>> alff_w.inputs.inputspec.rest_mask= '/home/data/subject/func/rest_mask.nii.gz' >>> alff_w.run() # doctest: +SKIP """ wf = pe.Workflow(name=wf_name) input_node = pe.Node( util.IdentityInterface(fields=['rest_res', 'rest_mask']), name='inputspec') input_node_hp = pe.Node(util.IdentityInterface(fields=['hp']), name='hp_input') input_node_lp = pe.Node(util.IdentityInterface(fields=['lp']), name='lp_input') output_node = pe.Node( util.IdentityInterface(fields=['alff_img', 'falff_img']), name='outputspec') # filtering bandpass = pe.Node(interface=preprocess.Bandpass(), name='bandpass_filtering') bandpass.inputs.outputtype = 'NIFTI_GZ' bandpass.inputs.out_file = os.path.join(os.path.curdir, 'residual_filtered.nii.gz') wf.connect(input_node_hp, 'hp', bandpass, 'highpass') wf.connect(input_node_lp, 'lp', bandpass, 'lowpass') wf.connect(input_node, 'rest_res', bandpass, 'in_file') get_option_string = pe.Node(util.Function(input_names=['mask'], output_names=['option_string'], function=get_opt_string), name='get_option_string') wf.connect(input_node, 'rest_mask', get_option_string, 'mask') # standard deviation over frequency try: from nipype.interfaces.afni import utils as afni_utils stddev_filtered = pe.Node(interface=afni_utils.TStat(), name='stddev_filtered') except ImportError: stddev_filtered = pe.Node(interface=preprocess.TStat(), name='stddev_filtered') stddev_filtered.inputs.outputtype = 'NIFTI_GZ' stddev_filtered.inputs.out_file = os.path.join(os.path.curdir, 'alff.nii.gz') wf.connect(bandpass, 'out_file', stddev_filtered, 'in_file') wf.connect(get_option_string, 'option_string', stddev_filtered, 'options') wf.connect(stddev_filtered, 'out_file', output_node, 'alff_img') # standard deviation of the unfiltered nuisance corrected image try: stddev_unfiltered = pe.Node(interface=afni_utils.TStat(), name='stddev_unfiltered') except UnboundLocalError: stddev_unfiltered = pe.Node(interface=preprocess.TStat(), name='stddev_unfiltered') stddev_unfiltered.inputs.outputtype = 'NIFTI_GZ' stddev_unfiltered.inputs.out_file = os.path.join(os.path.curdir, 'residual_3dT.nii.gz') wf.connect(input_node, 'rest_res', stddev_unfiltered, 'in_file') wf.connect(get_option_string, 'option_string', stddev_unfiltered, 'options') # falff calculations try: falff = pe.Node(interface=afni_utils.Calc(), name='falff') except UnboundLocalError: falff = pe.Node(interface=preprocess.Calc(), name='falff') falff.inputs.args = '-float' falff.inputs.expr = '(1.0*bool(a))*((1.0*b)/(1.0*c))' falff.inputs.outputtype = 'NIFTI_GZ' falff.inputs.out_file = os.path.join(os.path.curdir, 'falff.nii.gz') wf.connect(input_node, 'rest_mask', falff, 'in_file_a') wf.connect(stddev_filtered, 'out_file', falff, 'in_file_b') wf.connect(stddev_unfiltered, 'out_file', falff, 'in_file_c') wf.connect(falff, 'out_file', output_node, 'falff_img') return wf
def create_asl_preproc(c, strat, wf_name='asl_preproc'): # resource_pool = strat? # print('resource pool asl preproc: ', str(strat.get_resource_pool())) # allocate a workflow object asl_workflow = pe.Workflow(name=wf_name) asl_workflow.base_dir = c.workingDirectory # configure the workflow's input spec inputNode = pe.Node(util.IdentityInterface(fields=[ 'asl_file', 'anatomical_skull', 'anatomical_brain', 'seg_wm_pve' ]), name='inputspec') # configure the workflow's output spec outputNode = pe.Node(util.IdentityInterface( fields=['meanasl', 'perfusion_image', 'diffdata', 'diffdata_mean']), name='outputspec') # get segmentation output dir and file stub # create nodes for de-obliquing and reorienting try: from nipype.interfaces.afni import utils as afni_utils func_deoblique = pe.Node(interface=afni_utils.Refit(), name='func_deoblique') except ImportError: func_deoblique = pe.Node(interface=preprocess.Refit(), name='func_deoblique') func_deoblique.inputs.deoblique = True asl_workflow.connect(inputNode, 'asl_file', func_deoblique, 'in_file') try: func_reorient = pe.Node(interface=afni_utils.Resample(), name='func_reorient') except UnboundLocalError: func_reorient = pe.Node(interface=preprocess.Resample(), name='func_reorient') func_reorient.inputs.orientation = 'RPI' func_reorient.inputs.outputtype = 'NIFTI_GZ' # connect deoblique to reorient asl_workflow.connect(func_deoblique, 'out_file', func_reorient, 'in_file') # create node for splitting control and label pairs (unused currently) split_pairs_imports = ['import os', 'import subprocess'] split_ASL_pairs = pe.Node(interface=util.Function( input_names=['asl_file'], output_names=['control_image', 'label_image'], function=split_pairs, imports=split_pairs_imports), name='split_pairs') # create node for calculating subtracted images diffdata_imports = ['import os', 'import subprocess'] run_diffdata = pe.Node(interface=util.Function( input_names=['asl_file'], output_names=['diffdata_image', 'diffdata_mean'], function=diffdata, imports=diffdata_imports), name='diffdata') asl_workflow.connect(func_reorient, 'out_file', run_diffdata, 'asl_file') asl_workflow.connect(run_diffdata, 'diffdata_image', outputNode, 'diffdata') asl_workflow.connect(run_diffdata, 'diffdata_mean', outputNode, 'diffdata_mean') # create node for oxford_asl (perfusion image) asl_imports = ['import os', 'import subprocess'] run_oxford_asl = pe.Node(interface=util.Function( input_names=[ 'asl_file', 'anatomical_skull', 'anatomical_brain', 'seg' ], output_names=['perfusion_image', 'asl2anat_linear_xfm', 'asl2anat'], function=oxford_asl, imports=asl_imports), name='run_oxford_asl') # wire inputs from resource pool to ASL preprocessing FSL script # connect output of reorient to run_oxford_asl asl_workflow.connect(func_reorient, 'out_file', run_oxford_asl, 'asl_file') asl_workflow.connect(inputNode, 'seg_wm_pve', run_oxford_asl, 'seg') # pass the anatomical to the workflow asl_workflow.connect(inputNode, 'anatomical_skull', run_oxford_asl, 'anatomical_skull') # pass the anatomical to the workflow asl_workflow.connect(inputNode, 'anatomical_brain', run_oxford_asl, 'anatomical_brain') # connect oxford_asl outputs to outputNode asl_workflow.connect(run_oxford_asl, 'asl2anat_linear_xfm', outputNode, 'asl2anat_linear_xfm') asl_workflow.connect(run_oxford_asl, 'asl2anat', outputNode, 'asl2anat') asl_workflow.connect(run_oxford_asl, 'perfusion_image', outputNode, 'perfusion_image') strat.update_resource_pool({ 'mean_asl_in_anat': (run_oxford_asl, 'anat_asl'), 'asl_to_anat_linear_xfm': (run_oxford_asl, 'asl2anat_linear_xfm') }) # Take mean of the asl data for registration try: get_mean_asl = pe.Node(interface=afni_utils.TStat(), name='get_mean_asl') except UnboundLocalError: get_mean_asl = pe.Node(interface=preprocess.TStat(), name='get_mean_asl') get_mean_asl.inputs.options = '-mean' get_mean_asl.inputs.outputtype = 'NIFTI_GZ' asl_workflow.connect(func_reorient, 'out_file', get_mean_asl, 'in_file') asl_workflow.connect(get_mean_asl, 'out_file', outputNode, 'meanasl') return asl_workflow
def create_func_preproc(skullstrip_tool, n4_correction, anatomical_mask_dilation=False, wf_name='func_preproc'): """ The main purpose of this workflow is to process functional data. Raw rest file is deobliqued and reoriented into RPI. Then take the mean intensity values over all time points for each voxel and use this image to calculate motion parameters. The image is then skullstripped, normalized and a processed mask is obtained to use it further in Image analysis. Parameters ---------- wf_name : string Workflow name Returns ------- func_preproc : workflow object Functional Preprocessing workflow object Notes ----- `Source <https://github.com/FCP-INDI/C-PAC/blob/master/CPAC/func_preproc/func_preproc.py>`_ Workflow Inputs:: inputspec.func : func nifti file User input functional(T2) Image, in any of the 8 orientations inputspec.twopass : boolean Perform two-pass on volume registration Workflow Outputs:: outputspec.refit : string (nifti file) Path to deobliqued anatomical data outputspec.reorient : string (nifti file) Path to RPI oriented anatomical data outputspec.motion_correct_ref : string (nifti file) Path to Mean intensity Motion corrected image (base reference image for the second motion correction run) outputspec.motion_correct : string (nifti file) Path to motion corrected output file outputspec.max_displacement : string (Mat file) Path to maximum displacement (in mm) for brain voxels in each volume outputspec.movement_parameters : string (Mat file) Path to 1D file containing six movement/motion parameters(3 Translation, 3 Rotations) in different columns (roll pitch yaw dS dL dP) outputspec.skullstrip : string (nifti file) Path to skull stripped Motion Corrected Image outputspec.mask : string (nifti file) Path to brain-only mask outputspec.func_mean : string (nifti file) Mean, Skull Stripped, Motion Corrected output T2 Image path (Image with mean intensity values across voxels) outputpsec.preprocessed : string (nifti file) output skull stripped, motion corrected T2 image with normalized intensity values outputspec.preprocessed_mask : string (nifti file) Mask obtained from normalized preprocessed image Order of commands: - Deobliqing the scans. For details see `3drefit <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3drefit.html>`_:: 3drefit -deoblique rest_3dc.nii.gz - Re-orienting the Image into Right-to-Left Posterior-to-Anterior Inferior-to-Superior (RPI) orientation. For details see `3dresample <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dresample.html>`_:: 3dresample -orient RPI -prefix rest_3dc_RPI.nii.gz -inset rest_3dc.nii.gz - Calculate voxel wise statistics. Get the RPI Image with mean intensity values over all timepoints for each voxel. For details see `3dTstat <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dTstat.html>`_:: 3dTstat -mean -prefix rest_3dc_RPI_3dT.nii.gz rest_3dc_RPI.nii.gz - Motion Correction. For details see `3dvolreg <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dvolreg.html>`_:: 3dvolreg -Fourier -twopass -base rest_3dc_RPI_3dT.nii.gz/ -zpad 4 -maxdisp1D rest_3dc_RPI_3dvmd1D.1D -1Dfile rest_3dc_RPI_3dv1D.1D -prefix rest_3dc_RPI_3dv.nii.gz rest_3dc_RPI.nii.gz The base image or the reference image is the mean intensity RPI image obtained in the above the step.For each volume in RPI-oriented T2 image, the command, aligns the image with the base mean image and calculates the motion, displacement and movement parameters. It also outputs the aligned 4D volume and movement and displacement parameters for each volume. - Calculate voxel wise statistics. Get the motion corrected output Image from the above step, with mean intensity values over all timepoints for each voxel. For details see `3dTstat <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dTstat.html>`_:: 3dTstat -mean -prefix rest_3dc_RPI_3dv_3dT.nii.gz rest_3dc_RPI_3dv.nii.gz - Motion Correction and get motion, movement and displacement parameters. For details see `3dvolreg <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dvolreg.html>`_:: 3dvolreg -Fourier -twopass -base rest_3dc_RPI_3dv_3dT.nii.gz -zpad 4 -maxdisp1D rest_3dc_RPI_3dvmd1D.1D -1Dfile rest_3dc_RPI_3dv1D.1D -prefix rest_3dc_RPI_3dv.nii.gz rest_3dc_RPI.nii.gz The base image or the reference image is the mean intensity motion corrected image obtained from the above the step (first 3dvolreg run). For each volume in RPI-oriented T2 image, the command, aligns the image with the base mean image and calculates the motion, displacement and movement parameters. It also outputs the aligned 4D volume and movement and displacement parameters for each volume. - Create a brain-only mask. For details see `3dautomask <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dAutomask.html>`_:: 3dAutomask -prefix rest_3dc_RPI_3dv_automask.nii.gz rest_3dc_RPI_3dv.nii.gz - Edge Detect(remove skull) and get the brain only. For details see `3dcalc <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dcalc.html>`_:: 3dcalc -a rest_3dc_RPI_3dv.nii.gz -b rest_3dc_RPI_3dv_automask.nii.gz -expr 'a*b' -prefix rest_3dc_RPI_3dv_3dc.nii.gz - Normalizing the image intensity values. For details see `fslmaths <http://www.fmrib.ox.ac.uk/fsl/avwutils/index.html>`_:: fslmaths rest_3dc_RPI_3dv_3dc.nii.gz -ing 10000 rest_3dc_RPI_3dv_3dc_maths.nii.gz -odt float Normalized intensity = (TrueValue*10000)/global4Dmean - Calculate mean of skull stripped image. For details see `3dTstat <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dTstat.html>`_:: 3dTstat -mean -prefix rest_3dc_RPI_3dv_3dc_3dT.nii.gz rest_3dc_RPI_3dv_3dc.nii.gz - Create Mask (Generate mask from Normalized data). For details see `fslmaths <http://www.fmrib.ox.ac.uk/fsl/avwutils/index.html>`_:: fslmaths rest_3dc_RPI_3dv_3dc_maths.nii.gz -Tmin -bin rest_3dc_RPI_3dv_3dc_maths_maths.nii.gz -odt char .. exec:: from CPAC.func_preproc import create_func_preproc wf = create_func_preproc() wf.write_graph( graph2use='orig', dotfilename='./images/generated/func_preproc.dot' ) High Level Workflow Graph: .. image:: ../images/generated/func_preproc.png :width: 1000 Detailed Workflow Graph: .. image:: ../images/generated/func_preproc_detailed.png :width: 1000 Examples -------- >>> import func_preproc >>> preproc = create_func_preproc(bet=True) >>> preproc.inputs.inputspec.func='sub1/func/rest.nii.gz' >>> preproc.run() #doctest: +SKIP >>> import func_preproc >>> preproc = create_func_preproc(bet=False) >>> preproc.inputs.inputspec.func='sub1/func/rest.nii.gz' >>> preproc.run() #doctest: +SKIP """ preproc = pe.Workflow(name=wf_name) input_node = pe.Node(util.IdentityInterface( fields=['func', 'twopass', 'anatomical_brain_mask', 'anat_skull']), name='inputspec') output_node = pe.Node(util.IdentityInterface(fields=[ 'refit', 'reorient', 'reorient_mean', 'motion_correct', 'motion_correct_ref', 'movement_parameters', 'max_displacement', 'mask', 'skullstrip', 'func_mean', 'preprocessed', 'preprocessed_mask', 'slice_time_corrected', 'transform_matrices' ]), name='outputspec') func_deoblique = pe.Node(interface=afni_utils.Refit(), name='func_deoblique') func_deoblique.inputs.deoblique = True preproc.connect(input_node, 'func', func_deoblique, 'in_file') func_reorient = pe.Node(interface=afni_utils.Resample(), name='func_reorient') func_reorient.inputs.orientation = 'RPI' func_reorient.inputs.outputtype = 'NIFTI_GZ' preproc.connect(func_deoblique, 'out_file', func_reorient, 'in_file') preproc.connect(func_reorient, 'out_file', output_node, 'reorient') func_get_mean_RPI = pe.Node(interface=afni_utils.TStat(), name='func_get_mean_RPI') func_get_mean_RPI.inputs.options = '-mean' func_get_mean_RPI.inputs.outputtype = 'NIFTI_GZ' preproc.connect(func_reorient, 'out_file', func_get_mean_RPI, 'in_file') # calculate motion parameters func_motion_correct = pe.Node(interface=preprocess.Volreg(), name='func_motion_correct_3dvolreg') func_motion_correct.inputs.zpad = 4 func_motion_correct.inputs.outputtype = 'NIFTI_GZ' preproc.connect([ (input_node, func_motion_correct, [(('twopass', collect_arguments, '-twopass', '-Fourier'), 'args')]), ]) preproc.connect(func_get_mean_RPI, 'out_file', func_motion_correct, 'basefile') preproc.connect(func_reorient, 'out_file', func_motion_correct, 'in_file') func_get_mean_motion = func_get_mean_RPI.clone('func_get_mean_motion') preproc.connect(func_motion_correct, 'out_file', func_get_mean_motion, 'in_file') preproc.connect(func_get_mean_motion, 'out_file', output_node, 'motion_correct_ref') func_motion_correct_A = func_motion_correct.clone('func_motion_correct_A') func_motion_correct_A.inputs.md1d_file = 'max_displacement.1D' preproc.connect([ (input_node, func_motion_correct_A, [(('twopass', collect_arguments, '-twopass', '-Fourier'), 'args')]), ]) preproc.connect(func_reorient, 'out_file', func_motion_correct_A, 'in_file') preproc.connect(func_get_mean_motion, 'out_file', func_motion_correct_A, 'basefile') preproc.connect(func_motion_correct_A, 'out_file', output_node, 'motion_correct') preproc.connect(func_motion_correct_A, 'md1d_file', output_node, 'max_displacement') preproc.connect(func_motion_correct_A, 'oned_file', output_node, 'movement_parameters') preproc.connect(func_motion_correct_A, 'oned_matrix_save', output_node, 'transform_matrices') skullstrip_func = skullstrip_functional(skullstrip_tool, anatomical_mask_dilation, "{0}_skullstrip".format(wf_name)) preproc.connect(func_motion_correct_A, 'out_file', skullstrip_func, 'inputspec.func') preproc.connect(input_node, 'anatomical_brain_mask', skullstrip_func, 'inputspec.anatomical_brain_mask') preproc.connect(input_node, 'anat_skull', skullstrip_func, 'inputspec.anat_skull') preproc.connect(skullstrip_func, 'outputspec.func_brain', output_node, 'skullstrip') preproc.connect(skullstrip_func, 'outputspec.func_brain_mask', output_node, 'mask') func_mean = pe.Node(interface=afni_utils.TStat(), name='func_mean') func_mean.inputs.options = '-mean' func_mean.inputs.outputtype = 'NIFTI_GZ' preproc.connect(skullstrip_func, 'outputspec.func_brain', func_mean, 'in_file') if n4_correction: func_mean_n4_corrected = pe.Node(interface=ants.N4BiasFieldCorrection( dimension=3, copy_header=True, bspline_fitting_distance=200), shrink_factor=2, name='func_mean_n4_corrected') func_mean_n4_corrected.inputs.args = '-r True' # func_mean_n4_corrected.inputs.rescale_intensities = True preproc.connect(func_mean, 'out_file', func_mean_n4_corrected, 'input_image') preproc.connect(func_mean_n4_corrected, 'output_image', output_node, 'func_mean') else: preproc.connect(func_mean, 'out_file', output_node, 'func_mean') func_normalize = pe.Node(interface=fsl.ImageMaths(), name='func_normalize') func_normalize.inputs.op_string = '-ing 10000' func_normalize.inputs.out_data_type = 'float' preproc.connect(skullstrip_func, 'outputspec.func_brain', func_normalize, 'in_file') preproc.connect(func_normalize, 'out_file', output_node, 'preprocessed') func_mask_normalize = pe.Node(interface=fsl.ImageMaths(), name='func_mask_normalize') func_mask_normalize.inputs.op_string = '-Tmin -bin' func_mask_normalize.inputs.out_data_type = 'char' preproc.connect(func_normalize, 'out_file', func_mask_normalize, 'in_file') preproc.connect(func_mask_normalize, 'out_file', output_node, 'preprocessed_mask') return preproc
def skullstrip_functional(skullstrip_tool='afni', anatomical_mask_dilation=False, wf_name='skullstrip_functional'): skullstrip_tool = skullstrip_tool.lower() if skullstrip_tool != 'afni' and skullstrip_tool != 'fsl' and skullstrip_tool != 'fsl_afni' and skullstrip_tool != 'anatomical_refined': raise Exception( "\n\n[!] Error: The 'tool' parameter of the " "'skullstrip_functional' workflow must be either " "'afni' or 'fsl' or 'fsl_afni' or 'anatomical_refined'.\n\nTool input: " "{0}\n\n".format(skullstrip_tool)) wf = pe.Workflow(name=wf_name) input_node = pe.Node(util.IdentityInterface( fields=['func', 'anatomical_brain_mask', 'anat_skull']), name='inputspec') output_node = pe.Node( util.IdentityInterface(fields=['func_brain', 'func_brain_mask']), name='outputspec') if skullstrip_tool == 'afni': func_get_brain_mask = pe.Node(interface=preprocess.Automask(), name='func_get_brain_mask_AFNI') func_get_brain_mask.inputs.outputtype = 'NIFTI_GZ' wf.connect(input_node, 'func', func_get_brain_mask, 'in_file') wf.connect(func_get_brain_mask, 'out_file', output_node, 'func_brain_mask') elif skullstrip_tool == 'fsl': func_get_brain_mask = pe.Node(interface=fsl.BET(), name='func_get_brain_mask_BET') func_get_brain_mask.inputs.mask = True func_get_brain_mask.inputs.functional = True erode_one_voxel = pe.Node(interface=fsl.ErodeImage(), name='erode_one_voxel') erode_one_voxel.inputs.kernel_shape = 'box' erode_one_voxel.inputs.kernel_size = 1.0 wf.connect(input_node, 'func', func_get_brain_mask, 'in_file') wf.connect(func_get_brain_mask, 'mask_file', erode_one_voxel, 'in_file') wf.connect(erode_one_voxel, 'out_file', output_node, 'func_brain_mask') elif skullstrip_tool == 'fsl_afni': skullstrip_first_pass = pe.Node(fsl.BET(frac=0.2, mask=True, functional=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') unifize = pe.Node(afni_utils.Unifize( t2=True, outputtype='NIFTI_GZ', args='-clfrac 0.2 -rbt 18.3 65.0 90.0', out_file="uni.nii.gz"), name='unifize') skullstrip_second_pass = pe.Node(preprocess.Automask( dilate=1, outputtype='NIFTI_GZ'), name='skullstrip_second_pass') combine_masks = pe.Node(fsl.BinaryMaths(operation='mul'), name='combine_masks') wf.connect([ (input_node, skullstrip_first_pass, [('func', '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, 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, output_node, [('out_file', 'func_brain_mask')]) ]) # Refine functional mask by registering anatomical mask to functional space elif skullstrip_tool == 'anatomical_refined': # Get functional mean to use later as reference, when transform anatomical mask to functional space func_skull_mean = pe.Node(interface=afni_utils.TStat(), name='func_skull_mean') func_skull_mean.inputs.options = '-mean' func_skull_mean.inputs.outputtype = 'NIFTI_GZ' wf.connect(input_node, 'func', func_skull_mean, 'in_file') # Register func to anat linear_reg_func_to_anat = pe.Node(interface=fsl.FLIRT(), name='linear_reg_func_to_anat') linear_reg_func_to_anat.inputs.cost = 'mutualinfo' linear_reg_func_to_anat.inputs.dof = 6 wf.connect(func_skull_mean, 'out_file', linear_reg_func_to_anat, 'in_file') wf.connect(input_node, 'anat_skull', linear_reg_func_to_anat, 'reference') # Inverse func to anat affine inv_func_to_anat_affine = pe.Node(interface=fsl.ConvertXFM(), name='inv_func_to_anat_affine') inv_func_to_anat_affine.inputs.invert_xfm = True wf.connect(linear_reg_func_to_anat, 'out_matrix_file', inv_func_to_anat_affine, 'in_file') # Transform anatomical mask to functional space linear_trans_mask_anat_to_func = pe.Node( interface=fsl.FLIRT(), name='linear_trans_mask_anat_to_func') linear_trans_mask_anat_to_func.inputs.apply_xfm = True linear_trans_mask_anat_to_func.inputs.cost = 'mutualinfo' linear_trans_mask_anat_to_func.inputs.dof = 6 linear_trans_mask_anat_to_func.inputs.interp = 'nearestneighbour' # Dialate anatomical mask, if 'anatomical_mask_dilation : True' in config file if anatomical_mask_dilation: anat_mask_dilate = pe.Node(interface=afni.MaskTool(), name='anat_mask_dilate') anat_mask_dilate.inputs.dilate_inputs = '1' anat_mask_dilate.inputs.outputtype = 'NIFTI_GZ' wf.connect(input_node, 'anatomical_brain_mask', anat_mask_dilate, 'in_file') wf.connect(anat_mask_dilate, 'out_file', linear_trans_mask_anat_to_func, 'in_file') else: wf.connect(input_node, 'anatomical_brain_mask', linear_trans_mask_anat_to_func, 'in_file') wf.connect(func_skull_mean, 'out_file', linear_trans_mask_anat_to_func, 'reference') wf.connect(inv_func_to_anat_affine, 'out_file', linear_trans_mask_anat_to_func, 'in_matrix_file') wf.connect(linear_trans_mask_anat_to_func, 'out_file', output_node, 'func_brain_mask') func_edge_detect = pe.Node(interface=afni_utils.Calc(), name='func_extract_brain') func_edge_detect.inputs.expr = 'a*b' func_edge_detect.inputs.outputtype = 'NIFTI_GZ' wf.connect(input_node, 'func', func_edge_detect, 'in_file_a') if skullstrip_tool == 'afni': wf.connect(func_get_brain_mask, 'out_file', func_edge_detect, 'in_file_b') elif skullstrip_tool == 'fsl': wf.connect(erode_one_voxel, 'out_file', func_edge_detect, 'in_file_b') elif skullstrip_tool == 'fsl_afni': wf.connect(combine_masks, 'out_file', func_edge_detect, 'in_file_b') elif skullstrip_tool == 'anatomical_refined': wf.connect(linear_trans_mask_anat_to_func, 'out_file', func_edge_detect, 'in_file_b') wf.connect(func_edge_detect, 'out_file', output_node, 'func_brain') return wf