def create_vmhc(use_ants): """ Compute the map of brain functional homotopy, the high degree of synchrony in spontaneous activity between geometrically corresponding interhemispheric (i.e., homotopic) regions. Parameters ---------- None Returns ------- vmhc_workflow : workflow Voxel Mirrored Homotopic Connectivity Analysis Workflow Notes ----- `Source <https://github.com/FCP-INDI/C-PAC/blob/master/CPAC/vmhc/vmhc.py>`_ Workflow Inputs:: inputspec.brain : string (existing nifti file) Anatomical image(without skull) inputspec.brain_symmetric : string (existing nifti file) MNI152_T1_2mm_brain_symmetric.nii.gz inputspec.rest_res_filt : string (existing nifti file) Band passed Image with nuisance signal regressed out(and optionally scrubbed). Recommended bandpass filter (0.001,0.1) ) inputspec.reorient : string (existing nifti file) RPI oriented anatomical data inputspec.example_func2highres_mat : string (existing affine transformation .mat file) Specifies an affine transform that should be applied to the example_func before non linear warping inputspec.standard : string (existing nifti file) MNI152_T1_standard_resolution_brain.nii.gz inputspec.symm_standard : string (existing nifti file) MNI152_T1_2mm_symmetric.nii.gz inputspec.twomm_brain_mask_dil : string (existing nifti file) MNI152_T1_2mm_brain_mask_symmetric_dil.nii.gz inputspec.config_file_twomm_symmetric : string (existing .cnf file) T1_2_MNI152_2mm_symmetric.cnf inputspec.rest_mask : string (existing nifti file) A mask functional volume(derived by dilation from motion corrected functional volume) fwhm_input.fwhm : list (float) For spatial smoothing the Z-transformed correlations in MNI space. Generally the value of this parameter is 1.5 or 2 times the voxel size of the input Image. inputspec.mean_functional : string (existing nifti file) The mean functional image for use in the func-to-anat registration matrix conversion to ITK (ANTS) format, if the user selects to use ANTS. Workflow Outputs:: outputspec.highres2symmstandard : string (nifti file) Linear registration of T1 image to symmetric standard image outputspec.highres2symmstandard_mat : string (affine transformation .mat file) An affine transformation .mat file from linear registration and used in non linear registration outputspec.highres2symmstandard_warp : string (nifti file) warp file from Non Linear registration of T1 to symmetrical standard brain outputspec.fnirt_highres2symmstandard : string (nifti file) Non Linear registration of T1 to symmetrical standard brain outputspec.highres2symmstandard_jac : string (nifti file) jacobian determinant image from Non Linear registration of T1 to symmetrical standard brain outputspec.rest_res_2symmstandard : string (nifti file) nonlinear registration (func to standard) image outputspec.VMHC_FWHM_img : string (nifti file) pearson correlation between res2standard and flipped res2standard outputspec.VMHC_Z_FWHM_img : string (nifti file) Fisher Z transform map outputspec.VMHC_Z_stat_FWHM_img : string (nifti file) Z statistic map Order of commands: - Perform linear registration of Anatomical brain in T1 space to symmetric standard space. For details see `flirt <http://www.fmrib.ox.ac.uk/fsl/flirt/index.html>`_:: flirt -ref MNI152_T1_2mm_brain_symmetric.nii.gz -in mprage_brain.nii.gz -out highres2symmstandard.nii.gz -omat highres2symmstandard.mat -cost corratio -searchcost corratio -dof 12 -interp trilinear - Perform nonlinear registration (higres to standard) to symmetric standard brain. For details see `fnirt <http://fsl.fmrib.ox.ac.uk/fsl/fnirt/>`_:: fnirt --in=head.nii.gz --aff=highres2symmstandard.mat --cout=highres2symmstandard_warp.nii.gz --iout=fnirt_highres2symmstandard.nii.gz --jout=highres2symmstandard_jac.nii.gz --config=T1_2_MNI152_2mm_symmetric.cnf --ref=MNI152_T1_2mm_symmetric.nii.gz --refmask=MNI152_T1_2mm_brain_mask_symmetric_dil.nii.gz --warpres=10,10,10 - Perform spatial smoothing on the input functional image(inputspec.rest_res_filt). For details see `PrinciplesSmoothing <http://imaging.mrc-cbu.cam.ac.uk/imaging/PrinciplesSmoothing>`_ `fslmaths <http://www.fmrib.ox.ac.uk/fslcourse/lectures/practicals/intro/index.htm>`_:: fslmaths rest_res_filt.nii.gz -kernel gauss FWHM/ sqrt(8-ln(2)) -fmean -mas rest_mask.nii.gz rest_res_filt_FWHM.nii.gz - Apply nonlinear registration (func to standard). For details see `applywarp <http://www.fmrib.ox.ac.uk/fsl/fnirt/warp_utils.html#applywarp>`_:: applywarp --ref=MNI152_T1_2mm_symmetric.nii.gz --in=rest_res_filt_FWHM.nii.gz --out=rest_res_2symmstandard.nii.gz --warp=highres2symmstandard_warp.nii.gz --premat=example_func2highres.mat - Copy and L/R swap the output of applywarp command (rest_res_2symmstandard.nii.gz). For details see `fslswapdim <http://fsl.fmrib.ox.ac.uk/fsl/fsl4.0/avwutils/index.html>`_:: fslswapdim rest_res_2symmstandard.nii.gz -x y z tmp_LRflipped.nii.gz - Calculate pearson correlation between rest_res_2symmstandard.nii.gz and flipped rest_res_2symmstandard.nii.gz(tmp_LRflipped.nii.gz). For details see `3dTcorrelate <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dTcorrelate.html>`_:: 3dTcorrelate -pearson -polort -1 -prefix VMHC_FWHM.nii.gz rest_res_2symmstandard.nii.gz tmp_LRflipped.nii.gz - Fisher Z Transform the correlation. For details see `3dcalc <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dcalc.html>`_:: 3dcalc -a VMHC_FWHM.nii.gz -expr 'log((a+1)/(1-a))/2' -prefix VMHC_FWHM_Z.nii.gz - Calculate the number of volumes(nvols) in flipped rest_res_2symmstandard.nii.gz(tmp_LRflipped.nii.gz) :: -Use Nibabel to do this - Compute the Z statistic map :: 3dcalc -a VMHC_FWHM_Z.nii.gz -expr 'a*sqrt('${nvols}'-3)' -prefix VMHC_FWHM_Z_stat.nii.gz Workflow: .. image:: ../images/vmhc_graph.dot.png :width: 500 Workflow Detailed: .. image:: ../images/vmhc_detailed_graph.dot.png :width: 500 References ---------- .. [1] Zuo, X.-N., Kelly, C., Di Martino, A., Mennes, M., Margulies, D. S., Bangaru, S., Grzadzinski, R., et al. (2010). Growing together and growing apart: regional and sex differences in the lifespan developmental trajectories of functional homotopy. The Journal of neuroscience : the official journal of the Society for Neuroscience, 30(45), 15034-43. doi:10.1523/JNEUROSCI.2612-10.2010 Examples -------- >>> vmhc_w = create_vmhc() >>> vmhc_w.inputs.inputspec.brain_symmetric = 'MNI152_T1_2mm_brain_symmetric.nii.gz' >>> vmhc_w.inputs.inputspec.symm_standard = 'MNI152_T1_2mm_symmetric.nii.gz' >>> vmhc_w.inputs.inputspec.twomm_brain_mask_dil = 'MNI152_T1_2mm_brain_mask_symmetric_dil.nii.gz' >>> vmhc_w.inputs.inputspec.config_file_twomm = 'T1_2_MNI152_2mm_symmetric.cnf' >>> vmhc_w.inputs.inputspec.standard = 'MNI152_T1_2mm.nii.gz' >>> vmhc_w.inputs.fwhm_input.fwhm = [4.5, 6] >>> vmhc_w.get_node('fwhm_input').iterables = ('fwhm', [4.5, 6]) >>> vmhc_w.inputs.inputspec.rest_res = os.path.abspath('/home/data/Projects/Pipelines_testing/Dickstein/subjects/s1001/func/original/rest_res_filt.nii.gz') >>> vmhc_w.inputs.inputspec.reorient = os.path.abspath('/home/data/Projects/Pipelines_testing/Dickstein/subjects/s1001/anat/mprage_RPI.nii.gz') >>> vmhc_w.inputs.inputspec.brain = os.path.abspath('/home/data/Projects/Pipelines_testing/Dickstein/subjects/s1001/anat/mprage_brain.nii.gz') >>> vmhc_w.inputs.inputspec.example_func2highres_mat = os.path.abspath('/home/data/Projects/Pipelines_testing/Dickstein/subjects/s1001/func/original/reg/example_func2highres.mat') >>> vmhc_w.inputs.inputspec.rest_mask = os.path.abspath('/home/data/Projects/Pipelines_testing/Dickstein/subjects/s1001/func/original/rest_mask.nii.gz') >>> vmhc_w.run() # doctest: +SKIP """ vmhc = pe.Workflow(name='vmhc_workflow') inputNode = pe.Node(util.IdentityInterface(fields=['brain', 'brain_symmetric', 'rest_res', 'reorient', 'example_func2highres_mat', 'symm_standard', 'twomm_brain_mask_dil', 'config_file_twomm', 'rest_mask', 'standard', 'mean_functional']), name='inputspec') outputNode = pe.Node(util.IdentityInterface(fields=['highres2symmstandard', 'highres2symmstandard_mat', 'highres2symmstandard_warp', 'fnirt_highres2symmstandard', 'highres2symmstandard_jac', 'rest_res_2symmstandard', 'VMHC_FWHM_img', 'VMHC_Z_FWHM_img', 'VMHC_Z_stat_FWHM_img' ]), name='outputspec') inputnode_fwhm = pe.Node(util.IdentityInterface(fields=['fwhm']), name='fwhm_input') if use_ants == False: ## Linear registration of T1 --> symmetric standard linear_T1_to_symmetric_standard = pe.Node(interface=fsl.FLIRT(), name='linear_T1_to_symmetric_standard') linear_T1_to_symmetric_standard.inputs.cost = 'corratio' linear_T1_to_symmetric_standard.inputs.cost_func = 'corratio' linear_T1_to_symmetric_standard.inputs.dof = 12 linear_T1_to_symmetric_standard.inputs.interp = 'trilinear' ## Perform nonlinear registration ##(higres to standard) to symmetric standard brain nonlinear_highres_to_symmetric_standard = pe.Node(interface=fsl.FNIRT(), name='nonlinear_highres_to_symmetric_standard') nonlinear_highres_to_symmetric_standard.inputs.fieldcoeff_file = True nonlinear_highres_to_symmetric_standard.inputs.jacobian_file = True nonlinear_highres_to_symmetric_standard.inputs.warp_resolution = (10, 10, 10) # needs new inputs. needs input from resources for the field coeff of the template->symmetric. # and needs the field coeff of the anatomical-to-template registration ## Apply nonlinear registration (func to standard) nonlinear_func_to_standard = pe.Node(interface=fsl.ApplyWarp(), name='nonlinear_func_to_standard') elif use_ants == True: # ANTS warp image etc. calculate_ants_xfm_vmhc = create_wf_calculate_ants_warp(name='calculate_ants_xfm_vmhc') fsl_to_itk_vmhc = create_wf_c3d_fsl_to_itk(0, name='fsl_to_itk_vmhc') collect_transforms_vmhc = create_wf_collect_transforms(0, name='collect_transforms_vmhc') apply_ants_xfm_vmhc = create_wf_apply_ants_warp(0,name='apply_ants_xfm_vmhc') calculate_ants_xfm_vmhc.inputs.inputspec.dimension = 3 calculate_ants_xfm_vmhc.inputs.inputspec. \ use_histogram_matching = True calculate_ants_xfm_vmhc.inputs.inputspec. \ winsorize_lower_quantile = 0.01 calculate_ants_xfm_vmhc.inputs.inputspec. \ winsorize_upper_quantile = 0.99 calculate_ants_xfm_vmhc.inputs.inputspec. \ metric = ['MI','MI','CC'] calculate_ants_xfm_vmhc.inputs.inputspec.metric_weight = [1,1,1] calculate_ants_xfm_vmhc.inputs.inputspec. \ radius_or_number_of_bins = [32,32,4] calculate_ants_xfm_vmhc.inputs.inputspec. \ sampling_strategy = ['Regular','Regular',None] calculate_ants_xfm_vmhc.inputs.inputspec. \ sampling_percentage = [0.25,0.25,None] calculate_ants_xfm_vmhc.inputs.inputspec. \ number_of_iterations = [[1000,500,250,100], \ [1000,500,250,100], [100,100,70,20]] calculate_ants_xfm_vmhc.inputs.inputspec. \ convergence_threshold = [1e-8,1e-8,1e-9] calculate_ants_xfm_vmhc.inputs.inputspec. \ convergence_window_size = [10,10,15] calculate_ants_xfm_vmhc.inputs.inputspec. \ transforms = ['Rigid','Affine','SyN'] calculate_ants_xfm_vmhc.inputs.inputspec. \ transform_parameters = [[0.1],[0.1],[0.1,3,0]] calculate_ants_xfm_vmhc.inputs.inputspec. \ shrink_factors = [[8,4,2,1],[8,4,2,1],[6,4,2,1]] calculate_ants_xfm_vmhc.inputs.inputspec. \ smoothing_sigmas = [[3,2,1,0],[3,2,1,0],[3,2,1,0]] apply_ants_xfm_vmhc.inputs.inputspec.interpolation = 'Gaussian' apply_ants_xfm_vmhc.inputs.inputspec.input_image_type = 3 ## copy and L/R swap file copy_and_L_R_swap = pe.Node(interface=fsl.SwapDimensions(), name='copy_and_L_R_swap') copy_and_L_R_swap.inputs.new_dims = ('-x', 'y', 'z') ## caculate vmhc pearson_correlation = pe.Node(interface=preprocess.TCorrelate(), name='pearson_correlation') pearson_correlation.inputs.pearson = True pearson_correlation.inputs.polort = -1 pearson_correlation.inputs.outputtype = 'NIFTI_GZ' z_trans = pe.Node(interface=preprocess.Calc(), name='z_trans') z_trans.inputs.expr = 'log((1+a)/(1-a))/2' z_trans.inputs.outputtype = 'NIFTI_GZ' z_stat = pe.Node(interface=preprocess.Calc(), name='z_stat') z_stat.inputs.outputtype = 'NIFTI_GZ' NVOLS = pe.Node(util.Function(input_names=['in_files'], output_names=['nvols'], function=get_img_nvols), name='NVOLS') generateEXP = pe.Node(util.Function(input_names=['nvols'], output_names=['expr'], function=get_operand_expression), name='generateEXP') smooth = pe.Node(interface=fsl.MultiImageMaths(), name='smooth') if use_ants == False: vmhc.connect(inputNode, 'brain', linear_T1_to_symmetric_standard, 'in_file') vmhc.connect(inputNode, 'brain_symmetric', linear_T1_to_symmetric_standard, 'reference') vmhc.connect(inputNode, 'reorient', nonlinear_highres_to_symmetric_standard, 'in_file') vmhc.connect(linear_T1_to_symmetric_standard, 'out_matrix_file', nonlinear_highres_to_symmetric_standard, 'affine_file') vmhc.connect(inputNode, 'symm_standard', nonlinear_highres_to_symmetric_standard, 'ref_file') vmhc.connect(inputNode, 'twomm_brain_mask_dil', nonlinear_highres_to_symmetric_standard, 'refmask_file') vmhc.connect(inputNode, 'config_file_twomm', nonlinear_highres_to_symmetric_standard, 'config_file') vmhc.connect(inputNode, 'rest_res', smooth, 'in_file') vmhc.connect(inputnode_fwhm, ('fwhm', set_gauss), smooth, 'op_string') vmhc.connect(inputNode, 'rest_mask', smooth, 'operand_files') vmhc.connect(smooth, 'out_file', nonlinear_func_to_standard, 'in_file') vmhc.connect(inputNode, 'standard', nonlinear_func_to_standard, 'ref_file') vmhc.connect(nonlinear_highres_to_symmetric_standard, 'fieldcoeff_file', nonlinear_func_to_standard, 'field_file') ## func->anat matrix (bbreg) vmhc.connect(inputNode, 'example_func2highres_mat', nonlinear_func_to_standard, 'premat') vmhc.connect(nonlinear_func_to_standard, 'out_file', copy_and_L_R_swap, 'in_file') vmhc.connect(nonlinear_func_to_standard, 'out_file', pearson_correlation, 'xset') elif use_ants == True: # connections for ANTS stuff # registration calculation stuff -- might go out the window vmhc.connect(inputNode, 'brain', calculate_ants_xfm_vmhc, 'inputspec.anatomical_brain') vmhc.connect(inputNode, 'brain_symmetric', calculate_ants_xfm_vmhc, 'inputspec.reference_brain') # functional apply warp stuff vmhc.connect(inputNode, 'rest_res', smooth, 'in_file') vmhc.connect(inputnode_fwhm, ('fwhm', set_gauss), smooth, 'op_string') vmhc.connect(inputNode, 'rest_mask', smooth, 'operand_files') vmhc.connect(smooth, 'out_file', apply_ants_xfm_vmhc, 'inputspec.input_image') vmhc.connect(calculate_ants_xfm_vmhc, 'outputspec.ants_rigid_xfm', collect_transforms_vmhc, 'inputspec.linear_rigid') vmhc.connect(calculate_ants_xfm_vmhc, 'outputspec.ants_affine_xfm', collect_transforms_vmhc, 'inputspec.linear_affine') vmhc.connect(calculate_ants_xfm_vmhc, 'outputspec.warp_field', collect_transforms_vmhc, 'inputspec.warp_file') ## func->anat matrix (bbreg) vmhc.connect(inputNode, 'example_func2highres_mat', fsl_to_itk_vmhc, 'inputspec.affine_file') vmhc.connect(inputNode, 'brain', fsl_to_itk_vmhc, 'inputspec.reference_file') vmhc.connect(inputNode, 'mean_functional', fsl_to_itk_vmhc, 'inputspec.source_file') vmhc.connect(fsl_to_itk_vmhc, 'outputspec.itk_transform', collect_transforms_vmhc, 'inputspec.fsl_to_itk_affine') ''' vmhc.connect(inputNode, 'brain', apply_ants_xfm_vmhc, 'inputspec.conversion_reference') vmhc.connect(inputNode, 'mean_functional', apply_ants_xfm_vmhc, 'inputspec.conversion_source') ''' vmhc.connect(inputNode, 'brain_symmetric', apply_ants_xfm_vmhc, 'inputspec.reference_image') vmhc.connect(collect_transforms_vmhc, \ 'outputspec.transformation_series', \ apply_ants_xfm_vmhc, 'inputspec.transforms') vmhc.connect(apply_ants_xfm_vmhc, 'outputspec.output_image', copy_and_L_R_swap, 'in_file') vmhc.connect(apply_ants_xfm_vmhc, 'outputspec.output_image', pearson_correlation, 'xset') vmhc.connect(copy_and_L_R_swap, 'out_file', pearson_correlation, 'yset') vmhc.connect(pearson_correlation, 'out_file', z_trans, 'in_file_a') vmhc.connect(copy_and_L_R_swap, 'out_file', NVOLS, 'in_files') vmhc.connect(NVOLS, 'nvols', generateEXP, 'nvols') vmhc.connect(z_trans, 'out_file', z_stat, 'in_file_a') vmhc.connect(generateEXP, 'expr', z_stat, 'expr') if use_ants == False: vmhc.connect(linear_T1_to_symmetric_standard, 'out_file', outputNode, 'highres2symmstandard') vmhc.connect(linear_T1_to_symmetric_standard, 'out_matrix_file', outputNode, 'highres2symmstandard_mat') vmhc.connect(nonlinear_highres_to_symmetric_standard, 'jacobian_file', outputNode, 'highres2symmstandard_jac') vmhc.connect(nonlinear_highres_to_symmetric_standard, 'fieldcoeff_file', outputNode, 'highres2symmstandard_warp') vmhc.connect(nonlinear_highres_to_symmetric_standard, 'warped_file', outputNode, 'fnirt_highres2symmstandard') vmhc.connect(nonlinear_func_to_standard, 'out_file', outputNode, 'rest_res_2symmstandard') elif use_ants == True: # ANTS warp outputs to outputnode vmhc.connect(calculate_ants_xfm_vmhc, 'outputspec.ants_affine_xfm', outputNode, 'highres2symmstandard_mat') vmhc.connect(calculate_ants_xfm_vmhc, 'outputspec.warp_field', outputNode, 'highres2symmstandard_warp') vmhc.connect(calculate_ants_xfm_vmhc, 'outputspec.normalized_output_brain', outputNode, 'fnirt_highres2symmstandard') vmhc.connect(apply_ants_xfm_vmhc, 'outputspec.output_image', outputNode, 'rest_res_2symmstandard') vmhc.connect(pearson_correlation, 'out_file', outputNode, 'VMHC_FWHM_img') vmhc.connect(z_trans, 'out_file', outputNode, 'VMHC_Z_FWHM_img') vmhc.connect(z_stat, 'out_file', outputNode, 'VMHC_Z_stat_FWHM_img') return vmhc
def ants_apply_inverse_warps_template_to_func(workflow, strat, num_strat, num_ants_cores, input_node, input_outfile, ref_node, ref_outfile, func_name, interp, input_image_type): """Apply the functional-to-structural and structural-to-template warps inversely to functional time-series in template space to warp it back to native functional space. Parameters ---------- workflow: Nipype workflow object the workflow containing the resources involved strat: C-PAC Strategy object a strategy with one or more resource pools num_strat: int the number of strategy objects num_ants_cores: int the number of CPU cores dedicated to ANTS anatomical-to-standard registration input_node: Nipype pointer pointer to the node containing the 4D functional time-series (often the leaf node) input_outfile: Nipype pointer pointer to the output of the node, i.e. the 4D functional time-series itself ref_node: Nipype pointer pointer to the node containing the reference volume for the C3D FSL-to-ITK affine conversion (often the mean of the functional time-series, which is a single volume) ref_outfile: Nipype pointer pointer to the output of ref_node, i.e. the reference volume itself func_name: str what the name of the warped functional should be when written to the resource pool interp: str which interpolation to use when applying the warps input_image_type: int argument taken by the ANTs apply warp tool; in this case, should be 3 for 4D functional time-series """ # converts FSL-format .mat affine xfm into ANTS-format # .txt; .mat affine comes from Func->Anat registration fsl_to_itk_mni_func = create_wf_c3d_fsl_to_itk(name='fsl_to_itk_%s_%d' % (func_name, num_strat)) # collects series of warps to be applied collect_transforms_mni_func = \ create_wf_collect_transforms( inverse=True, name='collect_transforms_%s_%d' % (func_name, num_strat) ) # apply ants warps apply_ants_warp_mni_func = \ create_wf_apply_ants_warp( inverse=True, name='apply_ants_warp_%s_%d' % (func_name, num_strat), ants_threads=int(num_ants_cores)) apply_ants_warp_mni_func.inputs.inputspec.dimension = 3 apply_ants_warp_mni_func.inputs.inputspec.interpolation = interp # input_image_type: # (0 or 1 or 2 or 3) # Option specifying the input image type of scalar # (default), vector, tensor, or time series. apply_ants_warp_mni_func.inputs.inputspec. \ input_image_type = input_image_type # convert the .mat from linear Func->Anat to # ANTS format node, out_file = strat['functional_to_anat_linear_xfm'] workflow.connect(node, out_file, fsl_to_itk_mni_func, 'inputspec.affine_file') node, out_file = strat["anatomical_brain"] workflow.connect(node, out_file, fsl_to_itk_mni_func, 'inputspec.reference_file') workflow.connect(ref_node, ref_outfile, fsl_to_itk_mni_func, 'inputspec.source_file') workflow.connect(ref_node, ref_outfile, apply_ants_warp_mni_func, 'inputspec.reference_image') # Field file from anatomical nonlinear registration node, out_file = strat['mni_to_anatomical_nonlinear_xfm'] workflow.connect(node, out_file, collect_transforms_mni_func, 'inputspec.warp_file') # initial transformation from anatomical registration node, out_file = strat['ants_initial_xfm'] workflow.connect(node, out_file, collect_transforms_mni_func, 'inputspec.linear_initial') # affine transformation from anatomical registration node, out_file = strat['ants_affine_xfm'] workflow.connect(node, out_file, collect_transforms_mni_func, 'inputspec.linear_affine') # rigid transformation from anatomical registration node, out_file = strat['ants_rigid_xfm'] workflow.connect(node, out_file, collect_transforms_mni_func, 'inputspec.linear_rigid') # Premat from Func->Anat linear reg and bbreg # (if bbreg is enabled) workflow.connect(fsl_to_itk_mni_func, 'outputspec.itk_transform', collect_transforms_mni_func, 'inputspec.fsl_to_itk_affine') # this <node, out_file> pulls in directly because # it pulls in the leaf in some instances workflow.connect(input_node, input_outfile, apply_ants_warp_mni_func, 'inputspec.input_image') workflow.connect(collect_transforms_mni_func, 'outputspec.transformation_series', apply_ants_warp_mni_func, 'inputspec.transforms') strat.update_resource_pool( {func_name: (apply_ants_warp_mni_func, 'outputspec.output_image')}) strat.append_name(apply_ants_warp_mni_func.name) return apply_ants_warp_mni_func
def create_vmhc(use_ants, name='vmhc_workflow', ants_threads=1): """ Compute the map of brain functional homotopy, the high degree of synchrony in spontaneous activity between geometrically corresponding interhemispheric (i.e., homotopic) regions. Parameters ---------- None Returns ------- vmhc_workflow : workflow Voxel Mirrored Homotopic Connectivity Analysis Workflow Notes ----- `Source <https://github.com/FCP-INDI/C-PAC/blob/master/CPAC/vmhc/vmhc.py>`_ Workflow Inputs:: inputspec.brain : string (existing nifti file) Anatomical image(without skull) inputspec.symmetric_brain : string (existing nifti file) MNI152_T1_2mm_symmetric_brain.nii.gz inputspec.rest_res_filt : string (existing nifti file) Band passed Image with nuisance signal regressed out(and optionally scrubbed). Recommended bandpass filter (0.001,0.1) ) inputspec.reorient : string (existing nifti file) RPI oriented anatomical data inputspec.example_func2highres_mat : string (existing affine transformation .mat file) Specifies an affine transform that should be applied to the example_func before non linear warping inputspec.standard_for_func: string (existing nifti file) MNI152_T1_standard_resolution_brain.nii.gz inputspec.symmetric_skull : string (existing nifti file) MNI152_T1_2mm_symmetric.nii.gz inputspec.twomm_brain_mask_dil : string (existing nifti file) MNI152_T1_2mm_brain_mask_symmetric_dil.nii.gz inputspec.config_file_twomm_symmetric : string (existing .cnf file) T1_2_MNI152_2mm_symmetric.cnf inputspec.rest_mask : string (existing nifti file) A mask functional volume(derived by dilation from motion corrected functional volume) fwhm_input.fwhm : list (float) For spatial smoothing the Z-transformed correlations in MNI space. Generally the value of this parameter is 1.5 or 2 times the voxel size of the input Image. inputspec.mean_functional : string (existing nifti file) The mean functional image for use in the func-to-anat registration matrix conversion to ITK (ANTS) format, if the user selects to use ANTS. Workflow Outputs:: outputspec.highres2symmstandard : string (nifti file) Linear registration of T1 image to symmetric standard image outputspec.highres2symmstandard_mat : string (affine transformation .mat file) An affine transformation .mat file from linear registration and used in non linear registration outputspec.highres2symmstandard_warp : string (nifti file) warp file from Non Linear registration of T1 to symmetrical standard brain outputspec.fnirt_highres2symmstandard : string (nifti file) Non Linear registration of T1 to symmetrical standard brain outputspec.highres2symmstandard_jac : string (nifti file) jacobian determinant image from Non Linear registration of T1 to symmetrical standard brain outputspec.rest_res_2symmstandard : string (nifti file) nonlinear registration (func to standard) image outputspec.VMHC_FWHM_img : string (nifti file) pearson correlation between res2standard and flipped res2standard outputspec.VMHC_Z_FWHM_img : string (nifti file) Fisher Z transform map outputspec.VMHC_Z_stat_FWHM_img : string (nifti file) Z statistic map Order of commands: - Perform linear registration of Anatomical brain in T1 space to symmetric standard space. For details see `flirt <http://www.fmrib.ox.ac.uk/fsl/flirt/index.html>`_:: flirt -ref MNI152_T1_2mm_symmetric_brain.nii.gz -in mprage_brain.nii.gz -out highres2symmstandard.nii.gz -omat highres2symmstandard.mat -cost corratio -searchcost corratio -dof 12 -interp trilinear - Perform nonlinear registration (higres to standard) to symmetric standard brain. For details see `fnirt <http://fsl.fmrib.ox.ac.uk/fsl/fnirt/>`_:: fnirt --in=head.nii.gz --aff=highres2symmstandard.mat --cout=highres2symmstandard_warp.nii.gz --iout=fnirt_highres2symmstandard.nii.gz --jout=highres2symmstandard_jac.nii.gz --config=T1_2_MNI152_2mm_symmetric.cnf --ref=MNI152_T1_2mm_symmetric.nii.gz --refmask=MNI152_T1_2mm_brain_mask_symmetric_dil.nii.gz --warpres=10,10,10 - Perform spatial smoothing on the input functional image(inputspec.rest_res_filt). For details see `PrinciplesSmoothing <http://imaging.mrc-cbu.cam.ac.uk/imaging/PrinciplesSmoothing>`_ `fslmaths <http://www.fmrib.ox.ac.uk/fslcourse/lectures/practicals/intro/index.htm>`_:: fslmaths rest_res_filt.nii.gz -kernel gauss FWHM/ sqrt(8-ln(2)) -fmean -mas rest_mask.nii.gz rest_res_filt_FWHM.nii.gz - Apply nonlinear registration (func to standard). For details see `applywarp <http://www.fmrib.ox.ac.uk/fsl/fnirt/warp_utils.html#applywarp>`_:: applywarp --ref=MNI152_T1_2mm_symmetric.nii.gz --in=rest_res_filt_FWHM.nii.gz --out=rest_res_2symmstandard.nii.gz --warp=highres2symmstandard_warp.nii.gz --premat=example_func2highres.mat - Copy and L/R swap the output of applywarp command (rest_res_2symmstandard.nii.gz). For details see `fslswapdim <http://fsl.fmrib.ox.ac.uk/fsl/fsl4.0/avwutils/index.html>`_:: fslswapdim rest_res_2symmstandard.nii.gz -x y z tmp_LRflipped.nii.gz - Calculate pearson correlation between rest_res_2symmstandard.nii.gz and flipped rest_res_2symmstandard.nii.gz(tmp_LRflipped.nii.gz). For details see `3dTcorrelate <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dTcorrelate.html>`_:: 3dTcorrelate -pearson -polort -1 -prefix VMHC_FWHM.nii.gz rest_res_2symmstandard.nii.gz tmp_LRflipped.nii.gz - Fisher Z Transform the correlation. For details see `3dcalc <http://afni.nimh.nih.gov/pub/dist/doc/program_help/3dcalc.html>`_:: 3dcalc -a VMHC_FWHM.nii.gz -expr 'log((a+1)/(1-a))/2' -prefix VMHC_FWHM_Z.nii.gz - Calculate the number of volumes(nvols) in flipped rest_res_2symmstandard.nii.gz(tmp_LRflipped.nii.gz) :: -Use Nibabel to do this - Compute the Z statistic map :: 3dcalc -a VMHC_FWHM_Z.nii.gz -expr 'a*sqrt('${nvols}'-3)' -prefix VMHC_FWHM_Z_stat.nii.gz Workflow: .. image:: ../images/vmhc_graph.dot.png :width: 500 Workflow Detailed: .. image:: ../images/vmhc_detailed_graph.dot.png :width: 500 References ---------- .. [1] Zuo, X.-N., Kelly, C., Di Martino, A., Mennes, M., Margulies, D. S., Bangaru, S., Grzadzinski, R., et al. (2010). Growing together and growing apart: regional and sex differences in the lifespan developmental trajectories of functional homotopy. The Journal of neuroscience : the official journal of the Society for Neuroscience, 30(45), 15034-43. doi:10.1523/JNEUROSCI.2612-10.2010 Examples -------- >>> vmhc_w = create_vmhc() >>> vmhc_w.inputs.inputspec.symmetric_brain = 'MNI152_T1_2mm_symmetric_brain.nii.gz' >>> vmhc_w.inputs.inputspec.symmetric_skull = 'MNI152_T1_2mm_symmetric.nii.gz' >>> vmhc_w.inputs.inputspec.twomm_brain_mask_dil = 'MNI152_T1_2mm_brain_mask_symmetric_dil.nii.gz' >>> vmhc_w.inputs.inputspec.config_file_twomm = 'T1_2_MNI152_2mm_symmetric.cnf' >>> vmhc_w.inputs.inputspec.standard_for_func= 'MNI152_T1_2mm.nii.gz' >>> vmhc_w.inputs.fwhm_input.fwhm = [4.5, 6] >>> vmhc_w.get_node('fwhm_input').iterables = ('fwhm', [4.5, 6]) >>> vmhc_w.inputs.inputspec.rest_res = os.path.abspath('/home/data/Projects/Pipelines_testing/Dickstein/subjects/s1001/func/original/rest_res_filt.nii.gz') >>> vmhc_w.inputs.inputspec.reorient = os.path.abspath('/home/data/Projects/Pipelines_testing/Dickstein/subjects/s1001/anat/mprage_RPI.nii.gz') >>> vmhc_w.inputs.inputspec.brain = os.path.abspath('/home/data/Projects/Pipelines_testing/Dickstein/subjects/s1001/anat/mprage_brain.nii.gz') >>> vmhc_w.inputs.inputspec.example_func2highres_mat = os.path.abspath('/home/data/Projects/Pipelines_testing/Dickstein/subjects/s1001/func/original/reg/example_func2highres.mat') >>> vmhc_w.inputs.inputspec.rest_mask = os.path.abspath('/home/data/Projects/Pipelines_testing/Dickstein/subjects/s1001/func/original/rest_mask.nii.gz') >>> vmhc_w.run() # doctest: +SKIP """ vmhc = pe.Workflow(name=name) inputNode = pe.Node(util.IdentityInterface(fields=[ 'rest_res', 'example_func2highres_mat', 'rest_mask', 'standard_for_func', 'mean_functional', 'brain', 'fnirt_nonlinear_warp', 'ants_symm_initial_xfm', 'ants_symm_rigid_xfm', 'ants_symm_affine_xfm', 'ants_symm_warp_field' ]), name='inputspec') outputNode = pe.Node(util.IdentityInterface(fields=[ 'rest_res_2symmstandard', 'VMHC_FWHM_img', 'VMHC_Z_FWHM_img', 'VMHC_Z_stat_FWHM_img' ]), name='outputspec') inputnode_fwhm = pe.Node(util.IdentityInterface(fields=['fwhm']), name='fwhm_input') if use_ants == False: # Apply nonlinear registration (func to standard) nonlinear_func_to_standard = pe.Node(interface=fsl.ApplyWarp(), name='nonlinear_func_to_standard') elif use_ants == True: # ANTS warp image etc. fsl_to_itk_vmhc = create_wf_c3d_fsl_to_itk(0, name='fsl_to_itk_vmhc') collect_transforms_vmhc = create_wf_collect_transforms( 0, name='collect_transforms_vmhc') apply_ants_xfm_vmhc = create_wf_apply_ants_warp( 0, name='apply_ants_xfm_vmhc', ants_threads=ants_threads) # this has to be 3 instead of default 0 because it is a 4D file apply_ants_xfm_vmhc.inputs.inputspec.input_image_type = 3 # copy and L/R swap file copy_and_L_R_swap = pe.Node(interface=fsl.SwapDimensions(), name='copy_and_L_R_swap') copy_and_L_R_swap.inputs.new_dims = ('-x', 'y', 'z') # calculate vmhc pearson_correlation = pe.Node(interface=preprocess.TCorrelate(), name='pearson_correlation') pearson_correlation.inputs.pearson = True pearson_correlation.inputs.polort = -1 pearson_correlation.inputs.outputtype = 'NIFTI_GZ' try: z_trans = pe.Node(interface=preprocess.Calc(), name='z_trans') z_stat = pe.Node(interface=preprocess.Calc(), name='z_stat') except AttributeError: from nipype.interfaces.afni import utils as afni_utils z_trans = pe.Node(interface=afni_utils.Calc(), name='z_trans') z_stat = pe.Node(interface=afni_utils.Calc(), name='z_stat') z_trans.inputs.expr = 'log((1+a)/(1-a))/2' z_trans.inputs.outputtype = 'NIFTI_GZ' z_stat.inputs.outputtype = 'NIFTI_GZ' NVOLS = pe.Node(util.Function(input_names=['in_files'], output_names=['nvols'], function=get_img_nvols), name='NVOLS') generateEXP = pe.Node(util.Function(input_names=['nvols'], output_names=['expr'], function=get_operand_expression), name='generateEXP') smooth = pe.Node(interface=fsl.MultiImageMaths(), name='smooth') if use_ants == False: vmhc.connect(inputNode, 'rest_res', smooth, 'in_file') vmhc.connect(inputnode_fwhm, ('fwhm', set_gauss), smooth, 'op_string') vmhc.connect(inputNode, 'rest_mask', smooth, 'operand_files') vmhc.connect(smooth, 'out_file', nonlinear_func_to_standard, 'in_file') vmhc.connect(inputNode, 'standard_for_func', nonlinear_func_to_standard, 'ref_file') vmhc.connect(inputNode, 'fnirt_nonlinear_warp', nonlinear_func_to_standard, 'field_file') ## func->anat matrix (bbreg) vmhc.connect(inputNode, 'example_func2highres_mat', nonlinear_func_to_standard, 'premat') vmhc.connect(nonlinear_func_to_standard, 'out_file', copy_and_L_R_swap, 'in_file') vmhc.connect(nonlinear_func_to_standard, 'out_file', pearson_correlation, 'xset') elif use_ants == True: # connections for ANTS stuff # functional apply warp stuff vmhc.connect(inputNode, 'rest_res', smooth, 'in_file') vmhc.connect(inputnode_fwhm, ('fwhm', set_gauss), smooth, 'op_string') vmhc.connect(inputNode, 'rest_mask', smooth, 'operand_files') vmhc.connect(smooth, 'out_file', apply_ants_xfm_vmhc, 'inputspec.input_image') vmhc.connect(inputNode, 'ants_symm_initial_xfm', collect_transforms_vmhc, 'inputspec.linear_initial') vmhc.connect(inputNode, 'ants_symm_rigid_xfm', collect_transforms_vmhc, 'inputspec.linear_rigid') vmhc.connect(inputNode, 'ants_symm_affine_xfm', collect_transforms_vmhc, 'inputspec.linear_affine') vmhc.connect(inputNode, 'ants_symm_warp_field', collect_transforms_vmhc, 'inputspec.warp_file') # func->anat matrix (bbreg) vmhc.connect(inputNode, 'example_func2highres_mat', fsl_to_itk_vmhc, 'inputspec.affine_file') vmhc.connect(inputNode, 'brain', fsl_to_itk_vmhc, 'inputspec.reference_file') vmhc.connect(inputNode, 'mean_functional', fsl_to_itk_vmhc, 'inputspec.source_file') vmhc.connect(fsl_to_itk_vmhc, 'outputspec.itk_transform', collect_transforms_vmhc, 'inputspec.fsl_to_itk_affine') vmhc.connect(inputNode, 'standard_for_func', apply_ants_xfm_vmhc, 'inputspec.reference_image') vmhc.connect(collect_transforms_vmhc, 'outputspec.transformation_series', apply_ants_xfm_vmhc, 'inputspec.transforms') vmhc.connect(apply_ants_xfm_vmhc, 'outputspec.output_image', copy_and_L_R_swap, 'in_file') vmhc.connect(apply_ants_xfm_vmhc, 'outputspec.output_image', pearson_correlation, 'xset') vmhc.connect(copy_and_L_R_swap, 'out_file', pearson_correlation, 'yset') vmhc.connect(pearson_correlation, 'out_file', z_trans, 'in_file_a') vmhc.connect(copy_and_L_R_swap, 'out_file', NVOLS, 'in_files') vmhc.connect(NVOLS, 'nvols', generateEXP, 'nvols') vmhc.connect(z_trans, 'out_file', z_stat, 'in_file_a') vmhc.connect(generateEXP, 'expr', z_stat, 'expr') if use_ants == False: vmhc.connect(nonlinear_func_to_standard, 'out_file', outputNode, 'rest_res_2symmstandard') elif use_ants == True: # ANTS warp outputs to outputnode vmhc.connect(apply_ants_xfm_vmhc, 'outputspec.output_image', outputNode, 'rest_res_2symmstandard') vmhc.connect(pearson_correlation, 'out_file', outputNode, 'VMHC_FWHM_img') vmhc.connect(z_trans, 'out_file', outputNode, 'VMHC_Z_FWHM_img') vmhc.connect(z_stat, 'out_file', outputNode, 'VMHC_Z_stat_FWHM_img') return vmhc
def output_to_standard(workflow, output_name, strat, num_strat, pipeline_config_obj, map_node=False, input_image_type=0): nodes = strat.get_nodes_names() if 'apply_ants_warp_functional_to_standard' in nodes: # ANTS WARP APPLICATION # convert the func-to-anat linear warp from FSL FLIRT to # ITK (ANTS) format fsl_to_itk_convert = create_wf_c3d_fsl_to_itk( input_image_type, map_node, name='{0}_fsl_to_itk_{1}'.format(output_name, num_strat)) # collect the list of warps into a single stack to feed into the # ANTS warp apply tool collect_transforms = create_wf_collect_transforms( map_node, name='{0}_collect_transforms_{1}'.format(output_name, num_strat)) # ANTS apply warp apply_ants_warp = create_wf_apply_ants_warp( map_node, name='{0}_to_standard_{1}'.format(output_name, num_strat), ants_threads=int(pipeline_config_obj.num_ants_threads)) apply_ants_warp.inputs.inputspec.dimension = 3 apply_ants_warp.inputs.inputspec.interpolation = 'Linear' apply_ants_warp.inputs.inputspec.reference_image = \ pipeline_config_obj.template_brain_only_for_func apply_ants_warp.inputs.inputspec.input_image_type = \ input_image_type # affine from FLIRT func->anat linear registration node, out_file = strat['functional_to_anat_linear_xfm'] workflow.connect(node, out_file, fsl_to_itk_convert, 'inputspec.affine_file') # reference used in FLIRT func->anat linear registration node, out_file = strat['anatomical_brain'] workflow.connect(node, out_file, fsl_to_itk_convert, 'inputspec.reference_file') # output file to be converted node, out_file = \ strat[output_name] workflow.connect(node, out_file, fsl_to_itk_convert, 'inputspec.source_file') # nonlinear warp from anatomical->template ANTS registration node, out_file = strat['anatomical_to_mni_nonlinear_xfm'] workflow.connect(node, out_file, collect_transforms, 'inputspec.warp_file') # linear initial from anatomical->template ANTS registration node, out_file = strat['ants_initial_xfm'] workflow.connect(node, out_file, collect_transforms, 'inputspec.linear_initial') # linear affine from anatomical->template ANTS registration node, out_file = strat['ants_affine_xfm'] workflow.connect(node, out_file, collect_transforms, 'inputspec.linear_affine') # rigid affine from anatomical->template ANTS registration node, out_file = strat['ants_rigid_xfm'] workflow.connect(node, out_file, collect_transforms, 'inputspec.linear_rigid') # converted FLIRT func->anat affine, now in ITK (ANTS) format workflow.connect(fsl_to_itk_convert, 'outputspec.itk_transform', collect_transforms, 'inputspec.fsl_to_itk_affine') # output file to be converted node, out_file = strat[output_name] workflow.connect(node, out_file, apply_ants_warp, 'inputspec.input_image') # collection of warps to be applied to the output file workflow.connect(collect_transforms, 'outputspec.transformation_series', apply_ants_warp, 'inputspec.transforms') strat.update_resource_pool({ '{0}_to_standard'.format(output_name): (apply_ants_warp, 'outputspec.output_image') }) strat.append_name(apply_ants_warp.name) num_strat += 1 elif 'anat_mni_fnirt_register' in nodes: # FSL WARP APPLICATION if map_node: apply_fsl_warp = pe.MapNode(interface=fsl.ApplyWarp(), name='{0}_to_standard_{1}'.format( output_name, num_strat), iterfield=['in_file']) else: apply_fsl_warp = pe.Node(interface=fsl.ApplyWarp(), name='{0}_to_standard_{1}'.format( output_name, num_strat)) apply_fsl_warp.inputs.ref_file = \ pipeline_config_obj.template_skull_for_func # output file to be warped node, out_file = strat[output_name] workflow.connect(node, out_file, apply_fsl_warp, 'in_file') # linear affine from func->anat linear FLIRT registration node, out_file = strat['functional_to_anat_linear_xfm'] workflow.connect(node, out_file, apply_fsl_warp, 'premat') # nonlinear warp from anatomical->template FNIRT registration node, out_file = strat['anatomical_to_mni_nonlinear_xfm'] workflow.connect(node, out_file, apply_fsl_warp, 'field_file') strat.update_resource_pool({ '{0}_to_standard'.format(output_name): (apply_fsl_warp, 'out_file') }) strat.append_name(apply_fsl_warp.name) elif 'anat_mni_flirt_register' in nodes: # FSL WARP APPLICATION if map_node: apply_anat_warp = pe.MapNode(interface=fsl.ApplyWarp(), name='{0}_to_anat_{1}'.format( output_name, num_strat), iterfield=['in_file']) apply_fsl_warp = pe.MapNode(interface=fsl.ApplyWarp(), name='{0}_to_standard_{1}'.format( output_name, num_strat), iterfield=['in_file']) else: apply_anat_warp = pe.Node(interface=fsl.ApplyWarp(), name='{0}_to_anat_{1}'.format( output_name, num_strat)) apply_fsl_warp = pe.Node(interface=fsl.ApplyWarp(), name='{0}_to_standard_{1}'.format( output_name, num_strat)) node, out_file = strat['anatomical_brain'] workflow.connect(node, out_file, apply_anat_warp, 'ref_file') apply_fsl_warp.inputs.ref_file = \ pipeline_config_obj.template_skull_for_func # output file to be warped node, out_file = strat[output_name] workflow.connect(node, out_file, apply_anat_warp, 'in_file') # linear affine from func->anat linear FLIRT registration node, out_file = strat['functional_to_anat_linear_xfm'] workflow.connect(node, out_file, apply_anat_warp, 'premat') # output file to be warped workflow.connect(apply_anat_warp, 'out_file', apply_fsl_warp, 'in_file') # nonlinear warp from anatomical->template FNIRT registration node, out_file = strat['anatomical_to_mni_linear_xfm'] workflow.connect(node, out_file, apply_fsl_warp, 'premat') strat.update_resource_pool({ '{0}_to_standard'.format(output_name): (apply_fsl_warp, 'out_file') }) strat.append_name(apply_fsl_warp.name) return strat