def init_mask_overlap_wf(name="mask_overlap_wf"): """Check the Dice overlap of a b=0 mask and a T1-based mask for QC. **Inputs** anatomical_mask Path to a high-resolution brain mask from a T1w image dwi_mask Path to a mask based on diffusion-weighted images **Outputs** dice_score float value of the dice overlap of the masks """ inputnode = pe.Node( niu.IdentityInterface(fields=['anatomical_mask', 'dwi_mask']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=['dice_score']), name='outputnode') downsample_t1_mask = pe.Node(afni.Resample(resample_mode="NN", outputtype="NIFTI_GZ"), name='downsample_t1_mask') calculate_dice = pe.Node(DiceOverlap(), name='calculate_dice') workflow = Workflow(name=name) workflow.connect([ (inputnode, downsample_t1_mask, [ ('anatomical_mask', 'in_file'), ('dwi_mask', 'master')]), (inputnode, calculate_dice, [('dwi_mask', 'dwi_mask')]), (downsample_t1_mask, calculate_dice, [('out_file', 'anatomical_mask')]), (calculate_dice, outputnode, [('dice_score', 'dice_score')])]) return workflow
def anatomical_init(wf, cfg, strat_pool, pipe_num, opt=None): ''' {"name": "anatomical_init", "config": "None", "switch": "None", "option_key": "None", "option_val": "None", "inputs": ["T1w"], "outputs": ["desc-preproc_T1w", "desc-reorient_T1w"]} ''' anat_deoblique = pe.Node(interface=afni.Refit(), name=f'anat_deoblique_{pipe_num}') anat_deoblique.inputs.deoblique = True node, out = strat_pool.get_data('T1w') wf.connect(node, out, anat_deoblique, 'in_file') anat_reorient = pe.Node(interface=afni.Resample(), name=f'anat_reorient_{pipe_num}') anat_reorient.inputs.orientation = 'RPI' anat_reorient.inputs.outputtype = 'NIFTI_GZ' wf.connect(anat_deoblique, 'out_file', anat_reorient, 'in_file') outputs = { 'desc-preproc_T1w': (anat_reorient, 'out_file'), 'desc-reorient_T1w': (anat_reorient, 'out_file') } return (wf, outputs)
def preprocess(aroma_config, fwhm_config, input_img, mask_file, taskdir, task): # Resample to mask space # This is for AROMA images. Does it hurt non-AROMA? resample_path = os.path.join(taskdir, task + '_resample.nii.gz') resample = afni.Resample(master=mask_file, out_file=resample_path, in_file=input_img) resample_run = resample.run() # Apply fmriprep-calculated brain mask to the functional image masked_file_path = os.path.join(taskdir, task + "_input_functional_masked.nii.gz") applymask = fsl.ApplyMask(mask_file=mask_file, out_file=masked_file_path) applymask.inputs.in_file = resample_run.outputs.out_file mask_run = applymask.run() masked_input = masked_file_path if aroma_config: print("No smoothing required.") processed_image = masked_input else: # smoothing print("Smoothing the skull-stripped BOLD.") smooth = fsl.Smooth(in_file=masked_input, fwhm=fwhm_config) smooth_run = smooth.run() processed_image = smooth_run.outputs.smoothed_file return processed_image
def create_workflow(config: AttrDict, resource_pool: ResourcePool, context: Context): for _, rp in resource_pool[['T1w']]: anat_image = rp[R('T1w')] anat_deoblique = NipypeJob(interface=afni.Refit(deoblique=True), reference='anat_deoblique') anat_deoblique.in_file = anat_image output_node = anat_deoblique.out_file if config.non_local_means_filtering: denoise = NipypeJob(interface=ants.DenoiseImage(), reference='anat_denoise') denoise.input_image = output_node output_node = denoise.output_image if config.n4_bias_field_correction: n4 = NipypeJob(interface=ants.N4BiasFieldCorrection( dimension=3, shrink_factor=2, copy_header=True), reference='anat_n4') n4.input_image = output_node output_node = n4.output_image anat_reorient = NipypeJob(interface=afni.Resample( orientation='RPI', outputtype='NIFTI_GZ'), reference='anat_reorient') anat_reorient.in_file = output_node rp[R('T1w', label='reorient')] = anat_reorient.out_file
def preprocess_MRI(self): """ Runs N4 Bias Correction and resamples MRI to higher resolution if necessary. """ print('Preprocessing MRI') self.MRI_path = self.root_dir + 'MRI/' if self.input.MRI.N4 == True: self.MRI_path += 'N4_' if os.path.isfile(self.MRI_path + os.path.split(self.MRI)[1] ) and self.overwrite == False: print(' - ' + self.MRI_path + os.path.split(self.MRI)[1] + ' Already Exists') self.MRI = self.MRI_path + os.path.split(self.MRI)[1] else: #Run N4 Bias Field Correction on MRI Volume N4 = N4BiasFieldCorrection() N4.inputs.dimension = 3 N4.inputs.input_image = self.MRI N4.inputs.output_image = self.MRI_path + os.path.split( self.MRI)[1] N4.cmdline N4.run() #Redefine MRI as the N4 corrected volume. self.MRI = N4.inputs.output_image self.MRI_path = self.MRI_path + 'reoriented_' if os.path.isfile(self.MRI_path + os.path.split(self.orig_MRI)[1] ) and self.overwrite == False: print(' - ' + self.MRI_path + os.path.split(self.orig_MRI)[1] + ' Already Exists') self.MRI = self.MRI_path + os.path.split(self.orig_MRI)[1] else: res = afni.Resample() res.inputs.in_file = self.MRI tmp = self.histology.orientation #Resample MRI to the orientation found in the histology and blockface images #NOTE: AFNI (the program used below) and Nibabel (the program used to read/write NIFTI files) #use opposite orientation nomenclature. While confusing, this means the orientation string must #be inverted before using AFNI. if self.histology.orientation.find('S') >= 0: tmp.replace('S', 'I') else: tmp.replace('I', 'S') if self.histology.orientation.find('R') >= 0: tmp.replace('R', 'L') else: tmp.replace('L', 'R') if self.histology.orientation.find('P') >= 0: tmp.replace('P', 'A') else: tmp.replace('A', 'P') print(tmp) res.inputs.orientation = tmp res.inputs.out_file = self.MRI_path + os.path.split( self.orig_MRI)[1] res.run() self.MRI = res.inputs.out_file
def init_dsi_studio_recon_wf(name="dsi_studio_recon", output_suffix="", params={}): """Reconstructs diffusion data using DSI Studio. This workflow creates a ``.src.gz`` file from the input dwi, bvals and bvecs, then reconstructs ODFs using GQI. Inputs *Default qsiprep inputs* Outputs fibgz A DSI Studio fib file containing GQI ODFs, peaks and scalar values. Params ratio_of_mean_diffusion_distance: float Default 1.25. Distance to sample EAP at. """ inputnode = pe.Node(niu.IdentityInterface(fields=input_fields), name="inputnode") outputnode = pe.Node(niu.IdentityInterface(fields=['fibgz']), name="outputnode") workflow = pe.Workflow(name=name) create_src = pe.Node(DSIStudioCreateSrc(), name="create_src") gqi_recon = pe.Node(DSIStudioGQIReconstruction(), name="gqi_recon") # Resample anat mask resample_mask = pe.Node(afni.Resample(outputtype='NIFTI_GZ', resample_mode="NN"), name='resample_mask') workflow.connect([ (inputnode, create_src, [('dwi_file', 'input_nifti_file'), ('bval_file', 'input_bvals_file'), ('bvec_file', 'input_bvecs_file')]), (inputnode, resample_mask, [('t1_brain_mask', 'in_file'), ('dwi_file', 'master')]), (create_src, gqi_recon, [('output_src', 'input_src_file')]), (resample_mask, gqi_recon, [('out_file', 'mask')]), (gqi_recon, outputnode, [('output_fib', 'fibgz')]) ]) if output_suffix: # Save the output in the outputs directory ds_gqi_fibgz = pe.Node(ReconDerivativesDataSink(extension='.fib.gz', suffix=output_suffix, compress=True), name='ds_gqi_fibgz', run_without_submitting=True) workflow.connect(gqi_recon, 'output_fib', ds_gqi_fibgz, 'in_file') return workflow
def lesion_preproc(lesion_mask: str): lesion_deoblique = NipypeJob(interface=afni.Refit(deoblique=True), reference='lesion_deoblique') lesion_inverted = PythonJob(function=inverse_lesion, reference='inverse_lesion') lesion_reorient = NipypeJob(interface=afni.Resample(orientation='RPI', outputtype='NIFTI_GZ'), reference='lesion_reorient') lesion_inverted.lesion_path = S3Resource(lesion_mask) if lesion_mask.lower( ).startswith('s3://') else lesion_mask lesion_deoblique.in_file = lesion_inverted.lesion_out lesion_reorient.in_file = lesion_deoblique.out_file return lesion_reorient.out_file
def resolve_resolution(resolution, template, template_name, tag=None): import nipype.interfaces.afni as afni import nipype.pipeline.engine as pe from CPAC.utils.datasource import check_for_s3 tagname = None local_path = None if "{" in template and tag is not None: tagname = "${" + tag + "}" try: if tagname is not None: local_path = check_for_s3( template.replace(tagname, str(resolution))) except (IOError, OSError): local_path = None ## TODO debug - it works in ipython but doesn't work in nipype wf # try: # local_path = check_for_s3('/usr/local/fsl/data/standard/MNI152_T1_3.438mmx3.438mmx3.4mm_brain_mask_dil.nii.gz') # except (IOError, OSError): # local_path = None if local_path is None: if tagname is not None: ref_template = template.replace(tagname, '1mm') local_path = check_for_s3(ref_template) elif tagname is None and "s3" in template: local_path = check_for_s3(template) else: local_path = template if "x" in str(resolution): resolution = tuple( float(i.replace('mm', '')) for i in resolution.split("x")) else: resolution = (float(resolution.replace('mm', '')), ) * 3 resample = pe.Node(interface=afni.Resample(), name=template_name) resample.inputs.voxel_size = resolution resample.inputs.outputtype = 'NIFTI_GZ' resample.inputs.resample_mode = 'Cu' resample.inputs.in_file = local_path resample.base_dir = '.' resampled_template = resample.run() local_path = resampled_template.outputs.out_file return local_path
def _reorient_wf(name='ReorientWorkflow'): """A workflow to reorient images to 'RPI' orientation.""" workflow = Workflow(name=name) workflow.__desc__ = "Inner workflow. " inputnode = Node(niu.IdentityInterface(fields=['in_file']), name='inputnode') outputnode = Node(niu.IdentityInterface(fields=['out_file']), name='outputnode') deoblique = Node(afni.Refit(deoblique=True), name='deoblique') reorient = Node(afni.Resample(orientation='RPI', outputtype='NIFTI_GZ'), name='reorient') workflow.connect([(inputnode, deoblique, [('in_file', 'in_file')]), (deoblique, reorient, [('out_file', 'in_file')]), (reorient, outputnode, [('out_file', 'out_file')])]) return workflow
def create_workflow(config: AttrDict, resource_pool: ResourcePool, context: Context): for _, rp in resource_pool[['T1w']]: anat_image = rp[R('T1w')] anat_deoblique = NipypeJob( interface=afni.Refit(deoblique=True), reference='deoblique' ) anat_deoblique.in_file = anat_image output_node = anat_deoblique.out_file anat_reorient = NipypeJob( interface=afni.Resample(orientation='RPI', outputtype='NIFTI_GZ'), reference='reorient' ) anat_reorient.in_file = output_node rp[R('T1w', label='reorient')] = anat_reorient.out_file
def _reorient_wf(name="ReorientWorkflow"): """A workflow to reorient images to 'RPI' orientation.""" workflow = Workflow(name=name) workflow.__desc__ = "Inner workflow. " inputnode = Node(niu.IdentityInterface(fields=["in_file"]), name="inputnode") outputnode = Node(niu.IdentityInterface(fields=["out_file"]), name="outputnode") deoblique = Node(afni.Refit(deoblique=True), name="deoblique") reorient = Node(afni.Resample(orientation="RPI", outputtype="NIFTI_GZ"), name="reorient") workflow.connect([ (inputnode, deoblique, [("in_file", "in_file")]), (deoblique, reorient, [("out_file", "in_file")]), (reorient, outputnode, [("out_file", "out_file")]), ]) return workflow
def resolve_resolution(resolution, template, template_name, tag=None): import nipype.interfaces.afni as afni import nipype.pipeline.engine as pe from CPAC.utils.datasource import check_for_s3 tagname = None local_path = None # TODO XL think a better way to check template if "{" in template and tag is not None: tagname = "${" + tag + "}" try: if tagname is not None: local_path = check_for_s3( template.replace(tagname, str(resolution))) except IOError: local_path = None if local_path is None: if tagname is not None: ref_template = template.replace(tagname, '1mm') local_path = check_for_s3(ref_template) elif tagname is None and "s3" in template: local_path = check_for_s3(template) else: local_path = template if "x" in str(resolution): resolution = tuple( float(i.replace('mm', '')) for i in resolution.split("x")) else: resolution = (float(resolution.replace('mm', '')), ) * 3 resample = pe.Node(interface=afni.Resample(), name=template_name) resample.inputs.voxel_size = resolution resample.inputs.outputtype = 'NIFTI_GZ' resample.inputs.resample_mode = 'Cu' resample.inputs.in_file = local_path resample.base_dir = '.' resampled_template = resample.run() local_path = resampled_template.outputs.out_file return local_path
def test_resample(): input_map = dict( args=dict(argstr='%s', ), environ=dict(usedefault=True, ), ignore_exception=dict(usedefault=True, ), in_file=dict( argstr='-inset %s', mandatory=True, ), orientation=dict(argstr='-orient %s', ), out_file=dict(argstr='-prefix %s', ), outputtype=dict(), suffix=dict(), ) instance = afni.Resample() for key, metadata in input_map.items(): for metakey, value in metadata.items(): yield assert_equal, getattr(instance.inputs.traits()[key], metakey), value
def resample_nifti_images(images_location, voxel_dimensions, resample_method): """Resample the NIfTI images in a folder and put them in a new folder Args: images_location: Path where the images are stored voxel_dimension: tuple (dx, dy, dz) resample_method: NN - Nearest neighbor Li - Linear interpolation Returns: None: """ image_files = sorted([ f for f in os.listdir(images_location) if os.path.isfile(os.path.join(images_location, f)) ]) voxel_size_str = '_{:.0f}mm'.format(float(voxel_dimensions[0])) new_folder = images_location + voxel_size_str if not os.path.exists(new_folder): os.makedirs(new_folder) for image_file in image_files: print(image_file) (file_name, file_ext) = os.path.splitext(image_file) new_file_name = ''.join([file_name, voxel_size_str, file_ext]) resample = afni.Resample() resample.inputs.environ = {'AFNI_NIFTI_TYPE_WARN': 'NO'} resample.inputs.in_file = os.path.join(images_location, image_file) resample.inputs.out_file = os.path.join(new_folder, new_file_name) resample.inputs.voxel_size = voxel_dimensions resample.inputs.outputtype = 'NIFTI' resample.inputs.resample_mode = resample_method resample.run()
def init_mask_finalize_wf(name="mask_finalize_wf"): """Creates a final mask using a combination of the t1 mask and dwi2mask """ inputnode = pe.Node( niu.IdentityInterface(fields=['t1_mask', 'resampled_b0s']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=['mask_file']), name='outputnode') workflow = Workflow(name=name) resample_t1_mask = pe.Node(afni.Resample(outputtype='NIFTI_GZ', resample_mode="NN"), name='resample_t1_mask') b0mask = pe.Node(afni.Automask(outputtype='NIFTI_GZ'), name='b0mask') or_mask = pe.Node(afni.Calc(outputtype='NIFTI_GZ', expr='step(a+b)'), name='or_mask') workflow.connect([(inputnode, resample_t1_mask, [('t1_mask', 'in_file'), ('resampled_b0s', 'master')]), (inputnode, b0mask, [('resampled_b0s', 'in_file')]), (b0mask, or_mask, [('out_file', 'in_file_a')]), (resample_t1_mask, or_mask, [('out_file', 'in_file_b')]), (or_mask, outputnode, [('out_file', 'mask_file')])]) return workflow
def create_anat_preproc(template_path=None, mask_path=None, regmask_path=None, method='afni', already_skullstripped=False, non_local_means_filtering=True, n4_correction=True, wf_name='anat_preproc'): """ The main purpose of this workflow is to process T1 scans. Raw mprage file is deobliqued, reoriented into RPI and skullstripped. Also, a whole brain only mask is generated from the skull stripped image for later use in registration. Returns ------- anat_preproc : workflow Anatomical Preprocessing Workflow Notes ----- `Source <https://github.com/FCP-INDI/C-PAC/blob/master/CPAC/anat_preproc/anat_preproc.py>`_ Workflow Inputs:: inputspec.anat : string User input anatomical (T1) Image, in any of the 8 orientations Workflow Outputs:: outputspec.refit : string Path to deobliqued anatomical image outputspec.reorient : string Path to RPI oriented anatomical image outputspec.skullstrip : string Path to skull stripped RPI oriented mprage file with normalized intensities. outputspec.brain : string Path to skull stripped RPI brain image with original intensity values and not normalized or scaled. Order of commands: - Deobliqing the scans. :: 3drefit -deoblique mprage.nii.gz - Re-orienting the Image into Right-to-Left Posterior-to-Anterior Inferior-to-Superior (RPI) orientation :: 3dresample -orient RPI -prefix mprage_RPI.nii.gz -inset mprage.nii.gz - Skull-Stripping the image :: Using AFNI :: 3dSkullStrip -input mprage_RPI.nii.gz -o_ply mprage_RPI_3dT.nii.gz or using BET :: bet mprage_RPI.nii.gz - The skull-stripping step modifies the intensity values. To get back the original intensity values, we do an element wise product of RPI data with step function of skull-stripped data :: 3dcalc -a mprage_RPI.nii.gz -b mprage_RPI_3dT.nii.gz -expr 'a*step(b)' -prefix mprage_RPI_3dc.nii.gz High Level Workflow Graph: .. image:: ../images/anatpreproc_graph.dot.png :width: 500 Detailed Workflow Graph: .. image:: ../images/anatpreproc_graph_detailed.dot.png :width: 500 Examples -------- >>> from CPAC.anat_preproc import create_anat_preproc >>> preproc = create_anat_preproc() >>> preproc.inputs.inputspec.anat = 'sub1/anat/mprage.nii.gz' >>> preproc.run() #doctest: +SKIP """ preproc = pe.Workflow(name=wf_name) inputnode = pe.Node(util.IdentityInterface(fields=['anat', 'brain_mask']), name='inputspec') outputnode = pe.Node(util.IdentityInterface( fields=['refit', 'reorient', 'skullstrip', 'brain', 'brain_mask']), name='outputspec') anat_deoblique = pe.Node(interface=afni.Refit(), name='anat_deoblique') anat_deoblique.inputs.deoblique = True preproc.connect(inputnode, 'anat', anat_deoblique, 'in_file') preproc.connect(anat_deoblique, 'out_file', outputnode, 'refit') # Disable non_local_means_filtering and n4_correction when run niworkflows-ants if method == 'niworkflows-ants': non_local_means_filtering = False n4_correction = False if non_local_means_filtering and n4_correction: denoise = pe.Node(interface=ants.DenoiseImage(), name='anat_denoise') preproc.connect(anat_deoblique, 'out_file', denoise, 'input_image') n4 = pe.Node(interface=ants.N4BiasFieldCorrection(dimension=3, shrink_factor=2, copy_header=True), name='anat_n4') preproc.connect(denoise, 'output_image', n4, 'input_image') elif non_local_means_filtering and not n4_correction: denoise = pe.Node(interface=ants.DenoiseImage(), name='anat_denoise') preproc.connect(anat_deoblique, 'out_file', denoise, 'input_image') elif not non_local_means_filtering and n4_correction: n4 = pe.Node(interface=ants.N4BiasFieldCorrection(dimension=3, shrink_factor=2, copy_header=True), name='anat_n4') preproc.connect(anat_deoblique, 'out_file', n4, 'input_image') # Anatomical reorientation anat_reorient = pe.Node(interface=afni.Resample(), name='anat_reorient') anat_reorient.inputs.orientation = 'RPI' anat_reorient.inputs.outputtype = 'NIFTI_GZ' if n4_correction: preproc.connect(n4, 'output_image', anat_reorient, 'in_file') elif non_local_means_filtering and not n4_correction: preproc.connect(denoise, 'output_image', anat_reorient, 'in_file') else: preproc.connect(anat_deoblique, 'out_file', anat_reorient, 'in_file') preproc.connect(anat_reorient, 'out_file', outputnode, 'reorient') if already_skullstripped: anat_skullstrip = pe.Node( interface=util.IdentityInterface(fields=['out_file']), name='anat_skullstrip') preproc.connect(anat_reorient, 'out_file', anat_skullstrip, 'out_file') preproc.connect(anat_skullstrip, 'out_file', outputnode, 'skullstrip') preproc.connect(anat_skullstrip, 'out_file', outputnode, 'brain') else: if method == 'afni': # Skull-stripping using AFNI 3dSkullStrip inputnode_afni = pe.Node(util.IdentityInterface(fields=[ 'shrink_factor', 'var_shrink_fac', 'shrink_fac_bot_lim', 'avoid_vent', 'niter', 'pushout', 'touchup', 'fill_hole', 'avoid_eyes', 'use_edge', 'exp_frac', 'smooth_final', 'push_to_edge', 'use_skull', 'perc_int', 'max_inter_iter', 'blur_fwhm', 'fac', 'monkey' ]), name='AFNI_options') skullstrip_args = pe.Node(util.Function( input_names=[ 'spat_norm', 'spat_norm_dxyz', 'shrink_fac', 'var_shrink_fac', 'shrink_fac_bot_lim', 'avoid_vent', 'niter', 'pushout', 'touchup', 'fill_hole', 'avoid_eyes', 'use_edge', 'exp_frac', 'smooth_final', 'push_to_edge', 'use_skull', 'perc_int', 'max_inter_iter', 'blur_fwhm', 'fac', 'monkey' ], output_names=['expr'], function=create_3dskullstrip_arg_string), name='anat_skullstrip_args') preproc.connect([(inputnode_afni, skullstrip_args, [('shrink_factor', 'shrink_fac'), ('var_shrink_fac', 'var_shrink_fac'), ('shrink_fac_bot_lim', 'shrink_fac_bot_lim'), ('avoid_vent', 'avoid_vent'), ('niter', 'niter'), ('pushout', 'pushout'), ('touchup', 'touchup'), ('fill_hole', 'fill_hole'), ('avoid_eyes', 'avoid_eyes'), ('use_edge', 'use_edge'), ('exp_frac', 'exp_frac'), ('smooth_final', 'smooth_final'), ('push_to_edge', 'push_to_edge'), ('use_skull', 'use_skull'), ('perc_int', 'perc_int'), ('max_inter_iter', 'max_inter_iter'), ('blur_fwhm', 'blur_fwhm'), ('fac', 'fac'), ('monkey', 'monkey')])]) anat_skullstrip = pe.Node(interface=afni.SkullStrip(), name='anat_skullstrip') anat_skullstrip.inputs.outputtype = 'NIFTI_GZ' preproc.connect(anat_reorient, 'out_file', anat_skullstrip, 'in_file') preproc.connect(skullstrip_args, 'expr', anat_skullstrip, 'args') preproc.connect(anat_skullstrip, 'out_file', outputnode, 'skullstrip') # Apply skull-stripping step mask to original volume anat_skullstrip_orig_vol = pe.Node(interface=afni.Calc(), name='anat_skullstrip_orig_vol') anat_skullstrip_orig_vol.inputs.expr = 'a*step(b)' anat_skullstrip_orig_vol.inputs.outputtype = 'NIFTI_GZ' preproc.connect(anat_reorient, 'out_file', anat_skullstrip_orig_vol, 'in_file_a') anat_brain_mask = pe.Node(interface=afni.Calc(), name='anat_brain_mask') anat_brain_mask.inputs.expr = 'step(a)' anat_brain_mask.inputs.outputtype = 'NIFTI_GZ' preproc.connect(anat_skullstrip, 'out_file', anat_brain_mask, 'in_file_a') preproc.connect(anat_skullstrip, 'out_file', anat_skullstrip_orig_vol, 'in_file_b') preproc.connect(anat_brain_mask, 'out_file', outputnode, 'brain_mask') preproc.connect(anat_skullstrip_orig_vol, 'out_file', outputnode, 'brain') elif method == 'fsl': # Skull-stripping using FSL BET inputnode_bet = pe.Node(util.IdentityInterface(fields=[ 'frac', 'mask_boolean', 'mesh_boolean', 'outline', 'padding', 'radius', 'reduce_bias', 'remove_eyes', 'robust', 'skull', 'surfaces', 'threshold', 'vertical_gradient' ]), name='BET_options') anat_skullstrip = pe.Node(interface=fsl.BET(), name='anat_skullstrip') preproc.connect(anat_reorient, 'out_file', anat_skullstrip, 'in_file') preproc.connect([(inputnode_bet, anat_skullstrip, [ ('frac', 'frac'), ('mask_boolean', 'mask'), ('mesh_boolean', 'mesh'), ('outline', 'outline'), ('padding', 'padding'), ('radius', 'radius'), ('reduce_bias', 'reduce_bias'), ('remove_eyes', 'remove_eyes'), ('robust', 'robust'), ('skull', 'skull'), ('surfaces', 'surfaces'), ('threshold', 'threshold'), ('vertical_gradient', 'vertical_gradient'), ])]) preproc.connect(anat_skullstrip, 'out_file', outputnode, 'skullstrip') # Apply skull-stripping step mask to original volume anat_skullstrip_orig_vol = pe.Node(interface=afni.Calc(), name='anat_skullstrip_orig_vol') anat_skullstrip_orig_vol.inputs.expr = 'a*step(b)' anat_skullstrip_orig_vol.inputs.outputtype = 'NIFTI_GZ' preproc.connect(anat_reorient, 'out_file', anat_skullstrip_orig_vol, 'in_file_a') preproc.connect(anat_skullstrip, 'out_file', anat_skullstrip_orig_vol, 'in_file_b') preproc.connect(anat_skullstrip, 'mask_file', outputnode, 'brain_mask') preproc.connect(anat_skullstrip_orig_vol, 'out_file', outputnode, 'brain') elif method == 'niworkflows-ants': # Skull-stripping using niworkflows-ants anat_skullstrip_ants = init_brain_extraction_wf( tpl_target_path=template_path, tpl_mask_path=mask_path, tpl_regmask_path=regmask_path, name='anat_skullstrip_ants') preproc.connect(anat_reorient, 'out_file', anat_skullstrip_ants, 'inputnode.in_files') preproc.connect(anat_skullstrip_ants, 'copy_xform.out_file', outputnode, 'skullstrip') preproc.connect(anat_skullstrip_ants, 'copy_xform.out_file', outputnode, 'brain') preproc.connect(anat_skullstrip_ants, 'atropos_wf.copy_xform.out_mask', outputnode, 'brain_mask') elif method == 'mask': anat_skullstrip_orig_vol = pe.Node(interface=afni.Calc(), name='anat_skullstrip_orig_vol') anat_skullstrip_orig_vol.inputs.expr = 'a*step(b)' anat_skullstrip_orig_vol.inputs.outputtype = 'NIFTI_GZ' preproc.connect(anat_reorient, 'out_file', anat_skullstrip_orig_vol, 'in_file_a') preproc.connect(inputnode, 'brain_mask', anat_skullstrip_orig_vol, 'in_file_b') preproc.connect(inputnode, 'brain_mask', outputnode, 'brain_mask') preproc.connect(anat_skullstrip_orig_vol, 'out_file', outputnode, 'brain') return preproc
def create_denoise_pipeline(name='denoise'): # workflow denoise = Workflow(name='denoise') # Define nodes inputnode = Node(interface=util.IdentityInterface(fields=[ 'anat_brain', 'brain_mask', 'epi2anat_dat', 'unwarped_mean', 'epi_coreg', 'moco_par', 'highpass_sigma', 'lowpass_sigma', 'tr' ]), name='inputnode') outputnode = Node(interface=util.IdentityInterface(fields=[ 'wmcsf_mask', 'brain_mask_resamp', 'brain_mask2epi', 'combined_motion', 'outlier_files', 'intensity_files', 'outlier_stats', 'outlier_plots', 'mc_regressor', 'mc_F', 'mc_pF', 'comp_regressor', 'comp_F', 'comp_pF', 'normalized_file' ]), name='outputnode') # run fast to get tissue probability classes fast = Node(fsl.FAST(), name='fast') denoise.connect([(inputnode, fast, [('anat_brain', 'in_files')])]) # functions to select tissue classes def selectindex(files, idx): import numpy as np from nipype.utils.filemanip import filename_to_list, list_to_filename return list_to_filename( np.array(filename_to_list(files))[idx].tolist()) def selectsingle(files, idx): return files[idx] # resample tissue classes resample_tissue = MapNode(afni.Resample(resample_mode='NN', outputtype='NIFTI_GZ'), iterfield=['in_file'], name='resample_tissue') denoise.connect([ (inputnode, resample_tissue, [('epi_coreg', 'master')]), (fast, resample_tissue, [(('partial_volume_files', selectindex, [0, 2]), 'in_file')]), ]) # binarize tissue classes binarize_tissue = MapNode( fsl.ImageMaths(op_string='-nan -thr 0.99 -ero -bin'), iterfield=['in_file'], name='binarize_tissue') denoise.connect([ (resample_tissue, binarize_tissue, [('out_file', 'in_file')]), ]) # combine tissue classes to noise mask wmcsf_mask = Node(fsl.BinaryMaths(operation='add', out_file='wmcsf_mask_lowres.nii.gz'), name='wmcsf_mask') denoise.connect([(binarize_tissue, wmcsf_mask, [(('out_file', selectsingle, 0), 'in_file'), (('out_file', selectsingle, 1), 'operand_file')]), (wmcsf_mask, outputnode, [('out_file', 'wmcsf_mask')])]) # resample brain mask resample_brain = Node(afni.Resample( resample_mode='NN', outputtype='NIFTI_GZ', out_file='T1_brain_mask_lowres.nii.gz'), name='resample_brain') denoise.connect([(inputnode, resample_brain, [('brain_mask', 'in_file'), ('epi_coreg', 'master')]), (resample_brain, outputnode, [('out_file', 'brain_mask_resamp')])]) # project brain mask into original epi space fpr quality assessment brainmask2epi = Node(fs.ApplyVolTransform( interp='nearest', inverse=True, transformed_file='T1_brain_mask2epi.nii.gz', ), name='brainmask2epi') denoise.connect([ (inputnode, brainmask2epi, [('brain_mask', 'target_file'), ('epi2anat_dat', 'reg_file'), ('unwarped_mean', 'source_file')]), (brainmask2epi, outputnode, [('transformed_file', 'brain_mask2epi')]) ]) # perform artefact detection artefact = Node(ra.ArtifactDetect(save_plot=True, use_norm=True, parameter_source='FSL', mask_type='file', norm_threshold=1, zintensity_threshold=3, use_differences=[True, False]), name='artefact') artefact.plugin_args = {'submit_specs': 'request_memory = 17000'} denoise.connect([ (inputnode, artefact, [('epi_coreg', 'realigned_files'), ('moco_par', 'realignment_parameters')]), (resample_brain, artefact, [('out_file', 'mask_file')]), (artefact, outputnode, [('norm_files', 'combined_motion'), ('outlier_files', 'outlier_files'), ('intensity_files', 'intensity_files'), ('statistic_files', 'outlier_stats'), ('plot_files', 'outlier_plots')]) ]) # Compute motion regressors motreg = Node(util.Function( input_names=['motion_params', 'order', 'derivatives'], output_names=['out_files'], function=motion_regressors), name='getmotionregress') motreg.plugin_args = {'submit_specs': 'request_memory = 17000'} denoise.connect([(inputnode, motreg, [('moco_par', 'motion_params')])]) # Create a filter to remove motion and art confounds createfilter1 = Node(util.Function( input_names=['motion_params', 'comp_norm', 'outliers', 'detrend_poly'], output_names=['out_files'], function=build_filter1), name='makemotionbasedfilter') createfilter1.inputs.detrend_poly = 2 createfilter1.plugin_args = {'submit_specs': 'request_memory = 17000'} denoise.connect([ (motreg, createfilter1, [('out_files', 'motion_params')]), ( artefact, createfilter1, [ #('norm_files', 'comp_norm'), ('outlier_files', 'outliers') ]), (createfilter1, outputnode, [('out_files', 'mc_regressor')]) ]) # regress out motion and art confounds filter1 = Node(fsl.GLM(out_f_name='F_mcart.nii.gz', out_pf_name='pF_mcart.nii.gz', out_res_name='rest_mc_denoised.nii.gz', demean=True), name='filtermotion') filter1.plugin_args = {'submit_specs': 'request_memory = 17000'} denoise.connect([(inputnode, filter1, [('epi_coreg', 'in_file')]), (createfilter1, filter1, [(('out_files', list_to_filename), 'design')]), (filter1, outputnode, [('out_f', 'mc_F'), ('out_pf', 'mc_pF')])]) # create filter with compcor components createfilter2 = Node(util.Function(input_names=[ 'realigned_file', 'mask_file', 'num_components', 'extra_regressors' ], output_names=['out_files'], function=extract_noise_components), name='makecompcorfilter') createfilter2.inputs.num_components = 6 createfilter2.plugin_args = {'submit_specs': 'request_memory = 17000'} denoise.connect([ (createfilter1, createfilter2, [(('out_files', list_to_filename), 'extra_regressors')]), (filter1, createfilter2, [('out_res', 'realigned_file')]), (wmcsf_mask, createfilter2, [('out_file', 'mask_file')]), (createfilter2, outputnode, [('out_files', 'comp_regressor')]), ]) # regress compcor and other noise components filter2 = Node(fsl.GLM(out_f_name='F_noise.nii.gz', out_pf_name='pF_noise.nii.gz', out_res_name='rest2anat_denoised.nii.gz', demean=True), name='filternoise') filter2.plugin_args = {'submit_specs': 'request_memory = 17000'} denoise.connect([(filter1, filter2, [('out_res', 'in_file')]), (createfilter2, filter2, [('out_files', 'design')]), (resample_brain, filter2, [('out_file', 'mask')]), (filter2, outputnode, [('out_f', 'comp_F'), ('out_pf', 'comp_pF')])]) # bandpass filter denoised file bandpass_filter = Node( fsl.TemporalFilter(out_file='rest_denoised_bandpassed.nii.gz'), name='bandpass_filter') bandpass_filter.plugin_args = {'submit_specs': 'request_memory = 17000'} denoise.connect([(inputnode, bandpass_filter, [('highpass_sigma', 'highpass_sigma'), ('lowpass_sigma', 'lowpass_sigma')]), (filter2, bandpass_filter, [('out_res', 'in_file')])]) # time-normalize scans normalize_time = Node(util.Function(input_names=['in_file', 'tr'], output_names=['out_file'], function=time_normalizer), name='normalize_time') normalize_time.plugin_args = {'submit_specs': 'request_memory = 17000'} denoise.connect([ (inputnode, normalize_time, [('tr', 'tr')]), (bandpass_filter, normalize_time, [('out_file', 'in_file')]), (normalize_time, outputnode, [('out_file', 'normalized_file')]) ]) return denoise
def hmc_afni(name='fMRI_HMC_afni', st_correct=False, despike=False, deoblique=False): """A head motion correction (HMC) workflow for functional scans""" workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface( fields=['in_file', 'fd_radius', 'start_idx', 'stop_idx']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['out_file', 'out_fd']), name='outputnode') drop_trs = pe.Node(afni.Calc(expr='a', outputtype='NIFTI_GZ'), name='drop_trs') reorient = pe.Node(afni.Resample( orientation='RPI', outputtype='NIFTI_GZ'), name='reorient') get_mean_RPI = pe.Node(afni.TStat( options='-mean', outputtype='NIFTI_GZ'), name='get_mean_RPI') # calculate hmc parameters hmc = pe.Node( afni.Volreg(args='-Fourier -twopass', zpad=4, outputtype='NIFTI_GZ'), name='motion_correct') get_mean_motion = get_mean_RPI.clone('get_mean_motion') hmc_A = hmc.clone('motion_correct_A') hmc_A.inputs.md1d_file = 'max_displacement.1D' # Compute the frame-wise displacement calc_fd = pe.Node(niu.Function( function=fd_jenkinson, input_names=['in_file', 'rmax'], output_names=['out_fd']), name='calc_fd') workflow.connect([ (inputnode, drop_trs, [('in_file', 'in_file_a'), ('start_idx', 'start_idx'), ('stop_idx', 'stop_idx')]), (inputnode, calc_fd, [('fd_radius', 'rmax')]), (reorient, get_mean_RPI, [('out_file', 'in_file')]), (reorient, hmc, [('out_file', 'in_file')]), (get_mean_RPI, hmc, [('out_file', 'basefile')]), (hmc, get_mean_motion, [('out_file', 'in_file')]), (reorient, hmc_A, [('out_file', 'in_file')]), (get_mean_motion, hmc_A, [('out_file', 'basefile')]), (hmc_A, outputnode, [('out_file', 'out_file')]), (hmc_A, calc_fd, [('oned_matrix_save', 'in_file')]), (calc_fd, outputnode, [('out_fd', 'out_fd')]), ]) # Slice timing correction, despiking, and deoblique st_corr = pe.Node(afni.TShift(outputtype='NIFTI_GZ'), name='TimeShifts') deoblique_node = pe.Node(afni.Refit(deoblique=True), name='deoblique') despike_node = pe.Node(afni.Despike(outputtype='NIFTI_GZ'), name='despike') if st_correct and despike and deoblique: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, despike_node, [('out_file', 'in_file')]), (despike_node, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, reorient, [('out_file', 'in_file')]) ]) elif st_correct and despike: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, despike_node, [('out_file', 'in_file')]), (despike_node, reorient, [('out_file', 'in_file')]), ]) elif st_correct and deoblique: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, reorient, [('out_file', 'in_file')]) ]) elif st_correct: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, reorient, [('out_file', 'in_file')]) ]) elif despike and deoblique: workflow.connect([ (drop_trs, despike_node, [('out_file', 'in_file')]), (despike_node, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, reorient, [('out_file', 'in_file')]) ]) elif despike: workflow.connect([ (drop_trs, despike_node, [('out_file', 'in_file')]), (despike_node, reorient, [('out_file', 'in_file')]), ]) elif deoblique: workflow.connect([ (drop_trs, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, reorient, [('out_file', 'in_file')]) ]) else: workflow.connect([ (drop_trs, reorient, [('out_file', 'in_file')]), ]) return workflow
def create_transform_pipeline(name='transfrom_timeseries'): # set fsl output type fsl.FSLCommand.set_default_output_type('NIFTI_GZ') # initiate workflow transform_ts = Workflow(name='transform_timeseries') # inputnode inputnode=Node(util.IdentityInterface(fields=['orig_ts', 'anat_head', 'mat_moco', 'fullwarp', 'resolution', 'brain_mask' ]), name='inputnode') # outputnode outputnode=Node(util.IdentityInterface(fields=['trans_ts', 'trans_ts_mean', 'trans_ts_masked', 'resamp_brain', 'brain_mask_resamp', 'out_dvars' ]), name='outputnode') #resample anatomy resample = Node(fsl.FLIRT(datatype='float', out_file='T1_resampled.nii.gz'), name = 'resample_anat') transform_ts.connect([(inputnode, resample, [('anat_head', 'in_file'), ('anat_head', 'reference'), ('resolution', 'apply_isoxfm') ]), (resample, outputnode, [('out_file', 'resamp_brain')]) ]) # split timeseries in single volumes split=Node(fsl.Split(dimension='t', out_base_name='timeseries'), name='split') transform_ts.connect([(inputnode, split, [('orig_ts','in_file')])]) # applymoco premat and fullwarpfield applywarp = MapNode(fsl.ApplyWarp(interp='spline', relwarp=True, out_file='rest2anat.nii.gz', datatype='float'), iterfield=['in_file', 'premat'], name='applywarp') transform_ts.connect([(split, applywarp, [('out_files', 'in_file')]), (inputnode, applywarp, [('mat_moco', 'premat'), ('fullwarp','field_file')]), (resample, applywarp, [('out_file', 'ref_file')]) ]) # re-concatenate volumes merge=Node(fsl.Merge(dimension='t', merged_file='rest2anat.nii.gz'), name='merge') transform_ts.connect([(applywarp,merge,[('out_file','in_files')]), (merge, outputnode, [('merged_file', 'trans_ts')])]) # calculate new mean tmean = Node(fsl.maths.MeanImage(dimension='T', out_file='rest_mean2anat_lowres.nii.gz'), name='tmean') transform_ts.connect([(merge, tmean, [('merged_file', 'in_file')]), (tmean, outputnode, [('out_file', 'trans_ts_mean')]) ]) # resample brain mask resample_brain = Node(afni.Resample(resample_mode='NN', outputtype='NIFTI_GZ', out_file='T1_brain_mask_lowres.nii.gz'), name = 'resample_brain') transform_ts.connect([(inputnode, resample_brain, [('brain_mask', 'in_file')]), (tmean, resample_brain, [('out_file', 'master')]), (resample_brain, outputnode, [('out_file', 'brain_mask_resamp')]) ]) #mask the transformed file mask = Node(fsl.ApplyMask(), name="mask") transform_ts.connect([(resample_brain,mask, [('out_file', 'mask_file')]), (merge, mask, [('merged_file', 'in_file')]), (mask, outputnode, [('out_file', 'trans_ts_masked')]) ]) #calculate DVARS dvars = Node(confounds.ComputeDVARS(save_all=True, save_plot=True), name="dvars") transform_ts.connect([(resample_brain, dvars, [('out_file', 'in_mask')]), (merge, dvars, [('merged_file', 'in_file')]), (dvars, outputnode, [('out_all', 'out_dvars')]) ]) return transform_ts
def init_dsi_studio_recon_wf(omp_nthreads, has_transform, name="dsi_studio_recon", output_suffix="", params={}): """Reconstructs diffusion data using DSI Studio. This workflow creates a ``.src.gz`` file from the input dwi, bvals and bvecs, then reconstructs ODFs using GQI. Inputs *Default qsiprep inputs* Outputs fibgz A DSI Studio fib file containing GQI ODFs, peaks and scalar values. Params ratio_of_mean_diffusion_distance: float Default 1.25. Distance to sample EAP at. """ inputnode = pe.Node(niu.IdentityInterface(fields=input_fields + ['odf_rois']), name="inputnode") outputnode = pe.Node(niu.IdentityInterface(fields=['fibgz']), name="outputnode") workflow = Workflow(name=name) desc = """DSI Studio Reconstruction : """ create_src = pe.Node(DSIStudioCreateSrc(), name="create_src") romdd = params.get("ratio_of_mean_diffusion_distance", 1.25) gqi_recon = pe.Node( DSIStudioGQIReconstruction(ratio_of_mean_diffusion_distance=romdd), name="gqi_recon") desc += """\ Diffusion orientation distribution functions (ODFs) were reconstructed using generalized q-sampling imaging (GQI, @yeh2010gqi) with a ratio of mean diffusion distance of %02f.""" % romdd # Resample anat mask resample_mask = pe.Node(afni.Resample(outputtype='NIFTI_GZ', resample_mode="NN"), name='resample_mask') # Make a visual report of the model plot_peaks = pe.Node(ReconPeaksReport(subtract_iso=True), name='plot_peaks') ds_report_peaks = pe.Node(ReconDerivativesDataSink(extension='.png', desc="GQIODF", suffix='peaks'), name='ds_report_peaks', run_without_submitting=True) # Plot targeted regions if has_transform: ds_report_odfs = pe.Node(ReconDerivativesDataSink(extension='.png', desc="GQIODF", suffix='odfs'), name='ds_report_odfs', run_without_submitting=True) workflow.connect(plot_peaks, 'odf_report', ds_report_odfs, 'in_file') workflow.connect([ (inputnode, create_src, [('dwi_file', 'input_nifti_file'), ('bval_file', 'input_bvals_file'), ('bvec_file', 'input_bvecs_file')]), (inputnode, resample_mask, [('t1_brain_mask', 'in_file'), ('dwi_file', 'master')]), (create_src, gqi_recon, [('output_src', 'input_src_file')]), (resample_mask, gqi_recon, [('out_file', 'mask')]), (gqi_recon, outputnode, [('output_fib', 'fibgz')]), (gqi_recon, plot_peaks, [('output_fib', 'fib_file')]), (inputnode, plot_peaks, [('dwi_ref', 'background_image'), ('odf_rois', 'odf_rois')]), (resample_mask, plot_peaks, [('out_file', 'mask_file')]), (plot_peaks, ds_report_peaks, [('out_report', 'in_file')]) ]) if output_suffix: # Save the output in the outputs directory ds_gqi_fibgz = pe.Node(ReconDerivativesDataSink(extension='.fib.gz', suffix=output_suffix, compress=True), name='ds_gqi_fibgz', run_without_submitting=True) workflow.connect(gqi_recon, 'output_fib', ds_gqi_fibgz, 'in_file') workflow.__desc__ = desc return workflow
def _func_to_template(func_coreg_filename, template_filename, write_dir, func_to_anat_oned_filename, anat_to_template_oned_filename, anat_to_template_warp_filename, voxel_size=None, caching=False, verbose=True): """ Applies successive transforms to coregistered functional to put it in template space. Parameters ---------- coreg_func_filename : str Path to functional volume, coregistered to a common space with the anatomical volume. template_filename : str Template to register the functional to. func_to_anat_oned_filename : str Path to the affine 1D transform from functional to coregistration space. anat_to_template_oned_filename : str Path to the affine 1D transform from anatomical to template space. anat_to_template_warp_filename : str Path to the warp transform from anatomical to template space. voxel_size : 3-tuple of floats, optional Voxel size of the registered functional, in mm. caching : bool, optional Wether or not to use caching. verbose : bool, optional If True, all steps are verbose. Note that caching implies some verbosity in any case. """ environ = {} if verbose: terminal_output = 'allatonce' else: terminal_output = 'none' if caching: memory = Memory(write_dir) resample = memory.cache(afni.Resample) catmatvec = memory.cache(afni.CatMatvec) allineate = memory.cache(afni.Allineate) warp_apply = memory.cache(afni.NwarpApply) for step in [resample, allineate, warp_apply]: step.interface().set_default_terminal_output(terminal_output) else: resample = afni.Resample(terminal_output=terminal_output).run catmatvec = afni.CatMatvec().run allineate = afni.Allineate(terminal_output=terminal_output).run warp_apply = afni.NwarpApply(terminal_output=terminal_output).run environ['AFNI_DECONFLICT'] = 'OVERWRITE' current_dir = os.getcwd() os.chdir(write_dir) # XXX to remove normalized_filename = fname_presuffix(func_coreg_filename, suffix='_normalized') if voxel_size is None: func_template_filename = template_filename else: out_resample = resample(in_file=template_filename, voxel_size=voxel_size, outputtype='NIFTI_GZ', environ=environ) func_template_filename = out_resample.outputs.out_file if anat_to_template_warp_filename is None: affine_transform_filename = fname_presuffix(func_to_anat_oned_filename, suffix='_to_template') _ = catmatvec(in_file=[(anat_to_template_oned_filename, 'ONELINE'), (func_to_anat_oned_filename, 'ONELINE')], oneline=True, out_file=affine_transform_filename, environ=environ) _ = allineate(in_file=func_coreg_filename, master=func_template_filename, in_matrix=affine_transform_filename, out_file=normalized_filename, environ=environ) else: warp = "'{0} {1} {2}'".format(anat_to_template_warp_filename, anat_to_template_oned_filename, func_to_anat_oned_filename) _ = warp_apply(in_file=func_coreg_filename, master=func_template_filename, warp=warp, out_file=normalized_filename, environ=environ) os.chdir(current_dir) return normalized_filename
def coregister_fmri_session(session_data, t_r, write_dir, brain_volume, use_rats_tool=True, slice_timing=True, prior_rigid_body_registration=False, caching=False, voxel_size_x=.1, voxel_size_y=.1, verbose=True, **environ_kwargs): """ Coregistration of the subject's functional and anatomical images. The functional volume is aligned to the anatomical, first with a rigid body registration and then on a per-slice basis (only a fine correction, this is mostly for correction of EPI distortion). Parameters ---------- session_data : sammba.registration.SessionData Single animal data, giving paths to its functional and anatomical image, as well as it identifier. t_r : float Repetition time for the EPI, in seconds. write_dir : str Directory to save the output and temporary images. brain_volume : int Volume of the brain in mm3 used for brain extraction. Typically 400 for mouse and 1800 for rat. use_rats_tool : bool, optional If True, brain mask is computed using RATS Mathematical Morphology. Otherwise, a histogram-based brain segmentation is used. prior_rigid_body_registration : bool, optional If True, a rigid-body registration of the anat to the func is performed prior to the warp. Useful if the images headers have missing/wrong information. voxel_size_x : float, optional Resampling resolution for the x-axis, in mm. voxel_size_y : float, optional Resampling resolution for the y-axis, in mm. caching : bool, optional Wether or not to use caching. verbose : bool, optional If True, all steps are verbose. Note that caching implies some verbosity in any case. environ_kwargs : extra arguments keywords Extra arguments keywords, passed to interfaces environ variable. Returns ------- the same sequence with each animal_data updated: the following attributes are added - `output_dir_` : str Path to the output directory. - `coreg_func_` : str Path to paths to the coregistered functional image. - `coreg_anat_` : str Path to paths to the coregistered functional image. - `coreg_transform_` : str Path to the transform from anat to func. Notes ----- If `use_rats_tool` is turned on, RATS tool is used for brain extraction and has to be cited. For more information, see `RATS <http://www.iibi.uiowa.edu/content/rats-overview/>`_ """ func_filename = session_data.func anat_filename = session_data.anat environ = {'AFNI_DECONFLICT': 'OVERWRITE'} for (key, value) in environ_kwargs.items(): environ[key] = value if verbose: terminal_output = 'allatonce' else: terminal_output = 'none' if use_rats_tool: if segmentation.interfaces.Info().version() is None: raise ValueError('Can not locate RATS') else: ComputeMask = segmentation.MathMorphoMask else: ComputeMask = segmentation.HistogramMask if ants.base.Info().version is None: raise ValueError('Can not locate ANTS') if caching: memory = Memory(write_dir) tshift = memory.cache(afni.TShift) clip_level = memory.cache(afni.ClipLevel) volreg = memory.cache(afni.Volreg) allineate = memory.cache(afni.Allineate) tstat = memory.cache(afni.TStat) compute_mask = memory.cache(ComputeMask) calc = memory.cache(afni.Calc) allineate = memory.cache(afni.Allineate) allineate2 = memory.cache(afni.Allineate) unifize = memory.cache(afni.Unifize) bias_correct = memory.cache(ants.N4BiasFieldCorrection) catmatvec = memory.cache(afni.CatMatvec) warp = memory.cache(afni.Warp) resample = memory.cache(afni.Resample) slicer = memory.cache(afni.ZCutUp) warp_apply = memory.cache(afni.NwarpApply) qwarp = memory.cache(afni.Qwarp) merge = memory.cache(afni.Zcat) copy_geom = memory.cache(fsl.CopyGeom) overwrite = False for step in [ tshift, volreg, allineate, allineate2, tstat, compute_mask, calc, unifize, resample, slicer, warp_apply, qwarp, merge ]: step.interface().set_default_terminal_output(terminal_output) else: tshift = afni.TShift(terminal_output=terminal_output).run clip_level = afni.ClipLevel().run volreg = afni.Volreg(terminal_output=terminal_output).run allineate = afni.Allineate(terminal_output=terminal_output).run allineate2 = afni.Allineate(terminal_output=terminal_output ).run # TODO: remove after fixed bug tstat = afni.TStat(terminal_output=terminal_output).run compute_mask = ComputeMask().run calc = afni.Calc(terminal_output=terminal_output).run unifize = afni.Unifize(terminal_output=terminal_output).run bias_correct = ants.N4BiasFieldCorrection( terminal_output=terminal_output).run catmatvec = afni.CatMatvec().run warp = afni.Warp().run resample = afni.Resample(terminal_output=terminal_output).run slicer = afni.ZCutUp(terminal_output=terminal_output).run warp_apply = afni.NwarpApply(terminal_output=terminal_output).run qwarp = afni.Qwarp(terminal_output=terminal_output).run merge = afni.Zcat(terminal_output=terminal_output).run copy_geom = fsl.CopyGeom(terminal_output=terminal_output).run overwrite = True session_data._check_inputs() output_dir = os.path.join(os.path.abspath(write_dir), session_data.animal_id) session_data._set_output_dir_(output_dir) current_dir = os.getcwd() os.chdir(output_dir) output_files = [] ####################################### # Correct functional for slice timing # ####################################### if slice_timing: out_tshift = tshift(in_file=func_filename, outputtype='NIFTI_GZ', tpattern='altplus', tr=str(t_r), environ=environ) func_filename = out_tshift.outputs.out_file output_files.append(func_filename) ################################################ # Register functional volumes to the first one # ################################################ # XXX why do you need a thresholded image ? out_clip_level = clip_level(in_file=func_filename) out_calc_threshold = calc(in_file_a=func_filename, expr='ispositive(a-{0}) * a'.format( out_clip_level.outputs.clip_val), outputtype='NIFTI_GZ') thresholded_filename = out_calc_threshold.outputs.out_file out_volreg = volreg( # XXX dfile not saved in_file=thresholded_filename, outputtype='NIFTI_GZ', environ=environ, oned_file=fname_presuffix(thresholded_filename, suffix='Vr.1Dfile.1D', use_ext=False), oned_matrix_save=fname_presuffix(thresholded_filename, suffix='Vr.aff12.1D', use_ext=False)) # Apply the registration to the whole head out_allineate = allineate(in_file=func_filename, master=func_filename, in_matrix=out_volreg.outputs.oned_matrix_save, out_file=fname_presuffix(func_filename, suffix='Av'), environ=environ) # 3dAllineate removes the obliquity. This is not a good way to readd it as # removes motion correction info in the header if it were an AFNI file...as # it happens it's NIfTI which does not store that so irrelevant! out_copy_geom = copy_geom(dest_file=out_allineate.outputs.out_file, in_file=out_volreg.outputs.out_file) allineated_filename = out_copy_geom.outputs.out_file # Create a (hopefully) nice mean image for use in the registration out_tstat = tstat(in_file=allineated_filename, args='-mean', outputtype='NIFTI_GZ', environ=environ) # Update outputs output_files.extend([ thresholded_filename, out_volreg.outputs.oned_matrix_save, out_volreg.outputs.out_file, out_volreg.outputs.md1d_file, allineated_filename, out_tstat.outputs.out_file ]) ########################################### # Corret anat and func for intensity bias # ########################################### # Correct the functional average for intensities bias out_bias_correct = bias_correct(input_image=out_tstat.outputs.out_file) unbiased_func_filename = out_bias_correct.outputs.output_image # Bias correct the antomical image out_unifize = unifize(in_file=anat_filename, outputtype='NIFTI_GZ', environ=environ) unbiased_anat_filename = out_unifize.outputs.out_file # Update outputs output_files.extend([unbiased_func_filename, unbiased_anat_filename]) ############################################# # Rigid-body registration anat -> mean func # ############################################# if prior_rigid_body_registration: # Mask the mean functional volume outside the brain. out_clip_level = clip_level(in_file=unbiased_func_filename) out_compute_mask_func = compute_mask( in_file=unbiased_func_filename, volume_threshold=brain_volume, intensity_threshold=int(out_clip_level.outputs.clip_val)) out_cacl_func = calc(in_file_a=unbiased_func_filename, in_file_b=out_compute_mask_func.outputs.out_file, expr='a*b', outputtype='NIFTI_GZ', environ=environ) # Mask the anatomical volume outside the brain. out_clip_level = clip_level(in_file=unbiased_anat_filename) out_compute_mask_anat = compute_mask( in_file=unbiased_anat_filename, volume_threshold=brain_volume, intensity_threshold=int(out_clip_level.outputs.clip_val)) out_cacl_anat = calc(in_file_a=unbiased_anat_filename, in_file_b=out_compute_mask_anat.outputs.out_file, expr='a*b', outputtype='NIFTI_GZ', environ=environ) # Compute the transformation from functional to anatomical brain # XXX: why in this sense out_allineate = allineate2( in_file=out_cacl_func.outputs.out_file, reference=out_cacl_anat.outputs.out_file, out_matrix=fname_presuffix(out_cacl_func.outputs.out_file, suffix='_shr.aff12.1D', use_ext=False), center_of_mass='', warp_type='shift_rotate', out_file=fname_presuffix(out_cacl_func.outputs.out_file, suffix='_shr'), environ=environ) rigid_transform_file = out_allineate.outputs.out_matrix output_files.extend([ out_compute_mask_func.outputs.out_file, out_cacl_func.outputs.out_file, out_compute_mask_anat.outputs.out_file, out_cacl_anat.outputs.out_file, rigid_transform_file, out_allineate.outputs.out_file ]) # apply the inverse transform to register the anatomical to the func catmatvec_out_file = fname_presuffix(rigid_transform_file, suffix='INV') out_catmatvec = catmatvec(in_file=[(rigid_transform_file, 'I')], oneline=True, out_file=catmatvec_out_file) output_files.append(out_catmatvec.outputs.out_file) out_allineate = allineate(in_file=unbiased_anat_filename, master=unbiased_func_filename, in_matrix=out_catmatvec.outputs.out_file, out_file=fname_presuffix( unbiased_anat_filename, suffix='_shr_in_func_space'), environ=environ) allineated_anat_filename = out_allineate.outputs.out_file output_files.append(allineated_anat_filename) else: allineated_anat_filename = unbiased_anat_filename ############################################ # Nonlinear registration anat -> mean func # ############################################ # 3dWarp doesn't put the obliquity in the header, so do it manually # This step generates one file per slice and per time point, so we are # making sure they are removed at the end out_warp = warp(in_file=allineated_anat_filename, oblique_parent=unbiased_func_filename, interp='quintic', gridset=unbiased_func_filename, outputtype='NIFTI_GZ', verbose=True, environ=environ) registered_anat_filename = out_warp.outputs.out_file registered_anat_oblique_filename = fix_obliquity(registered_anat_filename, unbiased_func_filename, verbose=verbose) # Concatenate all the anat to func tranforms mat_filename = fname_presuffix(registered_anat_filename, suffix='_warp.mat', use_ext=False) # XXX Handle this correctly according to caching if not os.path.isfile(mat_filename): np.savetxt(mat_filename, [out_warp.runtime.stdout], fmt='%s') output_files.append(mat_filename) transform_filename = fname_presuffix(registered_anat_filename, suffix='_anat_to_func.aff12.1D', use_ext=False) if prior_rigid_body_registration: _ = catmatvec(in_file=[(mat_filename, 'ONELINE'), (rigid_transform_file, 'ONELINE')], oneline=True, out_file=transform_filename) else: _ = catmatvec(in_file=[(mat_filename, 'ONELINE')], oneline=True, out_file=transform_filename) ################################################## # Per-slice non-linear registration func -> anat # ################################################## # Slice anatomical image anat_img = nibabel.load(registered_anat_oblique_filename) anat_n_slices = anat_img.header.get_data_shape()[2] sliced_registered_anat_filenames = [] for slice_n in range(anat_n_slices): out_slicer = slicer(in_file=registered_anat_oblique_filename, keep='{0} {0}'.format(slice_n), out_file=fname_presuffix( registered_anat_oblique_filename, suffix='Sl%d' % slice_n), environ=environ) oblique_slice = fix_obliquity(out_slicer.outputs.out_file, registered_anat_oblique_filename, verbose=verbose) sliced_registered_anat_filenames.append(oblique_slice) # Slice mean functional sliced_bias_corrected_filenames = [] img = nibabel.load(func_filename) n_slices = img.header.get_data_shape()[2] for slice_n in range(n_slices): out_slicer = slicer(in_file=unbiased_func_filename, keep='{0} {0}'.format(slice_n), out_file=fname_presuffix(unbiased_func_filename, suffix='Sl%d' % slice_n), environ=environ) oblique_slice = fix_obliquity(out_slicer.outputs.out_file, unbiased_func_filename, verbose=verbose) sliced_bias_corrected_filenames.append(oblique_slice) # Below line is to deal with slices where there is no signal (for example # rostral end of some anatomicals) # The inverse warp frequently fails, Resampling can help it work better # XXX why specifically .1 in voxel_size ? voxel_size_z = anat_img.header.get_zooms()[2] resampled_registered_anat_filenames = [] for sliced_registered_anat_filename in sliced_registered_anat_filenames: out_resample = resample(in_file=sliced_registered_anat_filename, voxel_size=(voxel_size_x, voxel_size_y, voxel_size_z), outputtype='NIFTI_GZ', environ=environ) resampled_registered_anat_filenames.append( out_resample.outputs.out_file) resampled_bias_corrected_filenames = [] for sliced_bias_corrected_filename in sliced_bias_corrected_filenames: out_resample = resample(in_file=sliced_bias_corrected_filename, voxel_size=(voxel_size_x, voxel_size_y, voxel_size_z), outputtype='NIFTI_GZ', environ=environ) resampled_bias_corrected_filenames.append( out_resample.outputs.out_file) # single slice non-linear functional to anatomical registration warped_slices = [] warp_filenames = [] for (resampled_bias_corrected_filename, resampled_registered_anat_filename) in zip( resampled_bias_corrected_filenames, resampled_registered_anat_filenames): warped_slice = fname_presuffix(resampled_bias_corrected_filename, suffix='_qw') out_qwarp = qwarp( in_file=resampled_bias_corrected_filename, base_file=resampled_registered_anat_filename, iwarp=True, # XXX: is this necessary noneg=True, blur=[0], nmi=True, noXdis=True, allineate=True, allineate_opts='-parfix 1 0 -parfix 2 0 -parfix 3 0 ' '-parfix 4 0 -parfix 5 0 -parfix 6 0 ' '-parfix 7 0 -parfix 9 0 ' '-parfix 10 0 -parfix 12 0', out_file=warped_slice, environ=environ) warped_slices.append(out_qwarp.outputs.warped_source) warp_filenames.append(out_qwarp.outputs.source_warp) output_files.append(out_qwarp.outputs.base_warp) # There are files geenrated by the allineate option output_files.extend([ fname_presuffix(out_qwarp.outputs.warped_source, suffix='_Allin'), fname_presuffix(out_qwarp.outputs.warped_source, suffix='_Allin.nii', use_ext=False), fname_presuffix(out_qwarp.outputs.warped_source, suffix='_Allin.aff12.1D', use_ext=False) ]) # Resample the mean volume back to the initial resolution, voxel_size = nibabel.load(unbiased_func_filename).header.get_zooms() resampled_warped_slices = [] for warped_slice in warped_slices: out_resample = resample(in_file=warped_slice, voxel_size=voxel_size, outputtype='NIFTI_GZ', environ=environ) resampled_warped_slices.append(out_resample.outputs.out_file) # fix the obliquity resampled_warped_slices_oblique = [] for (sliced_registered_anat_filename, resampled_warped_slice) in zip(sliced_registered_anat_filenames, resampled_warped_slices): oblique_slice = fix_obliquity(resampled_warped_slice, sliced_registered_anat_filename, verbose=verbose) resampled_warped_slices_oblique.append(oblique_slice) # slice functional sliced_func_filenames = [] for slice_n in range(n_slices): out_slicer = slicer(in_file=allineated_filename, keep='{0} {0}'.format(slice_n), out_file=fname_presuffix(allineated_filename, suffix='Sl%d' % slice_n), environ=environ) oblique_slice = fix_obliquity(out_slicer.outputs.out_file, allineated_filename, verbose=verbose) sliced_func_filenames.append(oblique_slice) # Apply the precomputed warp slice by slice warped_func_slices = [] for (sliced_func_filename, warp_filename) in zip(sliced_func_filenames, warp_filenames): out_warp_apply = warp_apply(in_file=sliced_func_filename, master=sliced_func_filename, warp=warp_filename, out_file=fname_presuffix( sliced_func_filename, suffix='_qw'), environ=environ) warped_func_slices.append(out_warp_apply.outputs.out_file) # Finally, merge all slices ! out_merge_func = merge(in_files=warped_func_slices, outputtype='NIFTI_GZ', environ=environ) # Fix the obliquity merged_oblique = fix_obliquity(out_merge_func.outputs.out_file, allineated_filename, verbose=verbose) # Update the fmri data setattr(session_data, "coreg_func_", merged_oblique) setattr(session_data, "coreg_anat_", registered_anat_oblique_filename) setattr(session_data, "coreg_transform_", transform_filename) os.chdir(current_dir) # Collect the outputs output_files.extend(sliced_registered_anat_filenames + sliced_bias_corrected_filenames + resampled_registered_anat_filenames + resampled_bias_corrected_filenames + warped_slices + warp_filenames + resampled_warped_slices_oblique + sliced_func_filenames + warped_func_slices) if not caching: for out_file in output_files: if os.path.isfile(out_file): os.remove(out_file)
def create_lesion_preproc(wf_name='lesion_preproc'): """ The main purpose of this workflow is to process lesions masks. Lesion mask file is deobliqued and reoriented in the same way as the T1 in the anat_preproc function. Returns ------- lesion_preproc : workflow Lesion preprocessing Workflow Workflow Inputs:: inputspec.lesion : string User input lesion mask, in any of the 8 orientations Workflow Outputs:: outputspec.refit : string Path to deobliqued anatomical image outputspec.reorient : string Path to RPI oriented anatomical image Order of commands: - Deobliqing the scans. :: 3drefit -deoblique mprage.nii.gz - Re-orienting the Image into Right-to-Left Posterior-to-Anterior Inferior-to-Superior (RPI) orientation :: 3dresample -orient RPI -prefix mprage_RPI.nii.gz -inset mprage.nii.gz Examples -------- >>> from CPAC.anat_preproc.lesion_preproc import create_lesion_preproc >>> preproc = create_lesion_preproc() >>> preproc.inputs.inputspec.lesion = 'sub1/anat/lesion-mask.nii.gz' >>> preproc.run() #doctest: +SKIP """ preproc = pe.Workflow(name=wf_name) inputnode = pe.Node(util.IdentityInterface(fields=['lesion']), name='inputspec') outputnode = pe.Node(util.IdentityInterface(fields=['refit', 'reorient']), name='outputspec') lesion_deoblique = pe.Node(interface=afni.Refit(), name='lesion_deoblique') lesion_deoblique.inputs.deoblique = True lesion_inverted = pe.Node(interface=util.Function( input_names=['lesion_path'], output_names=['lesion_out'], function=inverse_lesion), name='inverse_lesion') # We first check and invert the lesion if needed to be used by ANTs preproc.connect(inputnode, 'lesion', lesion_inverted, 'lesion_path') preproc.connect(lesion_inverted, 'lesion_out', lesion_deoblique, 'in_file') preproc.connect(lesion_deoblique, 'out_file', outputnode, 'refit') # Anatomical reorientation lesion_reorient = pe.Node(interface=afni.Resample(), name='lesion_reorient') lesion_reorient.inputs.orientation = 'RPI' lesion_reorient.inputs.outputtype = 'NIFTI_GZ' preproc.connect(lesion_deoblique, 'out_file', lesion_reorient, 'in_file') preproc.connect(lesion_reorient, 'out_file', outputnode, 'reorient') return preproc
# TODO_ready: erode compcor noise mask!!!! erode_mask = pe.MapNode(fsl.ErodeImage(), iterfield=['in_file'], name="erode_compcor_mask") def pickindex(vec, i): return [x[i] for x in vec] myfuncproc = funcproc.FuncProc() #create atlas matching this space resample_atlas = pe.Node( interface=afni.Resample( outputtype='NIFTI_GZ', in_file="/Users/tspisak/data/atlases/MIST/Parcellations/MIST_7.nii.gz", master=globals._FSLDIR_ + '/data/standard/MNI152_T1_3mm_brain.nii.gz'), name='resample_atlas') #default interpolation is nearest neighbour # standardize what you need myfunc2mni = transform.func2mni(stdreg=_regtype_, carpet_plot="1_original", wf_name="func2mni_1") myfunc2mni_cc = transform.func2mni(stdreg=_regtype_, carpet_plot="2_cc", wf_name="func2mni_2_cc") myfunc2mni_cc_bpf = transform.func2mni(stdreg=_regtype_, carpet_plot="3_cc_bpf", wf_name="func2mni_3_cc_bpf") myfunc2mni_cc_bpf_cens = transform.func2mni(stdreg=_regtype_, carpet_plot="4_cc_bpf_cens",
def create_denoise_pipeline(name='denoise'): # workflow denoise = Workflow(name='denoise') # Define nodes inputnode = Node(interface=util.IdentityInterface(fields=['brain_mask', 'epi_coreg', 'wmseg', 'csfseg', 'highpass_freq', 'tr']), name='inputnode') outputnode = Node(interface=util.IdentityInterface(fields=['wmcsf_mask', 'combined_motion', 'comp_regressor', 'comp_F', 'comp_pF', 'out_betas', 'ts_fullspectrum', 'ts_filtered']), name='outputnode') # combine tissue classes to noise mask wmcsf_mask = Node(fsl.BinaryMaths(operation='add', out_file='wmcsf_mask.nii'), name='wmcsf_mask') denoise.connect([(inputnode, wmcsf_mask, [('wmseg', 'in_file'), ('csfseg', 'operand_file')])]) #resample + binarize wm_csf mask to epi resolution. resample_wmcsf= Node(afni.Resample(resample_mode='NN', outputtype='NIFTI_GZ', out_file='wmcsf_mask_lowres.nii.gz'), name = 'resample_wmcsf') bin_wmcsf_mask=Node(fsl.utils.ImageMaths(), name="bin_wmcsf_mask") bin_wmcsf_mask.inputs.op_string='-nan -thr 0.99 -ero -bin' denoise.connect([(wmcsf_mask, resample_wmcsf, [('out_file', 'in_file')]), (inputnode, resample_wmcsf, [('brain_mask', 'master')]), (resample_wmcsf, bin_wmcsf_mask,[('out_file', 'in_file')]), (bin_wmcsf_mask, outputnode, [('out_file', 'wmcsf_mask')]) ]) #no other denoising filters created here because AROMA performs already well. compcor=Node(conf.ACompCor(), name="compcor") compcor.inputs.num_components=5 #https://www.sciencedirect.com/science/article/pii/S105381191400175X?via%3Dihub denoise.connect([ (inputnode, compcor, [('epi_coreg', 'realigned_file')]), (bin_wmcsf_mask, compcor, [('out_file', 'mask_files')]), ]) def create_designs(compcor_regressors,epi_coreg,mask): import numpy as np import pandas as pd import os from nilearn.input_data import NiftiMasker brain_masker = NiftiMasker(mask_img = mask, smoothing_fwhm=None, standardize=False, memory='nilearn_cache', memory_level=5, verbose=2) whole_brain = brain_masker.fit_transform(epi_coreg) avg_signal = np.mean(whole_brain,axis=1) all_regressors=pd.read_csv(compcor_regressors,sep='\t') #add global signal. all_regressors['global_signal']=avg_signal fn=os.getcwd()+'/all_regressors.txt' all_regressors.to_csv(fn, sep='\t', index=False) return [fn, compcor_regressors] #create a list of design to loop over. create_design = Node(util.Function(input_names=['compcor_regressors','epi_coreg','mask'], output_names=['reg_list'], function=create_designs), name='create_design') denoise.connect([ (compcor, create_design, [('components_file', 'compcor_regressors')]), (inputnode, create_design, [('epi_coreg', 'epi_coreg')]), (inputnode, create_design, [('brain_mask', 'mask')]) ]) # regress compcor and other noise components filter2 = MapNode(fsl.GLM(out_f_name='F_noise.nii.gz', out_pf_name='pF_noise.nii.gz', out_res_name='rest2anat_denoised.nii.gz', output_type='NIFTI_GZ', demean=True), iterfield=['design'], name='filternoise') filter2.plugin_args = {'submit_specs': 'request_memory = 17000'} denoise.connect([(inputnode, filter2, [('epi_coreg', 'in_file')]), #(createfilter2, filter2, [('out_files', 'design')]), #(compcor, filter2, [('components_file', 'design')]), (create_design, filter2, [('reg_list', 'design')]), (inputnode, filter2, [('brain_mask', 'mask')]), (filter2, outputnode, [('out_f', 'comp_F'), ('out_pf', 'comp_pF'), ('out_file', 'out_betas'), ('out_res', 'ts_fullspectrum'), ]) ]) def calc_sigma(TR,highpass): # https://www.jiscmail.ac.uk/cgi-bin/webadmin?A2=ind1205&L=FSL&P=R57592&1=FSL&9=A&I=-3&J=on&d=No+Match%3BMatch%3BMatches&z=4 sigma=1. / (2 * TR * highpass) return sigma calc_s=Node(util.Function(input_names=['TR', 'highpass'], output_names=['sigma'], function=calc_sigma), name='calc_s') denoise.connect(inputnode, 'tr', calc_s, 'TR') denoise.connect(inputnode, 'highpass_freq', calc_s, 'highpass') #use only highpass filter (because high-frequency content is already somewhat filtered in AROMA)) highpass_filter = MapNode(fsl.TemporalFilter(out_file='rest_denoised_highpassed.nii'), name='highpass_filter', iterfield=['in_file']) highpass_filter.plugin_args = {'submit_specs': 'request_memory = 17000'} denoise.connect([(calc_s, highpass_filter, [('sigma', 'highpass_sigma')]), (filter2, highpass_filter, [('out_res', 'in_file')]), (highpass_filter, outputnode, [('out_file', 'ts_filtered')]) ]) return denoise
def init_dipy_mapmri_recon_wf(name="dipy_mapmri_recon", output_suffix="", params={}): """Reconstruct EAPs, ODFs, using 3dSHORE (brainsuite-style basis set). Inputs *qsiprep outputs* Outputs shore_coeffs 3dSHORE coefficients rtop Voxelwise Return-to-origin probability. rtap Voxelwise Return-to-axis probability. rtpp Voxelwise Return-to-plane probability. msd Voxelwise MSD qiv q-space inverse variance lapnorm Voxelwise norm of the Laplacian Params write_fibgz: bool True writes out a DSI Studio fib file write_mif: bool True writes out a MRTrix mif file with sh coefficients radial_order: int An even integer that represent the order of the basis laplacian_regularization: bool Regularize using the Laplacian of the MAP-MRI basis. laplacian_weighting: str or scalar The string 'GCV' makes it use generalized cross-validation to find the regularization weight. A scalar sets the regularization weight to that value and an array will make it selected the optimal weight from the values in the array. positivity_constraint: bool Constrain the propagator to be positive. pos_grid: int Grid points for estimating EAP(default=15) pos_radius Radius for EAP estimation (default=20e-03) or "adaptive" anisotropic_scaling : bool, If True, uses the standard anisotropic MAP-MRI basis. If False, uses the isotropic MAP-MRI basis (equal to 3D-SHORE). eigenvalue_threshold : float, Sets the minimum of the tensor eigenvalues in order to avoid stability problem. bval_threshold : float, Sets the b-value threshold to be used in the scale factor estimation. In order for the estimated non-Gaussianity to have meaning this value should set to a lower value (b<2000 s/mm^2) such that the scale factors are estimated on signal points that reasonably represent the spins at Gaussian diffusion. dti_scale_estimation : bool, Whether or not DTI fitting is used to estimate the isotropic scale factor for isotropic MAP-MRI. When set to False the algorithm presets the isotropic tissue diffusivity to static_diffusivity. This vastly increases fitting speed but at the cost of slightly reduced fitting quality. Can still be used in combination with regularization and constraints. static_diffusivity : float, the tissue diffusivity that is used when dti_scale_estimation is set to False. The default is that of typical white matter D=0.7e-3 _[5]. cvxpy_solver : str, optional cvxpy solver name. Optionally optimize the positivity constraint with a particular cvxpy solver. See http://www.cvxpy.org/ for details. Default: None (cvxpy chooses its own solver) """ inputnode = pe.Node(niu.IdentityInterface(fields=input_fields), name="inputnode") outputnode = pe.Node(niu.IdentityInterface(fields=[ 'mapmri_coeffs', 'rtop', 'rtap', 'rtpp', 'fibgz', 'fod_sh_mif', 'parng', 'perng', 'ng', 'qiv', 'lapnorm', 'msd' ]), name="outputnode") workflow = pe.Workflow(name=name) recon_map = pe.Node(MAPMRIReconstruction(**params), name="recon_map") resample_mask = pe.Node(afni.Resample(outputtype='NIFTI_GZ', resample_mode="NN"), name='resample_mask') workflow.connect([(inputnode, recon_map, [('dwi_file', 'dwi_file'), ('bval_file', 'bval_file'), ('bvec_file', 'bvec_file')]), (inputnode, resample_mask, [('t1_brain_mask', 'in_file'), ('dwi_file', 'master')]), (resample_mask, recon_map, [('out_file', 'mask_file')]), (recon_map, outputnode, [('mapmri_coeffs', 'mapmri_coeffs'), ('rtop', 'rtop'), ('rtap', 'rtap'), ('rtpp', 'rtpp'), ('parng', 'parng'), ('perng', 'perng'), ('msd', 'msd'), ('ng', 'ng'), ('qiv', 'qiv'), ('lapnorm', 'lapnorm'), ('fibgz', 'fibgz'), ('fod_sh_mif', 'fod_sh_mif')])]) if output_suffix: external_format_datasinks(output_suffix, params, workflow) connections = [] for scalar_name in ['rtop', 'rtap', 'rtpp', 'qiv', 'msd', 'lapnorm']: connections += [ (outputnode, pe.Node(ReconDerivativesDataSink(desc=scalar_name, suffix=output_suffix), name='ds_%s_%s' % (name, scalar_name)), [(scalar_name, 'in_file')]) ] workflow.connect(connections) return workflow
def create_qc_carpet(wf_name='qc_carpet', output_image='qc_carpet'): wf = pe.Workflow(name=wf_name) input_node = pe.Node(util.IdentityInterface(fields=[ 'functional_to_standard', 'mean_functional_to_standard', 'anatomical_gm_mask', 'anatomical_wm_mask', 'anatomical_csf_mask' ]), name='inputspec') output_node = pe.Node(util.IdentityInterface(fields=['carpet_plot']), name='outputspec') gm_resample = pe.Node(afni.Resample(), name='gm_resample') gm_resample.inputs.outputtype = 'NIFTI' wf.connect(input_node, 'anatomical_gm_mask', gm_resample, 'in_file') wf.connect(input_node, 'mean_functional_to_standard', gm_resample, 'master') gm_mask = pe.Node(afni.Calc(), name="gm_mask") gm_mask.inputs.expr = 'astep(a, 0.5)' gm_mask.inputs.outputtype = 'NIFTI' wf.connect(gm_resample, 'out_file', gm_mask, 'in_file_a') wm_resample = pe.Node(afni.Resample(), name='wm_resample') wm_resample.inputs.outputtype = 'NIFTI' wf.connect(input_node, 'anatomical_wm_mask', wm_resample, 'in_file') wf.connect(input_node, 'mean_functional_to_standard', wm_resample, 'master') wm_mask = pe.Node(afni.Calc(), name="wm_mask") wm_mask.inputs.expr = 'astep(a, 0.5)' wm_mask.inputs.outputtype = 'NIFTI' wf.connect(wm_resample, 'out_file', wm_mask, 'in_file_a') csf_resample = pe.Node(afni.Resample(), name='csf_resample') csf_resample.inputs.outputtype = 'NIFTI' wf.connect(input_node, 'anatomical_csf_mask', csf_resample, 'in_file') wf.connect(input_node, 'mean_functional_to_standard', csf_resample, 'master') csf_mask = pe.Node(afni.Calc(), name="csf_mask") csf_mask.inputs.expr = 'astep(a, 0.5)' csf_mask.inputs.outputtype = 'NIFTI' wf.connect(csf_resample, 'out_file', csf_mask, 'in_file_a') carpet_plot = pe.Node(Function(input_names=[ 'gm_mask', 'wm_mask', 'csf_mask', 'functional_to_standard', 'output' ], output_names=['carpet_plot'], function=gen_carpet_plt, as_module=True), name='carpet_plot') carpet_plot.inputs.output = output_image wf.connect(gm_mask, 'out_file', carpet_plot, 'gm_mask') wf.connect(wm_mask, 'out_file', carpet_plot, 'wm_mask') wf.connect(csf_mask, 'out_file', carpet_plot, 'csf_mask') wf.connect(input_node, 'functional_to_standard', carpet_plot, 'functional_to_standard') wf.connect(carpet_plot, 'carpet_plot', output_node, 'carpet_plot') return wf
def init_dipy_brainsuite_shore_recon_wf(name="dipy_3dshore_recon", output_suffix="", params={}): """Reconstruct EAPs, ODFs, using 3dSHORE (brainsuite-style basis set). Inputs *qsiprep outputs* Outputs shore_coeffs 3dSHORE coefficients rtop Voxelwise Return-to-origin probability. rtap Voxelwise Return-to-axis probability. rtpp Voxelwise Return-to-plane probability. Params write_fibgz: bool True writes out a DSI Studio fib file write_mif: bool True writes out a MRTrix mif file with sh coefficients convert_to_multishell: str either "HCP", "ABCD", "lifespan" will resample the data with this scheme radial_order: int Radial order for spherical harmonics (even) zeta: float Zeta parameter for basis set. tau:float Diffusion parameter (default= 4 * np.pi**2) regularization "L2" or "L1". Default is "L2" lambdaN LambdaN parameter for L2 regularization. (default=1e-8) lambdaL LambdaL parameter for L2 regularization. (default=1e-8) regularization_weighting: int or "CV" L1 regualrization weighting. Default "CV" (use cross-validation). Can specify a static value to use in all voxels. l1_positive_constraint: bool Use positivity constraint. l1_maxiter Maximum number of iterations for L1 optization. (Default=1000) l1_alpha Alpha parameter for L1 optimization. (default=1.0) pos_grid: int Grid points for estimating EAP(default=11) pos_radius Radius for EAP estimation (default=20e-03) """ inputnode = pe.Node(niu.IdentityInterface(fields=input_fields), name="inputnode") outputnode = pe.Node(niu.IdentityInterface(fields=[ 'shore_coeffs_image', 'rtop_image', 'alpha_image', 'r2_image', 'cnr_image', 'regularization_image', 'fibgz', 'fod_sh_mif', 'dwi_file', 'bval_file', 'bvec_file', 'b_file' ]), name="outputnode") workflow = pe.Workflow(name=name) resample_mask = pe.Node(afni.Resample(outputtype='NIFTI_GZ', resample_mode="NN"), name='resample_mask') recon_shore = pe.Node(BrainSuiteShoreReconstruction(**params), name="recon_shore") doing_extrapolation = params.get("extrapolate_scheme") in ("HCP", "ABCD") workflow.connect([ (inputnode, recon_shore, [('dwi_file', 'dwi_file'), ('bval_file', 'bval_file'), ('bvec_file', 'bvec_file')]), (inputnode, resample_mask, [('t1_brain_mask', 'in_file'), ('dwi_file', 'master')]), (resample_mask, recon_shore, [('out_file', 'mask_file')]), (recon_shore, outputnode, [('shore_coeffs_image', 'shore_coeffs_image'), ('rtop_image', 'rtop_image'), ('alpha_image', 'alpha_image'), ('r2_image', 'r2_image'), ('cnr_image', 'cnr_image'), ('regularization_image', 'regularization_image'), ('fibgz', 'fibgz'), ('fod_sh_mif', 'fod_sh_mif'), ('extrapolated_dwi', 'dwi_file'), ('extrapolated_bvals', 'bval_file'), ('extrapolated_bvecs', 'bvec_file'), ('extrapolated_b', 'b_file')]) ]) if output_suffix: external_format_datasinks(output_suffix, params, workflow) ds_rtop = pe.Node(ReconDerivativesDataSink(extension='.nii.gz', desc="rtop", suffix=output_suffix, compress=True), name='ds_bsshore_rtop', run_without_submitting=True) workflow.connect(outputnode, 'rtop_image', ds_rtop, 'in_file') ds_coeff = pe.Node(ReconDerivativesDataSink(extension='.nii.gz', desc="SHOREcoeff", suffix=output_suffix, compress=True), name='ds_bsshore_coeff', run_without_submitting=True) workflow.connect(outputnode, 'shore_coeffs_image', ds_coeff, 'in_file') ds_alpha = pe.Node(ReconDerivativesDataSink(extension='.nii.gz', desc="L1alpha", suffix=output_suffix, compress=True), name='ds_bsshore_alpha', run_without_submitting=True) workflow.connect(outputnode, 'alpha_image', ds_alpha, 'in_file') ds_r2 = pe.Node(ReconDerivativesDataSink(extension='.nii.gz', desc="r2", suffix=output_suffix, compress=True), name='ds_bsshore_r2', run_without_submitting=True) workflow.connect(outputnode, 'r2_image', ds_r2, 'in_file') ds_cnr = pe.Node(ReconDerivativesDataSink(extension='.nii.gz', desc="CNR", suffix=output_suffix, compress=True), name='ds_bsshore_cnr', run_without_submitting=True) workflow.connect(outputnode, 'cnr_image', ds_cnr, 'in_file') ds_regl = pe.Node(ReconDerivativesDataSink(extension='.nii.gz', desc="regularization", suffix=output_suffix, compress=True), name='ds_bsshore_regl', run_without_submitting=True) workflow.connect(outputnode, 'regularization_image', ds_regl, 'in_file') if doing_extrapolation: ds_extrap_dwi = pe.Node(ReconDerivativesDataSink( extension='.nii.gz', desc="extrapolated", suffix=output_suffix, compress=True), name='ds_extrap_dwi', run_without_submitting=True) workflow.connect(outputnode, 'dwi_file', ds_extrap_dwi, 'in_file') ds_extrap_bval = pe.Node(ReconDerivativesDataSink( extension='.bval', desc="extrapolated", suffix=output_suffix), name='ds_extrap_bval', run_without_submitting=True) workflow.connect(outputnode, 'bval_file', ds_extrap_bval, 'in_file') ds_extrap_bvec = pe.Node(ReconDerivativesDataSink( extension='.bvec', desc="extrapolated", suffix=output_suffix), name='ds_extrap_bvec', run_without_submitting=True) workflow.connect(outputnode, 'bvec_file', ds_extrap_bvec, 'in_file') ds_extrap_b = pe.Node(ReconDerivativesDataSink( extension='.b', desc="extrapolated", suffix=output_suffix), name='ds_extrap_b', run_without_submitting=True) workflow.connect(outputnode, 'b_file', ds_extrap_b, 'in_file') return workflow
import nipype.interfaces.fsl as fsl ### resampling template data to 2mm # all input/output hard coded (not good...) myindata = '/data/pt_neuam005/sheyma/mni_icbm152_nlin_asym_09c/' # choose a subject's EPI image with 2mm resoltuib as 'masterfile' masterdi = '/data/pt_neuam005/FSTIM_1_Think_preprocessed/fmriprep/sub-10/ses-01/func/' masterte = 'sub-10_ses-01_task-future_bold_space-MNI152NLin2009cAsym_preproc.nii.gz' masterfi = os.path.join(masterdi, masterte) os.chdir(myindata) # afni resample resample = afni.Resample() resample.inputs.in_file = 'mni_icbm152_t1_tal_nlin_asym_09c.nii' resample.inputs.voxel_size = (2.0, 2.0, 2.0) resample.inputs.master = masterfi resample.inputs.outputtype = 'NIFTI' resample.inputs.out_file = 'mni_icbm152_t1_tal_nlin_asym_09c_2mm.nii.gz' print(resample.cmdline) resample.run() # transforming template mask to 2mm (fsl nonlinear transform) aw = fsl.ApplyWarp() aw.inputs.in_file = 'mni_icbm152_t1_tal_nlin_asym_09c_mask.nii' aw.inputs.ref_file = 'mni_icbm152_t1_tal_nlin_asym_09c_2mm.nii.gz' aw.inputs.out_file = 'mni_icbm152_t1_tal_nlin_asym_09c_2mm_trf.nii.gz' print(aw.cmdline) aw.run()
def create_anat_preproc(method='afni', already_skullstripped=False, c=None, wf_name='anat_preproc'): """The main purpose of this workflow is to process T1 scans. Raw mprage file is deobliqued, reoriented into RPI and skullstripped. Also, a whole brain only mask is generated from the skull stripped image for later use in registration. Returns ------- anat_preproc : workflow Anatomical Preprocessing Workflow Notes ----- `Source <https://github.com/FCP-INDI/C-PAC/blob/master/CPAC/anat_preproc/anat_preproc.py>`_ Workflow Inputs:: inputspec.anat : string User input anatomical (T1) Image, in any of the 8 orientations Workflow Outputs:: outputspec.refit : string Path to deobliqued anatomical image outputspec.reorient : string Path to RPI oriented anatomical image outputspec.skullstrip : string Path to skull stripped RPI oriented mprage file with normalized intensities. outputspec.brain : string Path to skull stripped RPI brain image with original intensity values and not normalized or scaled. Order of commands: - Deobliqing the scans. :: 3drefit -deoblique mprage.nii.gz - Re-orienting the Image into Right-to-Left Posterior-to-Anterior Inferior-to-Superior (RPI) orientation :: 3dresample -orient RPI -prefix mprage_RPI.nii.gz -inset mprage.nii.gz - Skull-Stripping the image :: Using AFNI :: 3dSkullStrip -input mprage_RPI.nii.gz -o_ply mprage_RPI_3dT.nii.gz or using BET :: bet mprage_RPI.nii.gz - The skull-stripping step modifies the intensity values. To get back the original intensity values, we do an element wise product of RPI data with step function of skull-stripped data :: 3dcalc -a mprage_RPI.nii.gz -b mprage_RPI_3dT.nii.gz -expr 'a*step(b)' -prefix mprage_RPI_3dc.nii.gz High Level Workflow Graph: .. image:: ../images/anatpreproc_graph.dot.png :width: 500 Detailed Workflow Graph: .. image:: ../images/anatpreproc_graph_detailed.dot.png :width: 500 Examples -------- >>> from CPAC.anat_preproc import create_anat_preproc >>> preproc = create_anat_preproc() >>> preproc.inputs.inputspec.anat = 'sub1/anat/mprage.nii.gz' >>> preproc.run() #doctest: +SKIP """ preproc = pe.Workflow(name=wf_name) inputnode = pe.Node(util.IdentityInterface(fields=['anat', 'brain_mask']), name='inputspec') outputnode = pe.Node(util.IdentityInterface( fields=['refit', 'reorient', 'skullstrip', 'brain', 'brain_mask']), name='outputspec') anat_deoblique = pe.Node(interface=afni.Refit(), name='anat_deoblique') anat_deoblique.inputs.deoblique = True preproc.connect(inputnode, 'anat', anat_deoblique, 'in_file') preproc.connect(anat_deoblique, 'out_file', outputnode, 'refit') # Disable non_local_means_filtering and n4_bias_field_correction when run niworkflows-ants if method == 'niworkflows-ants': c.non_local_means_filtering = False c.n4_bias_field_correction = False if c.non_local_means_filtering and c.n4_bias_field_correction: denoise = pe.Node(interface=ants.DenoiseImage(), name='anat_denoise') preproc.connect(anat_deoblique, 'out_file', denoise, 'input_image') n4 = pe.Node(interface=ants.N4BiasFieldCorrection(dimension=3, shrink_factor=2, copy_header=True), name='anat_n4') preproc.connect(denoise, 'output_image', n4, 'input_image') elif c.non_local_means_filtering and not c.n4_bias_field_correction: denoise = pe.Node(interface=ants.DenoiseImage(), name='anat_denoise') preproc.connect(anat_deoblique, 'out_file', denoise, 'input_image') elif not c.non_local_means_filtering and c.n4_bias_field_correction: n4 = pe.Node(interface=ants.N4BiasFieldCorrection(dimension=3, shrink_factor=2, copy_header=True), name='anat_n4') preproc.connect(anat_deoblique, 'out_file', n4, 'input_image') # Anatomical reorientation anat_reorient = pe.Node(interface=afni.Resample(), name='anat_reorient') anat_reorient.inputs.orientation = 'RPI' anat_reorient.inputs.outputtype = 'NIFTI_GZ' if c.n4_bias_field_correction: preproc.connect(n4, 'output_image', anat_reorient, 'in_file') elif c.non_local_means_filtering and not c.n4_bias_field_correction: preproc.connect(denoise, 'output_image', anat_reorient, 'in_file') else: preproc.connect(anat_deoblique, 'out_file', anat_reorient, 'in_file') preproc.connect(anat_reorient, 'out_file', outputnode, 'reorient') if already_skullstripped: anat_skullstrip = pe.Node( interface=util.IdentityInterface(fields=['out_file']), name='anat_skullstrip') preproc.connect(anat_reorient, 'out_file', anat_skullstrip, 'out_file') preproc.connect(anat_skullstrip, 'out_file', outputnode, 'skullstrip') preproc.connect(anat_skullstrip, 'out_file', outputnode, 'brain') else: if method == 'afni': # Skull-stripping using AFNI 3dSkullStrip inputnode_afni = pe.Node(util.IdentityInterface(fields=[ 'mask_vol', 'shrink_factor', 'var_shrink_fac', 'shrink_fac_bot_lim', 'avoid_vent', 'niter', 'pushout', 'touchup', 'fill_hole', 'avoid_eyes', 'use_edge', 'exp_frac', 'smooth_final', 'push_to_edge', 'use_skull', 'perc_int', 'max_inter_iter', 'blur_fwhm', 'fac', 'monkey' ]), name='AFNI_options') skullstrip_args = pe.Node(util.Function( input_names=[ 'spat_norm', 'spat_norm_dxyz', 'mask_vol', 'shrink_fac', 'var_shrink_fac', 'shrink_fac_bot_lim', 'avoid_vent', 'niter', 'pushout', 'touchup', 'fill_hole', 'avoid_eyes', 'use_edge', 'exp_frac', 'smooth_final', 'push_to_edge', 'use_skull', 'perc_int', 'max_inter_iter', 'blur_fwhm', 'fac', 'monkey' ], output_names=['expr'], function=create_3dskullstrip_arg_string), name='anat_skullstrip_args') preproc.connect([(inputnode_afni, skullstrip_args, [('mask_vol', 'mask_vol'), ('shrink_factor', 'shrink_fac'), ('var_shrink_fac', 'var_shrink_fac'), ('shrink_fac_bot_lim', 'shrink_fac_bot_lim'), ('avoid_vent', 'avoid_vent'), ('niter', 'niter'), ('pushout', 'pushout'), ('touchup', 'touchup'), ('fill_hole', 'fill_hole'), ('avoid_eyes', 'avoid_eyes'), ('use_edge', 'use_edge'), ('exp_frac', 'exp_frac'), ('smooth_final', 'smooth_final'), ('push_to_edge', 'push_to_edge'), ('use_skull', 'use_skull'), ('perc_int', 'perc_int'), ('max_inter_iter', 'max_inter_iter'), ('blur_fwhm', 'blur_fwhm'), ('fac', 'fac'), ('monkey', 'monkey')])]) anat_skullstrip = pe.Node(interface=afni.SkullStrip(), name='anat_skullstrip') anat_skullstrip.inputs.outputtype = 'NIFTI_GZ' preproc.connect(anat_reorient, 'out_file', anat_skullstrip, 'in_file') preproc.connect(skullstrip_args, 'expr', anat_skullstrip, 'args') # Generate anatomical brain mask anat_brain_mask = pe.Node(interface=afni.Calc(), name='anat_brain_mask') anat_brain_mask.inputs.expr = 'step(a)' anat_brain_mask.inputs.outputtype = 'NIFTI_GZ' preproc.connect(anat_skullstrip, 'out_file', anat_brain_mask, 'in_file_a') # Apply skull-stripping step mask to original volume anat_skullstrip_orig_vol = pe.Node(interface=afni.Calc(), name='anat_skullstrip_orig_vol') anat_skullstrip_orig_vol.inputs.expr = 'a*step(b)' anat_skullstrip_orig_vol.inputs.outputtype = 'NIFTI_GZ' preproc.connect(anat_reorient, 'out_file', anat_skullstrip_orig_vol, 'in_file_a') preproc.connect(anat_brain_mask, 'out_file', anat_skullstrip_orig_vol, 'in_file_b') preproc.connect(anat_brain_mask, 'out_file', outputnode, 'brain_mask') preproc.connect(anat_skullstrip_orig_vol, 'out_file', outputnode, 'brain') elif method == 'fsl': # Skull-stripping using FSL BET inputnode_bet = pe.Node(util.IdentityInterface(fields=[ 'frac', 'mask_boolean', 'mesh_boolean', 'outline', 'padding', 'radius', 'reduce_bias', 'remove_eyes', 'robust', 'skull', 'surfaces', 'threshold', 'vertical_gradient' ]), name='BET_options') anat_skullstrip = pe.Node(interface=fsl.BET(), name='anat_skullstrip') anat_skullstrip.inputs.output_type = 'NIFTI_GZ' preproc.connect(anat_reorient, 'out_file', anat_skullstrip, 'in_file') preproc.connect([(inputnode_bet, anat_skullstrip, [ ('frac', 'frac'), ('mask_boolean', 'mask'), ('mesh_boolean', 'mesh'), ('outline', 'outline'), ('padding', 'padding'), ('radius', 'radius'), ('reduce_bias', 'reduce_bias'), ('remove_eyes', 'remove_eyes'), ('robust', 'robust'), ('skull', 'skull'), ('surfaces', 'surfaces'), ('threshold', 'threshold'), ('vertical_gradient', 'vertical_gradient'), ])]) preproc.connect(anat_skullstrip, 'out_file', outputnode, 'skullstrip') # Apply skull-stripping step mask to original volume anat_skullstrip_orig_vol = pe.Node(interface=afni.Calc(), name='anat_skullstrip_orig_vol') anat_skullstrip_orig_vol.inputs.expr = 'a*step(b)' anat_skullstrip_orig_vol.inputs.outputtype = 'NIFTI_GZ' preproc.connect(anat_reorient, 'out_file', anat_skullstrip_orig_vol, 'in_file_a') preproc.connect(anat_skullstrip, 'out_file', anat_skullstrip_orig_vol, 'in_file_b') preproc.connect(anat_skullstrip, 'mask_file', outputnode, 'brain_mask') preproc.connect(anat_skullstrip_orig_vol, 'out_file', outputnode, 'brain') elif method == 'niworkflows-ants': # Skull-stripping using niworkflows-ants anat_skullstrip_ants = init_brain_extraction_wf( tpl_target_path=c.niworkflows_ants_template_path, tpl_mask_path=c.niworkflows_ants_mask_path, tpl_regmask_path=c.niworkflows_ants_regmask_path, name='anat_skullstrip_ants') preproc.connect(anat_reorient, 'out_file', anat_skullstrip_ants, 'inputnode.in_files') preproc.connect(anat_skullstrip_ants, 'copy_xform.out_file', outputnode, 'skullstrip') preproc.connect(anat_skullstrip_ants, 'copy_xform.out_file', outputnode, 'brain') preproc.connect(anat_skullstrip_ants, 'atropos_wf.copy_xform.out_mask', outputnode, 'brain_mask') elif method == 'mask': brain_mask_deoblique = pe.Node(interface=afni.Refit(), name='brain_mask_deoblique') brain_mask_deoblique.inputs.deoblique = True preproc.connect(inputnode, 'brain_mask', brain_mask_deoblique, 'in_file') brain_mask_reorient = pe.Node(interface=afni.Resample(), name='brain_mask_reorient') brain_mask_reorient.inputs.orientation = 'RPI' brain_mask_reorient.inputs.outputtype = 'NIFTI_GZ' preproc.connect(brain_mask_deoblique, 'out_file', brain_mask_reorient, 'in_file') anat_skullstrip_orig_vol = pe.Node(interface=afni.Calc(), name='anat_skullstrip_orig_vol') anat_skullstrip_orig_vol.inputs.expr = 'a*step(b)' anat_skullstrip_orig_vol.inputs.outputtype = 'NIFTI_GZ' preproc.connect(anat_reorient, 'out_file', anat_skullstrip_orig_vol, 'in_file_a') preproc.connect(brain_mask_reorient, 'out_file', anat_skullstrip_orig_vol, 'in_file_b') preproc.connect(brain_mask_reorient, 'out_file', outputnode, 'brain_mask') preproc.connect(anat_skullstrip_orig_vol, 'out_file', outputnode, 'brain') elif method == 'unet': """ UNet options (following numbers are default): input_slice: 3 conv_block: 5 kernel_root: 16 rescale_dim: 256 """ # TODO: add options to pipeline_config train_model = UNet2d(dim_in=3, num_conv_block=5, kernel_root=16) unet_path = check_for_s3(c.unet_model) checkpoint = torch.load(unet_path, map_location={'cuda:0': 'cpu'}) train_model.load_state_dict(checkpoint['state_dict']) model = nn.Sequential(train_model, nn.Softmax2d()) # create a node called unet_mask unet_mask = pe.Node(util.Function(input_names=['model', 'cimg_in'], output_names=['out_path'], function=predict_volumes), name='unet_mask') unet_mask.inputs.model = model preproc.connect(anat_reorient, 'out_file', unet_mask, 'cimg_in') """ Revised mask with ANTs """ # fslmaths <whole head> -mul <mask> brain.nii.gz unet_masked_brain = pe.Node(interface=fsl.MultiImageMaths(), name='unet_masked_brain') unet_masked_brain.inputs.op_string = "-mul %s" preproc.connect(anat_reorient, 'out_file', unet_masked_brain, 'in_file') preproc.connect(unet_mask, 'out_path', unet_masked_brain, 'operand_files') # flirt -v -dof 6 -in brain.nii.gz -ref NMT_SS_0.5mm.nii.gz -o brain_rot2atl -omat brain_rot2atl.mat -interp sinc # TODO change it to ANTs linear transform native_brain_to_template_brain = pe.Node( interface=fsl.FLIRT(), name='native_brain_to_template_brain') native_brain_to_template_brain.inputs.reference = c.template_brain_only_for_anat native_brain_to_template_brain.inputs.dof = 6 native_brain_to_template_brain.inputs.interp = 'sinc' preproc.connect(unet_masked_brain, 'out_file', native_brain_to_template_brain, 'in_file') # flirt -in head.nii.gz -ref NMT_0.5mm.nii.gz -o head_rot2atl -applyxfm -init brain_rot2atl.mat # TODO change it to ANTs linear transform native_head_to_template_head = pe.Node( interface=fsl.FLIRT(), name='native_head_to_template_head') native_head_to_template_head.inputs.reference = c.template_skull_for_anat native_head_to_template_head.inputs.apply_xfm = True preproc.connect(anat_reorient, 'out_file', native_head_to_template_head, 'in_file') preproc.connect(native_brain_to_template_brain, 'out_matrix_file', native_head_to_template_head, 'in_matrix_file') # fslmaths NMT_SS_0.5mm.nii.gz -bin templateMask.nii.gz template_brain_mask = pe.Node(interface=fsl.maths.MathsCommand(), name='template_brain_mask') template_brain_mask.inputs.in_file = c.template_brain_only_for_anat template_brain_mask.inputs.args = '-bin' # ANTS 3 -m CC[head_rot2atl.nii.gz,NMT_0.5mm.nii.gz,1,5] -t SyN[0.25] -r Gauss[3,0] -o atl2T1rot -i 60x50x20 --use-Histogram-Matching --number-of-affine-iterations 10000x10000x10000x10000x10000 --MI-option 32x16000 ants_template_head_to_template = pe.Node( interface=ants.Registration(), name='template_head_to_template') ants_template_head_to_template.inputs.metric = ['CC'] ants_template_head_to_template.inputs.metric_weight = [1, 5] ants_template_head_to_template.inputs.moving_image = c.template_skull_for_anat ants_template_head_to_template.inputs.transforms = ['SyN'] ants_template_head_to_template.inputs.transform_parameters = [ (0.25, ) ] ants_template_head_to_template.inputs.interpolation = 'NearestNeighbor' ants_template_head_to_template.inputs.number_of_iterations = [[ 60, 50, 20 ]] ants_template_head_to_template.inputs.smoothing_sigmas = [[ 0.6, 0.2, 0.0 ]] ants_template_head_to_template.inputs.shrink_factors = [[4, 2, 1]] ants_template_head_to_template.inputs.convergence_threshold = [ 1.e-8 ] preproc.connect(native_head_to_template_head, 'out_file', ants_template_head_to_template, 'fixed_image') # antsApplyTransforms -d 3 -i templateMask.nii.gz -t atl2T1rotWarp.nii.gz atl2T1rotAffine.txt -r brain_rot2atl.nii.gz -o brain_rot2atl_mask.nii.gz template_head_transform_to_template = pe.Node( interface=ants.ApplyTransforms(), name='template_head_transform_to_template') template_head_transform_to_template.inputs.dimension = 3 preproc.connect(template_brain_mask, 'out_file', template_head_transform_to_template, 'input_image') preproc.connect(native_brain_to_template_brain, 'out_file', template_head_transform_to_template, 'reference_image') preproc.connect(ants_template_head_to_template, 'forward_transforms', template_head_transform_to_template, 'transforms') # convert_xfm -omat brain_rot2native.mat -inverse brain_rot2atl.mat invt = pe.Node(interface=fsl.ConvertXFM(), name='convert_xfm') invt.inputs.invert_xfm = True preproc.connect(native_brain_to_template_brain, 'out_matrix_file', invt, 'in_file') # flirt -in brain_rot2atl_mask.nii.gz -ref brain.nii.gz -o brain_mask.nii.gz -applyxfm -init brain_rot2native.mat template_brain_to_native_brain = pe.Node( interface=fsl.FLIRT(), name='template_brain_to_native_brain') template_brain_to_native_brain.inputs.apply_xfm = True preproc.connect(template_head_transform_to_template, 'output_image', template_brain_to_native_brain, 'in_file') preproc.connect(unet_masked_brain, 'out_file', template_brain_to_native_brain, 'reference') preproc.connect(invt, 'out_file', template_brain_to_native_brain, 'in_matrix_file') # fslmaths brain_mask.nii.gz -thr .5 -bin brain_mask_thr.nii.gz refined_mask = pe.Node(interface=fsl.Threshold(), name='refined_mask') refined_mask.inputs.thresh = 0.5 preproc.connect(template_brain_to_native_brain, 'out_file', refined_mask, 'in_file') # get a new brain with mask refined_brain = pe.Node(interface=fsl.MultiImageMaths(), name='refined_brain') refined_brain.inputs.op_string = "-mul %s" preproc.connect(anat_reorient, 'out_file', refined_brain, 'in_file') preproc.connect(refined_mask, 'out_file', refined_brain, 'operand_files') preproc.connect(refined_mask, 'out_file', outputnode, 'brain_mask') preproc.connect(refined_brain, 'out_file', outputnode, 'brain') return preproc