def create_tbss_non_FA(name='tbss_non_FA'): """ A pipeline that implement tbss_non_FA in FSL Example ------- >>> from nipype.workflows.dmri.fsl import tbss >>> tbss_MD = tbss.create_tbss_non_FA() >>> tbss_MD.inputs.inputnode.file_list = [] >>> tbss_MD.inputs.inputnode.field_list = [] >>> tbss_MD.inputs.inputnode.skeleton_thresh = 0.2 >>> tbss_MD.inputs.inputnode.groupmask = './xxx' >>> tbss_MD.inputs.inputnode.meanfa_file = './xxx' >>> tbss_MD.inputs.inputnode.distance_map = [] Inputs:: inputnode.file_list inputnode.field_list inputnode.skeleton_thresh inputnode.groupmask inputnode.meanfa_file inputnode.distance_map Outputs:: outputnode.projected_nonFA_file """ # Define the inputnode inputnode = pe.Node(interface=util.IdentityInterface(fields=[ 'file_list', 'field_list', 'skeleton_thresh', 'groupmask', 'meanfa_file', 'distance_map' ]), name='inputnode') # Apply the warpfield to the non FA image applywarp = pe.MapNode(interface=fsl.ApplyWarp(), iterfield=['in_file', 'field_file'], name="applywarp") if fsl.no_fsl(): warn('NO FSL found') else: applywarp.inputs.ref_file = fsl.Info.standard_image( "FMRIB58_FA_1mm.nii.gz") # Merge the non FA files into a 4D file merge = pe.Node(fsl.Merge(dimension="t"), name="merge") #merged_file="all_FA.nii.gz" maskgroup = pe.Node(fsl.ImageMaths(op_string="-mas", suffix="_masked"), name="maskgroup") projectfa = pe.Node( fsl.TractSkeleton( project_data=True, #projected_data = 'test.nii.gz', use_cingulum_mask=True), name="projectfa") tbss_non_FA = pe.Workflow(name=name) tbss_non_FA.connect([ (inputnode, applywarp, [ ('file_list', 'in_file'), ('field_list', 'field_file'), ]), (applywarp, merge, [("out_file", "in_files")]), (merge, maskgroup, [("merged_file", "in_file")]), (inputnode, maskgroup, [('groupmask', 'in_file2')]), (maskgroup, projectfa, [('out_file', 'data_file')]), (inputnode, projectfa, [ ('skeleton_thresh', 'threshold'), ("meanfa_file", "in_file"), ("distance_map", "distance_map"), ]), ]) # Define the outputnode outputnode = pe.Node( interface=util.IdentityInterface(fields=['projected_nonFA_file']), name='outputnode') tbss_non_FA.connect([ (projectfa, outputnode, [ ('projected_data', 'projected_nonFA_file'), ]), ]) return tbss_non_FA
def create_tbss_4_prestats(name='tbss_4_prestats'): """Post-registration processing:Creating skeleton mask using a threshold projecting all FA data onto skeleton. A pipeline that does the same as tbss_4_prestats script from FSL Example ------- >>> from nipype.workflows.dmri.fsl import tbss >>> tbss4 = tbss.create_tbss_4_prestats(name='tbss4') >>> tbss4.inputs.inputnode.skeleton_thresh = 0.2 Inputs:: inputnode.skeleton_thresh inputnode.groupmask inputnode.skeleton_file inputnode.meanfa_file inputnode.mergefa_file Outputs:: outputnode.all_FA_skeletonised outputnode.mean_FA_skeleton_mask outputnode.distance_map outputnode.skeleton_file """ # Create inputnode inputnode = pe.Node(interface=util.IdentityInterface(fields=[ 'groupmask', 'skeleton_file', 'meanfa_file', 'mergefa_file', 'skeleton_thresh' ]), name='inputnode') # Mask the skeleton at the threshold skeletonmask = pe.Node(fsl.ImageMaths(suffix="_mask"), name="skeletonmask") # Invert the brainmask then add in the tract skeleton invertmask = pe.Node(fsl.ImageMaths(suffix="_inv", op_string="-mul -1 -add 1 -add"), name="invertmask") # Generate a distance map with the tract skeleton distancemap = pe.Node(fsl.DistanceMap(), name="distancemap") # Project the FA values onto the skeleton projectfa = pe.Node(fsl.TractSkeleton(project_data=True, skeleton_file=True, use_cingulum_mask=True), name="projectfa") # Create tbss4 workflow tbss4 = pe.Workflow(name=name) tbss4.connect([ (inputnode, invertmask, [("groupmask", "in_file")]), (inputnode, skeletonmask, [("skeleton_file", "in_file"), (('skeleton_thresh', tbss4_op_string), 'op_string')]), (inputnode, projectfa, [('skeleton_thresh', 'threshold'), ("meanfa_file", "in_file"), ("mergefa_file", "data_file")]), (skeletonmask, invertmask, [("out_file", "in_file2")]), (invertmask, distancemap, [("out_file", "in_file")]), (distancemap, projectfa, [("distance_map", "distance_map")]), ]) # Create the outputnode outputnode = pe.Node(interface=util.IdentityInterface(fields=[ 'projectedfa_file', 'skeleton_mask', 'distance_map', 'skeleton_file' ]), name='outputnode') tbss4.connect([ (projectfa, outputnode, [('projected_data', 'projectedfa_file'), ('skeleton_file', 'skeleton_file')]), (distancemap, outputnode, [('distance_map', 'distance_map')]), (skeletonmask, outputnode, [('out_file', 'skeleton_mask')]) ]) return tbss4
def create_tbss_3_postreg(name='tbss_3_postreg', estimate_skeleton=True): """Post-registration processing: derive mean_FA and mean_FA_skeleton from mean of all subjects in study. Target is assumed to be FMRIB58_FA_1mm. A pipeline that does the same as 'tbss_3_postreg -S' script from FSL Setting 'estimate_skeleton to False will use precomputed FMRIB58_FA-skeleton_1mm skeleton (same as 'tbss_3_postreg -T'). Example ------- >>> from nipype.workflows.dmri.fsl import tbss >>> tbss3 = tbss.create_tbss_3_postreg() >>> tbss3.inputs.inputnode.fa_list = ['s1_wrapped_FA.nii', 's2_wrapped_FA.nii', 's3_wrapped_FA.nii'] Inputs:: inputnode.field_list inputnode.fa_list Outputs:: outputnode.groupmask outputnode.skeleton_file outputnode.meanfa_file outputnode.mergefa_file """ # Create the inputnode inputnode = pe.Node( interface=util.IdentityInterface(fields=['field_list', 'fa_list']), name='inputnode') # Apply the warpfield to the masked FA image applywarp = pe.MapNode(interface=fsl.ApplyWarp(), iterfield=['in_file', 'field_file'], name="applywarp") if fsl.no_fsl(): warn('NO FSL found') else: applywarp.inputs.ref_file = fsl.Info.standard_image( "FMRIB58_FA_1mm.nii.gz") # Merge the FA files into a 4D file mergefa = pe.Node(fsl.Merge(dimension="t"), name="mergefa") # Get a group mask groupmask = pe.Node(fsl.ImageMaths(op_string="-max 0 -Tmin -bin", out_data_type="char", suffix="_mask"), name="groupmask") maskgroup = pe.Node(fsl.ImageMaths(op_string="-mas", suffix="_masked"), name="maskgroup") tbss3 = pe.Workflow(name=name) tbss3.connect([ (inputnode, applywarp, [("fa_list", "in_file"), ("field_list", "field_file")]), (applywarp, mergefa, [("out_file", "in_files")]), (mergefa, groupmask, [("merged_file", "in_file")]), (mergefa, maskgroup, [("merged_file", "in_file")]), (groupmask, maskgroup, [("out_file", "in_file2")]), ]) # Create outputnode outputnode = pe.Node(interface=util.IdentityInterface( fields=['groupmask', 'skeleton_file', 'meanfa_file', 'mergefa_file']), name='outputnode') if estimate_skeleton: # Take the mean over the fourth dimension meanfa = pe.Node(fsl.ImageMaths(op_string="-Tmean", suffix="_mean"), name="meanfa") # Use the mean FA volume to generate a tract skeleton makeskeleton = pe.Node(fsl.TractSkeleton(skeleton_file=True), name="makeskeleton") tbss3.connect([ (maskgroup, meanfa, [("out_file", "in_file")]), (meanfa, makeskeleton, [("out_file", "in_file")]), (groupmask, outputnode, [('out_file', 'groupmask')]), (makeskeleton, outputnode, [('skeleton_file', 'skeleton_file')]), (meanfa, outputnode, [('out_file', 'meanfa_file')]), (maskgroup, outputnode, [('out_file', 'mergefa_file')]) ]) else: #$FSLDIR/bin/fslmaths $FSLDIR/data/standard/FMRIB58_FA_1mm -mas mean_FA_mask mean_FA maskstd = pe.Node(fsl.ImageMaths(op_string="-mas", suffix="_masked"), name="maskstd") maskstd.inputs.in_file = fsl.Info.standard_image( "FMRIB58_FA_1mm.nii.gz") #$FSLDIR/bin/fslmaths mean_FA -bin mean_FA_mask binmaskstd = pe.Node(fsl.ImageMaths(op_string="-bin"), name="binmaskstd") #$FSLDIR/bin/fslmaths all_FA -mas mean_FA_mask all_FA maskgroup2 = pe.Node(fsl.ImageMaths(op_string="-mas", suffix="_masked"), name="maskgroup2") tbss3.connect([(groupmask, maskstd, [("out_file", "in_file2")]), (maskstd, binmaskstd, [("out_file", "in_file")]), (maskgroup, maskgroup2, [("out_file", "in_file")]), (binmaskstd, maskgroup2, [("out_file", "in_file2")])]) outputnode.inputs.skeleton_file = fsl.Info.standard_image( "FMRIB58_FA-skeleton_1mm.nii.gz") tbss3.connect([(binmaskstd, outputnode, [('out_file', 'groupmask')]), (maskstd, outputnode, [('out_file', 'meanfa_file')]), (maskgroup2, outputnode, [('out_file', 'mergefa_file')]) ]) return tbss3
def tbss4d(self, tbss_dir, oDir, template, **kwargs): """ python function to generate 4d nii files for randomise from TBSS. Required arguments: tbss_dir --- where the 'FA' and 'stats' folder exists. This by default on knicr servers is here: /Volumes/rbraid/mr_data_idc/aug2013_final/dti/tbss oDir --- this is where you want the 4d files to go. This should be specific to the analysis you are doing e.g., /home/tonya/my_data/tbss/dysregulation_analysis/ Default is to assume scalars FA, MD, RD, AD are all processed. Also assumes the subject files are named as such: idc_#_SCALAR_to_FMRIB58_FA_2mm_nonlinear.nii.gz Optional Arguments: tbss_pfix --- default is "idc_" This is what goes before the subject id String type tbss_sfix --- default is "_to_FMRIB58_FA_2mm_nonlin.nii.gz" This is what goes after the subject id and scalar name (eg FA, MD) String type Scalars --- List of Scalars default is: [FA, MD, RD, AD] List type opfix --- prefix for the 4d output file. suffix will be the scalar type. default is tbss_all_ string type. """ tbss_pfix = 'idc_' tbss_sfix = '_to_FMRIB58_FA_2mm_nonlin.nii.gz' scalars = ['FA', 'MD', 'RD', 'AD'] opfix = 'tbss_all_' threshold = 0.2 for i in kwargs.keys(): if i == 'tbss_pfix': tbss_pfix = kwargs[i] elif i == 'tbss_sfix': tbss_sfix = kwargs[i] elif i == 'opfix': opfix = kwargs[i] elif i == 'scalars': scalars = kwargs[i] if not type(scalars) is list: print 'ERROR....scalar option must be a LIST!' print 'Resetting scalars to be FA only...' scalars = ['FA'] elif i == 'threshold': threshold = kwarg[i] for scalar in scalars: print 'writing out 4d file for component: ', scalar fourDlist = [] for s in range(0, self.subj_list.shape[0]): subj = str(int(self.subj_list[s][0])) tbss_file = os.path.join( tbss_dir, 'FA', tbss_pfix + subj + '_' + scalar + tbss_sfix) if not os.path.exists(tbss_file): print 'CANNOT FIND tbss data for :', subj, scalar print 'Looked here: ', tbss_file print 'Cannot continue...must exit...' sys.exit(0) fourDlist.append(tbss_file) #merge the file logFile = os.path.join(oDir, 'tbss_nonFA.log') merged4d = os.path.join(oDir, opfix + scalar + '.nii.gz') if not os.path.exists(merged4d): fslmerge = fsl.Merge(dimension='t', terminal_output='stream', in_files=fourDlist, merged_file=merged4d, output_type='NIFTI_GZ') fslmerge.run() write_log(fslmerge.cmdline, logFile) subjinfo = merged4d.replace('.nii.gz', '_mergeInfo.csv') write_txt(fourDlist, subjinfo) if scalar.endswith('_FA'): #next we make the mean FA image op_str = '-max 0 -Tmin -bin' fslmaths = fsl.ImageMaths(in_file=merged4d, op_string=op_str, out_file=os.path.join( oDir, 'mean_FA_mask.nii.gz'), output_type='NIFTI_GZ', out_data_type='char') fslmaths.run() write_log(fslmaths.cmdline, logFile) op_str = '-mas ' + os.path.join(oDir, 'mean_FA_mask.nii.gz') fslmaths = fsl.ImageMaths(in_file=merged4d, op_string=op_str, out_file=merged4d.replace( '.nii.gz', '_masked.nii.gz'), output_type='NIFTI_GZ') fslmaths.run() write_log(fslmaths.cmdline, logFile) op_str = '-Tmean' fslmaths = fsl.ImageMaths( in_file=merged4d.replace('.nii.gz', '_masked.nii.gz'), op_string=op_str, out_file=os.path.join(oDir, 'mean_FA.nii.gz'), output_type='NIFTI_GZ') fslmaths.run() write_log(fslmaths.cmdline, logFile) #now make the initial skeleton tbss_skeleton = fsl.TractSkeleton( in_file=os.path.join(oDir, 'mean_FA.nii.gz'), skeleton_file=os.path.join(oDir, 'mean_FA_skeleton.nii.gz')) tbss_skeleton.run() write_log(tbss_skeleton.cmdline, logFile) print 'Creating Skeleton Mask using threshold', str(threshold) op_str = '-thr ' + str(threshold) + ' -bin' fslmaths = fsl.ImageMaths( in_file=os.path.join(oDir, 'mean_FA_skeleton.nii.gz'), op_string=op_str, out_file=os.path.join(oDir, 'mean_FA_skeleton_mask.nii.gz'), output_type='NIFTI_GZ') fslmaths.run() write_log(fslmaths.cmdline, logFile) print 'Creating skeleton distancemap (for use in projection search)' op_str = '-mul 1 -add 1 -add ' + os.path.join( oDir, 'mean_FA_skeleton_mask.nii.gz') fslmaths = fsl.ImageMaths( in_file=os.path.join(oDir, 'mean_FA_mask.nii.gz'), op_string=op_str, out_file=os.path.join(oDir, 'mean_FA_skeleton_mask_dst.nii.gz'), output_type='NIFTI_GZ') fslmaths.run() write_log(fslmaths.cmdline, logFile) distancemap = fsl.DistanceMap( in_file=os.path.join(oDir, 'mean_FA_skeleton_mask_dst.nii.gz'), distance_map=os.path.join( oDir, 'mean_FA_skeleton_mask_dst.nii.gz')) distancemap.run() write_log(distancemap.cmdline, logFile) #to make things easier below, make a generic-named copy of the 4d fa map. needed for skeletonization. shutil.copyfile(merged4d.replace('.nii.gz', '_masked.nii.gz'), os.path.join(oDir, 'all_FA.nii.gz')) else: if not os.path.exists(os.path.join(oDir, 'mean_FA_mask.nii.gz')): print oDir, 'mean_FA_mask.nii.gz does not exist' print 'Make sure FA is the first scalar in your list. Must exit' sys.exit(0) #mask other scalars op_str = '-mas ' + os.path.join(oDir, 'mean_FA_mask.nii.gz') fslmaths = fsl.ImageMaths(in_file=merged4d, op_string=op_str, out_file=merged4d.replace( '.nii.gz', '_masked.nii.gz'), output_type='NIFTI_GZ') fslmaths.run() write_log(fslmaths.cmdline, logFile) #skeletenize nb_template = nb.load(template) x = abs(nb_template.get_affine()[0][0]) y = abs(nb_template.get_affine()[1][1]) z = abs(nb_template.get_affine()[2][2]) cing_file1mm = os.path.join(os.environ['FSLDIR'], 'data', 'standard', 'LowerCingulum_1mm.nii.gz') if x == 1 and y == 1 and z == 1: cing_file = cing_file1mm elif x == 2 and y == 2 and z == 2: cing_file = os.path.join(os.environ['FSLDIR'], 'data', 'standard', 'LowerCingulum_2mm.nii.gz') if not os.path.exists(cing_file): cing_file = os.path.join(oDir, 'LowerCingulum_2mm.nii.gz') flirt = fsl.FLIRT(in_file=cing_file1mm, reference=os.path.join( os.environ['FSLDIR'], 'data', 'standard', 'MNI152_T1_2mm.nii.gz'), out_file=cing_file, args='-applyisoxfm 2') flirt.run() write_log(flirt.cmdline, logFile) else: cing_file = False if not cing_file: print 'Cannot find cingulum file.' return print 'Projecting all FA data onto Skeleton' #run the tbss skeletonize thing if not os.path.exists(os.path.join(oDir, 'mean_FA_mask.nii.gz')): print oDir, 'mean_FA_mask.nii.gz does not exist' print 'Make sure FA is the first scalar in your list. Must exit' sys.exit(0) final4d = merged4d.replace('.nii.gz', '_skeletonized.nii.gz') tbss_skeleton = fsl.TractSkeleton( threshold=threshold, distance_map=os.path.join(oDir, 'mean_FA_skeleton_mask_dst.nii.gz'), alt_data_file=merged4d.replace('.nii.gz', '_masked.nii.gz'), data_file=os.path.join(oDir, 'all_FA.nii.gz'), projected_data=final4d, in_file=os.path.join(oDir, 'mean_FA.nii.gz'), project_data=True) tbss_skeleton.inputs.use_cingulum_mask = Undefined tbss_skeleton.inputs.search_mask_file = cing_file tbss_skeleton.run() write_log(tbss_skeleton.cmdline, logFile)
def create_tbss_3_postreg(name='tbss_3_postreg'): """Post-registration processing: derive mean_FA and mean_FA_skeleton from mean of all subjects in study. A pipeline that does the same as tbss_3_postreg script from FSL Example -------- >>>tbss3 = create_tbss_3_postreg(name='tbss3') >>>... Inputs:: inputnode.wraped_fa_list Outputs:: outputnode.groupmask outputnode.skeleton_file outputnode.meanfa_file outputnode.mergefa_file """ # Create the inputnode inputnode = pe.Node(interface = util.IdentityInterface(fields=['field_list', 'fa_list', 'target']), name='inputnode') # Apply the warpfield to the masked FA image applywarp = pe.MapNode(interface=fsl.ApplyWarp(), iterfield=['in_file','field_file'], name="applywarp") # Merge the FA files into a 4D file mergefa = pe.Node(fsl.Merge(dimension="t", merged_file="all_FA.nii.gz"), name="mergefa") # Get a group mask groupmask = pe.Node(fsl.ImageMaths(op_string="-max 0 -Tmin -bin", out_data_type="char", suffix="_mask"), name="groupmask") maskgroup = pe.Node(fsl.ImageMaths(op_string="-mas", suffix="_masked"), name="maskgroup") # Take the mean over the fourth dimension meanfa = pe.Node(fsl.ImageMaths(op_string="-Tmean", suffix="_mean"), name="meanfa") # Use the mean FA volume to generate a tract skeleton makeskeleton = pe.Node(fsl.TractSkeleton(skeleton_file=True), name="makeskeleton") tbss3 = pe.Workflow(name=name) tbss3.connect([ (inputnode,applywarp,[("fa_list", "in_file"), ("target","ref_file"), ("field_list", "field_file")]), (applywarp, mergefa, [("out_file", "in_files")]), (mergefa, groupmask, [("merged_file", "in_file")]), (mergefa, maskgroup, [("merged_file", "in_file")]), (groupmask, maskgroup, [("out_file", "in_file2")]), (maskgroup, meanfa, [("out_file", "in_file")]), (meanfa, makeskeleton, [("out_file", "in_file")]) ]) # Create outputnode outputnode = pe.Node(interface = util.IdentityInterface(fields=['groupmask', 'skeleton_file', 'meanfa_file', 'mergefa_file']), name='outputnode') tbss3.connect([ (groupmask, outputnode,[('out_file', 'groupmask')]), (makeskeleton, outputnode,[('skeleton_file', 'skeleton_file')]), (meanfa, outputnode,[('out_file', 'meanfa_file')]), (maskgroup, outputnode,[('out_file', 'mergefa_file')]) ]) return tbss3
def create_cross_sectional_tbss_pipeline(in_files, output_dir, name='cross_sectional_tbss', skeleton_threshold=0.2, design_mat=None, design_con=None): workflow = pe.Workflow(name=name) workflow.base_dir = output_dir workflow.base_output_dir = name # Create the dtitk groupwise registration workflow groupwise_dtitk = create_dtitk_groupwise_workflow(in_files=in_files, name="dtitk_groupwise", rig_iteration=3, aff_iteration=3, nrr_iteration=6) # Create the average FA map mean_fa = pe.Node(interface=dtitk.TVtool(), name="mean_fa") workflow.connect(groupwise_dtitk, 'output_node.out_template', mean_fa, 'in_file') mean_fa.inputs.operation = 'fa' # Register the FMRIB58_FA_1mm.nii.gz atlas to the mean FA map reg_atlas = pe.Node(interface=niftyreg.RegAladin(), name='reg_atlas') workflow.connect(mean_fa, 'out_file', reg_atlas, 'ref_file') reg_atlas.inputs.flo_file = os.path.join(os.environ['FSLDIR'], 'data', 'standard', 'FMRIB58_FA_1mm.nii.gz') # Apply the transformation to the lower cingulum image war_atlas = pe.Node(interface=niftyreg.RegResample(), name='war_atlas') workflow.connect(mean_fa, 'out_file', war_atlas, 'ref_file') war_atlas.inputs.flo_file = os.path.join(os.environ['FSLDIR'], 'data', 'standard', 'LowerCingulum_1mm.nii.gz') workflow.connect(reg_atlas, 'aff_file', war_atlas, 'trans_file') war_atlas.inputs.inter_val = 'LIN' # Threshold the propagated lower cingulum thr_atlas = pe.Node(interface=niftyseg.BinaryMaths(), name='thr_atlas') workflow.connect(war_atlas, 'out_file', thr_atlas, 'in_file') thr_atlas.inputs.operation = 'thr' thr_atlas.inputs.operand_value = 0.5 # Binarise the propagated lower cingulum bin_atlas = pe.Node(interface=niftyseg.UnaryMaths(), name='bin_atlas') workflow.connect(thr_atlas, 'out_file', bin_atlas, 'in_file') bin_atlas.inputs.operation = 'bin' # Create all the individual FA maps individual_fa = pe.MapNode(interface=dtitk.TVtool(), name="individual_fa", iterfield=['in_file']) workflow.connect(groupwise_dtitk, 'output_node.out_res', individual_fa, 'in_file') individual_fa.inputs.operation = 'fa' # Create all the individual MD maps individual_md = pe.MapNode(interface=dtitk.TVtool(), name="individual_md", iterfield=['in_file']) workflow.connect(groupwise_dtitk, 'output_node.out_res', individual_md, 'in_file') individual_md.inputs.operation = 'tr' # Create all the individual RD maps individual_rd = pe.MapNode(interface=dtitk.TVtool(), name="individual_rd", iterfield=['in_file']) workflow.connect(groupwise_dtitk, 'output_node.out_res', individual_rd, 'in_file') individual_rd.inputs.operation = 'rd' # Create all the individual RD maps individual_ad = pe.MapNode(interface=dtitk.TVtool(), name="individual_ad", iterfield=['in_file']) workflow.connect(groupwise_dtitk, 'output_node.out_res', individual_ad, 'in_file') individual_ad.inputs.operation = 'ad' # Combine all the warped FA images into a 4D image merged_4d_fa = pe.Node(interface=fsl.Merge(), name='merged_4d_fa') merged_4d_fa.inputs.dimension = 't' workflow.connect(individual_fa, 'out_file', merged_4d_fa, 'in_files') # Combine all the warped MD images into a 4D image merged_4d_md = pe.Node(interface=fsl.Merge(), name='merged_4d_md') merged_4d_md.inputs.dimension = 't' workflow.connect(individual_md, 'out_file', merged_4d_md, 'in_files') # Combine all the warped RD images into a 4D image merged_4d_rd = pe.Node(interface=fsl.Merge(), name='merged_4d_rd') merged_4d_rd.inputs.dimension = 't' workflow.connect(individual_rd, 'out_file', merged_4d_rd, 'in_files') # Combine all the warped AD images into a 4D image merged_4d_ad = pe.Node(interface=fsl.Merge(), name='merged_4d_ad') merged_4d_ad.inputs.dimension = 't' workflow.connect(individual_ad, 'out_file', merged_4d_ad, 'in_files') # Threshold the 4D FA image to 0 merged_4d_fa_thresholded = pe.Node(interface=niftyseg.BinaryMaths(), name='merged_4d_fa_thresholded') merged_4d_fa_thresholded.inputs.operation = 'thr' merged_4d_fa_thresholded.inputs.operand_value = 0 workflow.connect(merged_4d_fa, 'merged_file', merged_4d_fa_thresholded, 'in_file') # Extract the min value from the 4D FA image minimal_value_across_all_fa = pe.Node(interface=niftyseg.UnaryMaths(), name='minimal_value_across_all_fa') minimal_value_across_all_fa.inputs.operation = 'tmin' workflow.connect(merged_4d_fa_thresholded, 'out_file', minimal_value_across_all_fa, 'in_file') # Create the mask image fa_mask = pe.Node(interface=niftyseg.UnaryMaths(), name='fa_mask') fa_mask.inputs.operation = 'bin' fa_mask.inputs.output_datatype = 'char' workflow.connect(minimal_value_across_all_fa, 'out_file', fa_mask, 'in_file') # Mask the mean FA image masked_mean_fa = pe.Node(interface=fsl.ApplyMask(), name='masked_mean_fa') workflow.connect(mean_fa, 'out_file', masked_mean_fa, 'in_file') workflow.connect(fa_mask, 'out_file', masked_mean_fa, 'mask_file') # Create the skeleton image skeleton = pe.Node(interface=fsl.TractSkeleton(), name='skeleton') skeleton.inputs.skeleton_file = True workflow.connect(masked_mean_fa, 'out_file', skeleton, 'in_file') # Threshold the skeleton image thresholded_skeleton = pe.Node(interface=niftyseg.BinaryMaths(), name='thresholded_skeleton') thresholded_skeleton.inputs.operation = 'thr' thresholded_skeleton.inputs.operand_value = skeleton_threshold workflow.connect(skeleton, 'skeleton_file', thresholded_skeleton, 'in_file') # Binarise the skeleton image binarised_skeleton = pe.Node(interface=niftyseg.UnaryMaths(), name='binarised_skeleton') binarised_skeleton.inputs.operation = 'bin' workflow.connect(thresholded_skeleton, 'out_file', binarised_skeleton, 'in_file') # Create skeleton distance map invert_mask1 = pe.Node(interface=niftyseg.BinaryMaths(), name='invert_mask1') invert_mask1.inputs.operation = 'mul' invert_mask1.inputs.operand_value = -1 workflow.connect(fa_mask, 'out_file', invert_mask1, 'in_file') invert_mask2 = pe.Node(interface=niftyseg.BinaryMaths(), name='invert_mask2') invert_mask2.inputs.operation = 'add' invert_mask2.inputs.operand_value = 1 workflow.connect(invert_mask1, 'out_file', invert_mask2, 'in_file') invert_mask3 = pe.Node(interface=niftyseg.BinaryMaths(), name='invert_mask3') invert_mask3.inputs.operation = 'add' workflow.connect(invert_mask2, 'out_file', invert_mask3, 'in_file') workflow.connect(binarised_skeleton, 'out_file', invert_mask3, 'operand_file') distance_map = pe.Node(interface=fsl.DistanceMap(), name='distance_map') workflow.connect(invert_mask3, 'out_file', distance_map, 'in_file') # Project the FA values onto the skeleton all_fa_projected = pe.Node(interface=fsl.TractSkeleton(), name='all_fa_projected') all_fa_projected.inputs.threshold = skeleton_threshold all_fa_projected.inputs.project_data = True workflow.connect(masked_mean_fa, 'out_file', all_fa_projected, 'in_file') workflow.connect(distance_map, 'distance_map', all_fa_projected, 'distance_map') workflow.connect(merged_4d_fa, 'merged_file', all_fa_projected, 'data_file') workflow.connect(bin_atlas, 'out_file', all_fa_projected, 'search_mask_file') # Project the MD values onto the skeleton all_md_projected = pe.Node(interface=fsl.TractSkeleton(), name='all_md_projected') all_md_projected.inputs.threshold = skeleton_threshold all_md_projected.inputs.project_data = True workflow.connect(masked_mean_fa, 'out_file', all_md_projected, 'in_file') workflow.connect(distance_map, 'distance_map', all_md_projected, 'distance_map') workflow.connect(merged_4d_fa, 'merged_file', all_md_projected, 'data_file') workflow.connect(merged_4d_md, 'merged_file', all_md_projected, 'alt_data_file') workflow.connect(bin_atlas, 'out_file', all_md_projected, 'search_mask_file') # Project the RD values onto the skeleton all_rd_projected = pe.Node(interface=fsl.TractSkeleton(), name='all_rd_projected') all_rd_projected.inputs.threshold = skeleton_threshold all_rd_projected.inputs.project_data = True workflow.connect(masked_mean_fa, 'out_file', all_rd_projected, 'in_file') workflow.connect(distance_map, 'distance_map', all_rd_projected, 'distance_map') workflow.connect(merged_4d_fa, 'merged_file', all_rd_projected, 'data_file') workflow.connect(merged_4d_rd, 'merged_file', all_rd_projected, 'alt_data_file') workflow.connect(bin_atlas, 'out_file', all_rd_projected, 'search_mask_file') # Project the RD values onto the skeleton all_ad_projected = pe.Node(interface=fsl.TractSkeleton(), name='all_ad_projected') all_ad_projected.inputs.threshold = skeleton_threshold all_ad_projected.inputs.project_data = True workflow.connect(masked_mean_fa, 'out_file', all_ad_projected, 'in_file') workflow.connect(distance_map, 'distance_map', all_ad_projected, 'distance_map') workflow.connect(merged_4d_fa, 'merged_file', all_ad_projected, 'data_file') workflow.connect(merged_4d_ad, 'merged_file', all_ad_projected, 'alt_data_file') workflow.connect(bin_atlas, 'out_file', all_ad_projected, 'search_mask_file') # Create an output node output_node = pe.Node(interface=niu.IdentityInterface(fields=[ 'mean_fa', 'all_fa_skeletonised', 'all_md_skeletonised', 'all_rd_skeletonised', 'all_ad_skeletonised', 'skeleton', 'skeleton_bin', 't_contrast_raw_stat', 't_contrast_uncorrected_pvalue', 't_contrast_corrected_pvalue' ]), name='output_node') # Connect the workflow to the output node workflow.connect(masked_mean_fa, 'out_file', output_node, 'mean_fa') workflow.connect(all_fa_projected, 'projected_data', output_node, 'all_fa_skeletonised') workflow.connect(all_md_projected, 'projected_data', output_node, 'all_md_skeletonised') workflow.connect(all_rd_projected, 'projected_data', output_node, 'all_rd_skeletonised') workflow.connect(all_ad_projected, 'projected_data', output_node, 'all_ad_skeletonised') workflow.connect(skeleton, 'skeleton_file', output_node, 'skeleton') workflow.connect(binarised_skeleton, 'out_file', output_node, 'skeleton_bin') # Run randomise if required and connect its output to the output node if design_mat is not None and design_con is not None: randomise = pe.Node(interface=fsl.Randomise(), name='randomise') randomise.inputs.base_name = 'stats_tbss' randomise.inputs.tfce2D = True randomise.inputs.num_perm = 5000 workflow.connect(all_fa_projected, 'projected_data', randomise, 'in_file') randomise.inputs.design_mat = design_mat randomise.inputs.design_con = design_con workflow.connect(binarised_skeleton, 'out_file', randomise, 'mask') workflow.connect(randomise, 'tstat_files', output_node, 't_contrast_raw_stat') workflow.connect(randomise, 't_p_files', output_node, 't_contrast_uncorrected_pvalue') workflow.connect(randomise, 't_corrected_p_files', output_node, 't_contrast_corrected_pvalue') # Create nodes to rename the outputs mean_fa_renamer = pe.Node(interface=niu.Rename( format_string='tbss_mean_fa', keep_ext=True), name='mean_fa_renamer') workflow.connect(output_node, 'mean_fa', mean_fa_renamer, 'in_file') mean_sk_renamer = pe.Node(interface=niu.Rename( format_string='tbss_mean_fa_skeleton', keep_ext=True), name='mean_sk_renamer') workflow.connect(output_node, 'skeleton', mean_sk_renamer, 'in_file') bin_ske_renamer = pe.Node(interface=niu.Rename( format_string='tbss_mean_fa_skeleton_mask', keep_ext=True), name='bin_ske_renamer') workflow.connect(output_node, 'skeleton_bin', bin_ske_renamer, 'in_file') fa_skel_renamer = pe.Node(interface=niu.Rename( format_string='tbss_all_fa_skeletonised', keep_ext=True), name='fa_skel_renamer') workflow.connect(output_node, 'all_fa_skeletonised', fa_skel_renamer, 'in_file') md_skel_renamer = pe.Node(interface=niu.Rename( format_string='tbss_all_md_skeletonised', keep_ext=True), name='md_skel_renamer') workflow.connect(output_node, 'all_md_skeletonised', md_skel_renamer, 'in_file') rd_skel_renamer = pe.Node(interface=niu.Rename( format_string='tbss_all_rd_skeletonised', keep_ext=True), name='rd_skel_renamer') workflow.connect(output_node, 'all_rd_skeletonised', rd_skel_renamer, 'in_file') ad_skel_renamer = pe.Node(interface=niu.Rename( format_string='tbss_all_ad_skeletonised', keep_ext=True), name='ad_skel_renamer') workflow.connect(output_node, 'all_ad_skeletonised', ad_skel_renamer, 'in_file') # Create a data sink ds = pe.Node(nio.DataSink(parameterization=False), name='data_sink') ds.inputs.base_directory = os.path.abspath(output_dir) # Connect the data sink workflow.connect(mean_fa_renamer, 'out_file', ds, '@mean_fa') workflow.connect(mean_sk_renamer, 'out_file', ds, '@skel_fa') workflow.connect(bin_ske_renamer, 'out_file', ds, '@bkel_fa') workflow.connect(fa_skel_renamer, 'out_file', ds, '@all_fa') workflow.connect(md_skel_renamer, 'out_file', ds, '@all_md') workflow.connect(rd_skel_renamer, 'out_file', ds, '@all_rd') workflow.connect(ad_skel_renamer, 'out_file', ds, '@all_ad') if design_mat is not None and design_con is not None: workflow.connect(output_node, 't_contrast_raw_stat', ds, '@t_contrast_raw_stat') workflow.connect(output_node, 't_contrast_uncorrected_pvalue', ds, '@t_contrast_uncorrected_pvalue') workflow.connect(output_node, 't_contrast_corrected_pvalue', ds, '@t_contrast_corrected_pvalue') return workflow