def warp_rois_gray_fs(name='warp_rois_gray_fs'): inputnode = pe.Node( utility.IdentityInterface( fields=['fmri_reference','seg','mni_reg','def_field', 'rois_files','t1_to_epi']), name='inputspec') outputnode = pe.Node( utility.IdentityInterface( fields=['t1_rois','t1_gray_rois','fmri_rois','min_nvox']), name='outputspec') n_mni_to_t1 = pe.MapNode( freesurfer.ApplyVolTransform(interp='nearest', no_def_m3z_path=True, inverse=True,invert_morph=True), iterfield = ['target_file','transformed_file'], name='mni_to_t1') n_restrict_to_gray_fs = pe.Node( utility.Function(input_names=['rois','seg','tissues'], output_names=['masked_rois'], function=restrict_to_gray_fs), name='restrict_to_gray_fs') n_restrict_to_gray_fs.inputs.min_nvox = 100 n_restrict_to_gray_fs.inputs.tissues = [2,42,8,47,12,51,11,50,10,49,18,54,26,58] n_restrict_to_gray_fs.inputs.threshold = 1e-3 n_t1_to_fmri = pe.MapNode( freesurfer.ApplyVolTransform(interp='nearest',inverse=True), iterfield=['target_file','transformed_file'], name='t1_to_fmri') w=pe.Workflow(name=name) w.connect([ (inputnode,n_mni_to_t1, [('rois_files','target_file'), (('rois_files',fname_presuffix_basename,'','_native'), 'transformed_file'), ('def_field','m3z_file'), ('mni_reg','reg_file'), ('seg','source_file')]), (inputnode,n_restrict_to_gray_fs,[('seg','seg')]), (n_mni_to_t1,n_restrict_to_gray_fs,[('transformed_file','rois')]), (n_restrict_to_gray_fs,n_t1_to_fmri,[ ('masked_rois','target_file'), (('masked_rois',fname_presuffix_basename,'','_epi'), 'transformed_file'),]), (inputnode,n_t1_to_fmri,[('fmri_reference','source_file'), ('t1_to_epi','reg_file')]), (n_mni_to_t1,outputnode,[('transformed_file','t1_rois')]), (n_t1_to_fmri,outputnode,[('transformed_file','fmri_rois')]), (n_restrict_to_gray_fs,outputnode,[('masked_rois','t1_gray_rois')]) ]) return w
def _post_run_hook(self, runtime): outputs = self.aggregate_outputs(runtime=runtime) mri_dir = None if isdefined(self.inputs.subject_id): mri_dir = os.path.join(self.inputs.subjects_dir, self.inputs.subject_id, "mri") if isdefined(self.inputs.reference_file): target_file = self.inputs.reference_file else: target_file = os.path.join(mri_dir, "brainmask.mgz") # Apply transform for simplicity mri_vol2vol = fs.ApplyVolTransform( source_file=self.inputs.source_file, target_file=target_file, lta_file=outputs.out_lta_file, interp="nearest", ) res = mri_vol2vol.run() self._fixed_image = target_file self._moving_image = res.outputs.transformed_file if mri_dir is not None: self._contour = os.path.join(mri_dir, "ribbon.mgz") NIWORKFLOWS_LOG.info( "Report - setting fixed (%s) and moving (%s) images", self._fixed_image, self._moving_image, ) return super(MRICoregRPT, self)._post_run_hook(runtime)
def epi_fs_coregister(name='epi_fs_coregister'): inputnode = pe.Node( utility.IdentityInterface( fields=['fmri','subject_id','subjects_dir', 'roi_file','mask_file']), name='inputspec') outputnode = pe.Node( utility.IdentityInterface( fields=['fmri_mask','fmri_rois','reg_file','fsl_reg_file']), name='outputspec') n_bbregister = pe.Node( freesurfer.BBRegister(init='fsl', contrast_type='t2', out_fsl_file=True), name='bbregister') n_fsmask2epi = pe.Node( freesurfer.ApplyVolTransform(inverse=True, interp='nearest', transformed_file='mask_epi.nii.gz'), name='fsmask2epi') n_fsrois2epi = pe.Node( freesurfer.ApplyVolTransform(inverse=True, interp='nearest', transformed_file='epi_aparc.aseg.nii.gz'), name='fsrois2epi') w=pe.Workflow(name=name) w.connect([ (inputnode, n_bbregister,[('fmri','source_file'), ('subjects_dir','subjects_dir'), ('subject_id','subject_id')]), (n_bbregister, n_fsrois2epi,[('out_reg_file','reg_file')]), (inputnode, n_fsrois2epi, [('fmri','source_file'), ('roi_file','target_file')]), (n_bbregister, n_fsmask2epi,[('out_reg_file','reg_file')]), (inputnode, n_fsmask2epi, [('fmri','source_file'), ('mask_file','target_file')]), (n_bbregister, outputnode,[('out_reg_file','reg_file')]), (n_bbregister, outputnode,[('out_fsl_file','fsl_reg_file')]), (n_fsmask2epi, outputnode, [('transformed_file','fmri_mask')]), (n_fsrois2epi, outputnode, [('transformed_file','fmri_rois')]), ]) return w
def make_freesurfer(self): # Ref: http://nipype.readthedocs.io/en/1.0.4/interfaces/generated/interfaces.freesurfer/preprocess.html#reconall fs_recon1 = Node(interface=fs.ReconAll(directive='autorecon1', mris_inflate='-n 15', hires=True, mprage=True, openmp=self.omp_nthreads), name='fs_recon1', n_procs=self.omp_nthreads) fs_mriconv = Node(interface=fs.MRIConvert(out_type='mgz'), name='fs_mriconv') fs_vol2vol = Node(interface=fs.ApplyVolTransform(mni_152_reg=True), name='fs_vol2vol') fs_mrimask = Node(interface=fs.ApplyMask(), name='fs_mrimask') fs_recon2 = Node(interface=fs.ReconAll(directive='autorecon2', hires=True, mprage=True, hippocampal_subfields_T1=False, openmp=self.omp_nthreads), name='fs_recon2', n_procs=self.omp_nthreads) fs_recon3 = Node(interface=fs.ReconAll(directive='autorecon3', hires=True, mprage=True, hippocampal_subfields_T1=False, openmp=self.omp_nthreads), name='fs_recon3', n_procs=self.omp_nthreads) copy_brainmask = Node(Function(['in_file', 'fs_dir'], ['fs_dir'], self.copy_mask), name='copy_brainmask') segment_hp = Node(interface=SegmentHA_T1(), name='segment_hp') freesurfer = Workflow(name='freesurfer', base_dir=self.temp_dir) freesurfer.connect(fs_recon1, 'T1', fs_vol2vol, 'target_file') freesurfer.connect(fs_mriconv, 'out_file', fs_vol2vol, 'source_file') freesurfer.connect(fs_recon1, 'T1', fs_mrimask, 'in_file') freesurfer.connect(fs_vol2vol, 'transformed_file', fs_mrimask, 'mask_file') freesurfer.connect(fs_mrimask, 'out_file', copy_brainmask, 'in_file') freesurfer.connect(fs_recon1, 'subjects_dir', copy_brainmask, 'fs_dir') freesurfer.connect(copy_brainmask, 'fs_dir', fs_recon2, 'subjects_dir') freesurfer.connect(fs_recon2, 'subjects_dir', fs_recon3, 'subjects_dir') freesurfer.connect(fs_recon3, 'subjects_dir', segment_hp, 'subjects_dir') return freesurfer
def pet_register_rois(name='pet_register_rois', pet_prefix='fdg'): inputnode = pe.Node(utility.IdentityInterface( fields=['pet_image', 't1_image', 'rois_image']), name='inputspec') outputnode = pe.Node(utility.IdentityInterface( fields=['pet2t1', 'pet2t1_xfm', 'warped_rois', 'stats']), name='outputspec') n_flirt_pet2t1 = pe.Node(fsl.FLIRT(dof=6, cost='mutualinfo', out_file=Undefined, out_matrix_file='%spet2t1.mat' % pet_prefix), name='flirt_%spet2t1' % pet_prefix) n_fsl2xfm = pe.Node(freesurfer.preprocess.Tkregister(no_edit=True, xfm_out='%s.xfm', reg_file='%s.dat'), name='fsl2xfm') n_warp_rois = pe.Node(freesurfer.ApplyVolTransform( inverse=True, interp='nearest', transformed_file='warped_rois.nii.gz'), name='warp_rois') w = pe.Workflow(name=name) n_extract_signal = pe.Node( afni.ROIStats(args='-nzvoxels -nzsigma -nzmedian -nobriklab'), name='extract_signal') w.connect([(inputnode, n_flirt_pet2t1, [('pet_image', 'in_file'), ('t1_image', 'reference')]), (n_flirt_pet2t1, n_fsl2xfm, [('out_matrix_file', 'fsl_reg')]), (inputnode, n_fsl2xfm, [ ('pet_image', 'mov'), ('t1_image', 'target'), ]), (n_fsl2xfm, n_warp_rois, [('xfm_out', 'xfm_reg_file')]), (inputnode, n_warp_rois, [('pet_image', 'source_file'), ('rois_image', 'target_file')]), (n_warp_rois, n_extract_signal, [('transformed_file', 'mask')]), (inputnode, n_extract_signal, [('pet_image', 'in_file')]), (n_warp_rois, outputnode, [('transformed_file', 'warped_rois') ]), (n_flirt_pet2t1, outputnode, [('out_matrix_file', 'pet2t1')]), (n_fsl2xfm, outputnode, [('xfm_out', 'pet2t1_xfm')]), (n_extract_signal, outputnode, [('stats', 'stats')])]) return w
def extract_csf_mask(): """Create a workflow to extract a mask of csf voxels Inputs ------ inputspec.mean_file : inputspec.reg_file : inputspec.fsaseg_file : Outputs ------- outputspec.csf_mask : Returns ------- workflow : workflow that extracts mask of csf voxels """ import nipype.pipeline.engine as pe import nipype.interfaces.freesurfer as fs import nipype.interfaces.utility as util extract_csf = pe.Workflow(name='extract_csf_mask') inputspec = pe.Node(util.IdentityInterface( fields=['mean_file', 'reg_file', 'fsaseg_file']), name='inputspec') bin = pe.Node(fs.Binarize(), name='binarize') bin.inputs.wm_ven_csf = True bin.inputs.match = [4, 5, 14, 15, 24, 31, 43, 44, 63] bin.inputs.erode = 2 extract_csf.connect(inputspec, 'fsaseg_file', bin, "in_file") voltransform = pe.Node(fs.ApplyVolTransform(inverse=True), name='inverse_transform') extract_csf.connect(bin, 'binary_file', voltransform, 'target_file') extract_csf.connect(inputspec, 'reg_file', voltransform, 'reg_file') extract_csf.connect(inputspec, 'mean_file', voltransform, 'source_file') outputspec = pe.Node(util.IdentityInterface(fields=['csf_mask']), name='outputspec') extract_csf.connect(voltransform, 'transformed_file', outputspec, 'csf_mask') return extract_csf
def freesurfer_brain_connector(wf, cfg, strat_pool, pipe_num, opt): # register FS brain mask to native space fs_brain_mask_to_native = pe.Node(interface=freesurfer.ApplyVolTransform(), name='fs_brain_mask_to_native') fs_brain_mask_to_native.inputs.reg_header = True node, out = strat_pool.get_data('space-T1w_desc-brain_mask') wf.connect(node, out, fs_brain_mask_to_native, 'source_file') node, out = strat_pool.get_data('raw_average') wf.connect(node, out, fs_brain_mask_to_native, 'target_file') node, out = strat_pool.get_data('freesurfer_subject_dir') wf.connect(node, out, fs_brain_mask_to_native, 'subjects_dir') # convert brain mask file from .mgz to .nii.gz fs_brain_mask_to_nifti = pe.Node(util.Function(input_names=['in_file'], output_names=['out_file'], function=mri_convert), name='fs_brainmask_to_nifti') wf.connect(fs_brain_mask_to_native, 'transformed_file', fs_brain_mask_to_nifti, 'in_file') # binarize the brain mask binarize_fs_brain_mask = pe.Node(interface=fsl.maths.MathsCommand(), name='binarize_fs_brainmask') binarize_fs_brain_mask.inputs.args = '-bin' wf.connect(fs_brain_mask_to_nifti, 'out_file', binarize_fs_brain_mask, 'in_file') # fill holes fill_fs_brain_mask = pe.Node(interface=afni.MaskTool(), name='fill_fs_brainmask') fill_fs_brain_mask.inputs.fill_holes = True fill_fs_brain_mask.inputs.outputtype = 'NIFTI_GZ' wf.connect(binarize_fs_brain_mask, 'out_file', fill_fs_brain_mask, 'in_file') outputs = {'space-T1w_desc-brain_mask': (fill_fs_brain_mask, 'out_file')} return (wf, outputs)
def _post_run_hook(self, runtime): outputs = self.aggregate_outputs(runtime=runtime) mri_dir = os.path.join(self.inputs.subjects_dir, self.inputs.subject_id, 'mri') target_file = os.path.join(mri_dir, 'brainmask.mgz') # Apply transform for simplicity mri_vol2vol = fs.ApplyVolTransform(source_file=self.inputs.source_file, target_file=target_file, lta_file=outputs.out_lta_file, interp='nearest') res = mri_vol2vol.run() self._fixed_image = target_file self._moving_image = res.outputs.transformed_file self._contour = os.path.join(mri_dir, 'ribbon.mgz') NIWORKFLOWS_LOG.info( 'Report - setting fixed (%s) and moving (%s) images', self._fixed_image, self._moving_image) return super(BBRegisterRPT, self)._post_run_hook(runtime)
def create_confound_extraction_workflow(name="confounds", wm_components=6): """Extract nuisance variables from anatomical sources.""" inputnode = Node( IdentityInterface( ["timeseries", "brain_mask", "reg_file", "subject_id"]), "inputs") # Find the subject's Freesurfer segmentation # Grab the Freesurfer aparc+aseg file as an anatomical brain mask getaseg = Node( io.SelectFiles({"aseg": "{subject_id}/mri/aseg.mgz"}, base_directory=os.environ["SUBJECTS_DIR"]), "getaseg") # Select and erode the white matter to get deep voxels selectwm = Node(fs.Binarize(erode=3, wm=True), "selectwm") # Transform the mask into functional space transform = MapNode(fs.ApplyVolTransform(inverse=True, interp="nearest"), ["reg_file", "source_file"], "transform") # Extract eigenvariates of the timeseries from WM and whole brain extract = MapNode(ExtractConfounds(n_components=wm_components), ["timeseries", "brain_mask", "wm_mask"], "extract") outputnode = Node(IdentityInterface(["confound_file"]), "outputs") confounds = Workflow(name) confounds.connect([ (inputnode, getaseg, [("subject_id", "subject_id")]), (getaseg, selectwm, [("aseg", "in_file")]), (selectwm, transform, [("binary_file", "target_file")]), (inputnode, transform, [("reg_file", "reg_file"), ("timeseries", "source_file")]), (transform, extract, [("transformed_file", "wm_mask")]), (inputnode, extract, [("timeseries", "timeseries"), ("brain_mask", "brain_mask")]), (extract, outputnode, [("out_file", "confound_file")]), ]) return confounds
def init_segs_to_native_wf(*, name="segs_to_native", segmentation="aseg"): """ Get a segmentation from FreeSurfer conformed space into native T1w space. Workflow Graph .. workflow:: :graph2use: orig :simple_form: yes from smriprep.workflows.surfaces import init_segs_to_native_wf wf = init_segs_to_native_wf() Parameters ---------- segmentation The name of a segmentation ('aseg' or 'aparc_aseg' or 'wmparc') Inputs ------ in_file Anatomical, merged T1w image after INU correction subjects_dir FreeSurfer SUBJECTS_DIR subject_id FreeSurfer subject ID fsnative2t1w_xfm LTA-style affine matrix translating from FreeSurfer-conformed subject space to T1w Outputs ------- out_file The selected segmentation, after resampling in native space """ workflow = Workflow(name="%s_%s" % (name, segmentation)) inputnode = pe.Node( niu.IdentityInterface( ["in_file", "subjects_dir", "subject_id", "fsnative2t1w_xfm"] ), name="inputnode", ) outputnode = pe.Node(niu.IdentityInterface(["out_file"]), name="outputnode") # Extract the aseg and aparc+aseg outputs fssource = pe.Node(nio.FreeSurferSource(), name="fs_datasource") # Resample from T1.mgz to T1w.nii.gz, applying any offset in fsnative2t1w_xfm, # and convert to NIfTI while we're at it resample = pe.Node( fs.ApplyVolTransform(transformed_file="seg.nii.gz", interp="nearest"), name="resample", ) if segmentation.startswith("aparc"): if segmentation == "aparc_aseg": def _sel(x): return [parc for parc in x if "aparc+" in parc][0] # noqa elif segmentation == "aparc_a2009s": def _sel(x): return [parc for parc in x if "a2009s+" in parc][0] # noqa elif segmentation == "aparc_dkt": def _sel(x): return [parc for parc in x if "DKTatlas+" in parc][0] # noqa segmentation = (segmentation, _sel) # fmt:off workflow.connect([ (inputnode, fssource, [ ('subjects_dir', 'subjects_dir'), ('subject_id', 'subject_id')]), (inputnode, resample, [('in_file', 'target_file'), ('fsnative2t1w_xfm', 'lta_file')]), (fssource, resample, [(segmentation, 'source_file')]), (resample, outputnode, [('transformed_file', 'out_file')]), ]) # fmt:on return workflow
def create_skullstrip_workflow(name="skullstrip"): """Remove non-brain voxels from the timeseries.""" # Define the workflow inputs inputnode = Node( IdentityInterface(["subject_id", "timeseries", "reg_file"]), "inputs") # Mean the timeseries across the fourth dimension origmean = MapNode(fsl.MeanImage(), "in_file", "origmean") # Grab the Freesurfer aparc+aseg file as an anatomical brain mask getaseg = Node( io.SelectFiles({"aseg": "{subject_id}/mri/aparc+aseg.mgz"}, base_directory=os.environ["SUBJECTS_DIR"]), "getaseg") # Threshold the aseg volume to get a boolean mask makemask = Node(fs.Binarize(dilate=4, min=0.5), "makemask") # Transform the brain mask into functional space transform = MapNode(fs.ApplyVolTransform(inverse=True, interp="nearest"), ["reg_file", "source_file"], "transform") # Convert the mask to nifti and rename convertmask = MapNode(fs.MRIConvert(out_file="functional_mask.nii.gz"), "in_file", "convertmask") # Use the mask to skullstrip the timeseries stripts = MapNode(fs.ApplyMask(), ["in_file", "mask_file"], "stripts") # Use the mask to skullstrip the mean image stripmean = MapNode(fs.ApplyMask(), ["in_file", "mask_file"], "stripmean") # Generate images summarizing the skullstrip and resulting data reportmask = MapNode(MaskReport(), ["mask_file", "orig_file", "mean_file"], "reportmask") # Define the workflow outputs outputnode = Node( IdentityInterface(["timeseries", "mean_file", "mask_file", "report"]), "outputs") # Define and connect the workflow skullstrip = Workflow(name) skullstrip.connect([ (inputnode, origmean, [("timeseries", "in_file")]), (inputnode, getaseg, [("subject_id", "subject_id")]), (origmean, transform, [("out_file", "source_file")]), (getaseg, makemask, [("aseg", "in_file")]), (makemask, transform, [("binary_file", "target_file")]), (inputnode, transform, [("reg_file", "reg_file")]), (transform, stripts, [("transformed_file", "mask_file")]), (transform, stripmean, [("transformed_file", "mask_file")]), (inputnode, stripts, [("timeseries", "in_file")]), (origmean, stripmean, [("out_file", "in_file")]), (stripmean, reportmask, [("out_file", "mean_file")]), (origmean, reportmask, [("out_file", "orig_file")]), (transform, reportmask, [("transformed_file", "mask_file")]), (transform, convertmask, [("transformed_file", "in_file")]), (stripts, outputnode, [("out_file", "timeseries")]), (stripmean, outputnode, [("out_file", "mean_file")]), (convertmask, outputnode, [("out_file", "mask_file")]), (reportmask, outputnode, [("out_files", "report")]), ]) return skullstrip
def define_template_workflow(info, subjects, qc=True): # --- Workflow parameterization subject_source = Node(IdentityInterface(["subject"]), name="subject_source", iterables=("subject", subjects)) # Data input template_input = Node(TemplateInput(data_dir=info.data_dir), "template_input") # --- Definition of functional template space crop_image = Node(fs.ApplyMask(args="-bb 4"), "crop_image") zoom_image = Node(fs.MRIConvert(resample_type="cubic", out_type="niigz", vox_size=info.voxel_size, ), "zoom_image") reorient_image = Node(fsl.Reorient2Std(out_file="anat.nii.gz"), "reorient_image") generate_reg = Node(fs.Tkregister2(fsl_out="anat2func.mat", reg_file="anat2func.dat", reg_header=True), "generate_reg") invert_reg = Node(fs.Tkregister2(reg_file="func2anat.dat", reg_header=True), "invert_reg") # --- Identification of surface vertices hemi_source = Node(IdentityInterface(["hemi"]), "hemi_source", iterables=("hemi", ["lh", "rh"])) tag_surf = Node(fs.Surface2VolTransform(surf_name="graymid", transformed_file="ribbon.nii.gz", vertexvol_file="vertices.nii.gz", mkmask=True), "tag_surf") mask_cortex = Node(MaskWithLabel(fill_value=-1), "mask_cortex") combine_hemis = JoinNode(fsl.Merge(dimension="t", merged_file="surf.nii.gz"), name="combine_hemis", joinsource="hemi_source", joinfield="in_files") make_ribbon = Node(MakeRibbon(), "make_ribbon") # --- Segementation of anatomical tissue in functional space transform_wmparc = Node(fs.ApplyVolTransform(inverse=True, interp="nearest", args="--keep-precision"), "transform_wmparc") anat_segment = Node(AnatomicalSegmentation(), "anat_segment") # --- Template QC template_qc = Node(TemplateReport(), "template_qc") # --- Workflow ouptut save_info = Node(SaveInfo(info_dict=info.trait_get()), "save_info") template_output = Node(DataSink(base_directory=info.proc_dir, parameterization=False), "template_output") # === Assemble pipeline workflow = Workflow(name="template", base_dir=info.cache_dir) processing_edges = [ (subject_source, template_input, [("subject", "subject")]), (template_input, crop_image, [("norm_file", "in_file"), ("wmparc_file", "mask_file")]), (crop_image, zoom_image, [("out_file", "in_file")]), (zoom_image, reorient_image, [("out_file", "in_file")]), (subject_source, generate_reg, [("subject", "subject_id")]), (template_input, generate_reg, [("norm_file", "moving_image")]), (reorient_image, generate_reg, [("out_file", "target_image")]), (subject_source, invert_reg, [("subject", "subject_id")]), (template_input, invert_reg, [("norm_file", "target_image")]), (reorient_image, invert_reg, [("out_file", "moving_image")]), (hemi_source, tag_surf, [("hemi", "hemi")]), (invert_reg, tag_surf, [("reg_file", "reg_file")]), (reorient_image, tag_surf, [("out_file", "template_file")]), (template_input, mask_cortex, [("label_files", "label_files")]), (hemi_source, mask_cortex, [("hemi", "hemi")]), (tag_surf, mask_cortex, [("vertexvol_file", "in_file")]), (mask_cortex, combine_hemis, [("out_file", "in_files")]), (combine_hemis, make_ribbon, [("merged_file", "in_file")]), (reorient_image, transform_wmparc, [("out_file", "source_file")]), (template_input, transform_wmparc, [("wmparc_file", "target_file")]), (invert_reg, transform_wmparc, [("reg_file", "reg_file")]), (reorient_image, anat_segment, [("out_file", "anat_file")]), (transform_wmparc, anat_segment, [("transformed_file", "wmparc_file")]), (combine_hemis, anat_segment, [("merged_file", "surf_file")]), (template_input, template_output, [("output_path", "container")]), (reorient_image, template_output, [("out_file", "@anat")]), (generate_reg, template_output, [("fsl_file", "@anat2func")]), (anat_segment, template_output, [("seg_file", "@seg"), ("lut_file", "@lut"), ("edge_file", "@edge"), ("mask_file", "@mask")]), (combine_hemis, template_output, [("merged_file", "@surf")]), (make_ribbon, template_output, [("out_file", "@ribon")]), ] workflow.connect(processing_edges) # Optionally connect QC nodes qc_edges = [ (reorient_image, template_qc, [("out_file", "anat_file")]), (combine_hemis, template_qc, [("merged_file", "surf_file")]), (anat_segment, template_qc, [("lut_file", "lut_file"), ("seg_file", "seg_file"), ("edge_file", "edge_file"), ("mask_file", "mask_file")]), (subject_source, save_info, [("subject", "parameterization")]), (save_info, template_output, [("info_file", "qc.@info_json")]), (template_qc, template_output, [("seg_plot", "qc.@seg_plot"), ("mask_plot", "qc.@mask_plot"), ("edge_plot", "qc.@edge_plot"), ("surf_plot", "qc.@surf_plot"), ("anat_plot", "qc.@anat_plot")]), ] if qc: workflow.connect(qc_edges) return workflow
def get_fmri2standard_wf( tvols, subject_id, ACQ_PARAMS="/home/didac/LabScripts/fMRI_preprocess/acparams_hcp.txt"): """Estimates transformation from Gradiend Field Distortion-warped BOLD to T1 In general: BOLD is field-inhomogeneity corrected and corregistered into standard space (T1). To do so, the following steps are carried out: 1) Corregister SBref to SEgfmAP (fsl.FLIRT) 2) Realign BOLD to corrected SBref (fsl.MCFLIRT) 3) Field inhomogeneity correction estimation of SBref from SEfm_AP and SEfm_PA (fsl.TOPUP) 4) Apply field inhomogeneity correction to SBref (fsl.ApplyTOPUP) 5) Apply field inhomogeneity correction to BOLD (fsl.ApplyTOPUP) 6) Transform free-surfer brain mask (brain.mgz) to T1 space (freesurfer.ApplyVolTransform ;mri_vol2vol), then binarized (fsl.UnaryMaths) and the mask is extracted from T1 (fsl.BinaryMaths) 7) Corregister BOLD (field-inhomogeneity corrected) to Standard T1 (fsl.Epi2Reg) Parameters ---------- tvols: [t_initial, t_final] volumes included in the preprocess ACQ_params: Path to txt file containing MRI acquisition parameters; needs to be specified for topup correction Returns ------- Workflow with the transformation """ from nipype import Workflow, Node, interfaces from nipype.interfaces import fsl, utility, freesurfer print("defining workflow...") wf = Workflow(name=subject_id, base_dir='') #Setting INPUT node... print("defines input node...") node_input = Node(utility.IdentityInterface(fields=[ 'func_sbref_img', 'func_segfm_ap_img', 'func_segfm_pa_img', 'func_bold_ap_img', 'T1_img', 'T1_brain_freesurfer_mask' ]), name='input_node') print( "Averages the three repeated Spin-Echo images with same Phase Encoding (AP or PA) for Susceptibility Correction (unwarping)..." ) node_average_SEgfm = Node(fsl.maths.MeanImage(), name='Mean_SEgfm_AP') print("Corregister SB-ref to average SEgfm-AP") node_coregister_SBref2SEgfm = Node( fsl.FLIRT(dof=6 #translation and rotation only ), name='Corregister_SBref2SEgfm') print("Eliminates first volumes.") node_eliminate_first_scans = Node( fsl.ExtractROI( t_min=tvols[0], # first included volume t_size=tvols[1] - tvols[0], # number of volumes from the first to the last one ), name="eliminate_first_scans") print("Realigns fMRI BOLD volumes to SBref in SEgfm-AP space") node_realign_bold = Node( fsl.MCFLIRT( save_plots=True, # save transformation matrices ), name="realign_fmri2SBref") print("Concatenates AP and PA SEgfm volumes...") # AP AP AP PA PA PA node_merge_ap_pa_inputs = Node( utility.base.Merge(2 # number of inputs; it concatenates lists ), name='Merge_ap_pa_inputs') node_merge_SEgfm = Node( fsl.Merge(dimension='t' # ¿? ), name='Merge_SEgfm_AP_PA') print( "Estimates TopUp inhomogeneity correction from SEfm_AP and SEfm_PA...") node_topup_SEgfm = Node(fsl.TOPUP(encoding_file=ACQ_PARAMS, ), name='Topup_SEgfm_estimation') print("Applies warp from TOPUP to correct SBref...") node_apply_topup_to_SBref = Node( fsl.ApplyTOPUP( encoding_file=ACQ_PARAMS, method='jac', # jacobian modulation interp='spline', # interpolation method ), name="apply_topup_to_SBref") print("Applies warp from TOPUP to correct realigned BOLD...") node_apply_topup = Node( fsl.ApplyTOPUP( encoding_file=ACQ_PARAMS, method='jac', # jacobian modulation interp='spline', # interpolation method ), name="apply_topup") ## BRAIN MASK #Registration to T1. Epireg without fieldmaps combined (see https://www.fmrib.ox.ac.uk/primers/intro_primer/ExBox20/IntroBox20.html) # print ("Eliminates scalp from brain using T1 high res image"); # node_mask_T1=Node(fsl.BET( # frac=0.7 # umbral # ), # name="mask_T1"); print('Transform brain mask T1 from freesurfer space to T1 space') node_vol2vol_brain = Node( freesurfer.ApplyVolTransform( reg_header=True, # (--regheader) transformed_file='brainmask_warped.nii.gz' #source_file --mov (INPUT; freesurfer brain.mgz) #transformed_file --o (OUTPUT; ...brain.nii.gz) #target_file --targ (REFERENCE; ...T1w.nii.gz) ), name="vol2vol") print('Transform brain mask T1 to binary mask') node_bin_mask_brain = Node( fsl.UnaryMaths( # fslmaths T1_brain -bin T1_binarized mask operation='bin', # (-bin) #in_file (T1_brain) #out_file (T1_binarized_mask) ), name="binarize_mask") print('Extract brain mask from T1 using binary mask') node_extract_mask = Node( fsl. BinaryMaths( # fslmaths T1 -mul T1_binarized_mask T1_extracted_mask operation='mul' # (-mul) #in_file (T1) #out_file (T1_extracted_mask) #operand_file (T1_binarized_mask) ), name="extract_mask") ## print("Estimate and appply transformation from SBref to T1") node_epireg = Node( fsl.EpiReg( #t1_head=SUBJECT_FSTRUCT_DIC['anat_T1'], out_base='SEgfm2T1'), name="epi2reg") ''' EPI2REG ALREADY APPLIED print ("Apply epi2reg to SBRef.."); node_apply_epi2reg_SBref= Node(fsl.ApplyXFM( ), name="node_apply_epi2reg_SBref"); ''' print("Estimates inverse transform from epi2reg...") # quality control node_invert_epi2reg = Node(fsl.ConvertXFM(invert_xfm=True), name="invert_epi2reg") print("...") node_mask_fMRI = Node(fsl.BET(mask=True, ), name='mask_fMRI') #node_fmriMask.overwrite=True print("Setting OUTPUT node...") node_output = Node(interfaces.utility.IdentityInterface(fields=[ 'SBref2SEgfm_mat', 'realign_movpar_txt', 'realign_fmri_img', 'topup_movpar_txt', 'topup_field_coef_img', 'epi2str_mat', 'epi2str_img', 'fmri_mask_img', 'rfmri_unwarped_imgs', 'sb_ref_unwarped_img', ]), name='output_node') print("All nodes created; Starts creating connections") #Connects nodes wf.connect([ #inputs (node_input, node_average_SEgfm, [("func_segfm_ap_img", "in_file")]), (node_input, node_coregister_SBref2SEgfm, [("func_sbref_img", "in_file")]), (node_input, node_eliminate_first_scans, [("func_bold_ap_img", "in_file")]), (node_input, node_merge_ap_pa_inputs, [("func_segfm_ap_img", "in1"), ("func_segfm_pa_img", "in2")]), (node_merge_ap_pa_inputs, node_merge_SEgfm, [("out", "in_files")]), (node_input, node_epireg, [("T1_img", "t1_head")]), (node_input, node_vol2vol_brain, [("T1_brain_freesurfer_mask", "source_file")]), (node_input, node_vol2vol_brain, [("T1_img", "target_file")]), (node_input, node_extract_mask, [("T1_img", "in_file")]), #connections (node_eliminate_first_scans, node_realign_bold, [("roi_file", "in_file")]), (node_average_SEgfm, node_coregister_SBref2SEgfm, [("out_file", "reference")]), (node_coregister_SBref2SEgfm, node_realign_bold, [("out_file", "ref_file")]), #T1 brain mask transformations (change space / vol2vol, binarize and extract) (node_vol2vol_brain, node_bin_mask_brain, [("transformed_file", "in_file")]), (node_bin_mask_brain, node_extract_mask, [("out_file", "operand_file") ]), #(node_realign_bold, node_tsnr, [("out_file", "in_file")]), (node_merge_SEgfm, node_topup_SEgfm, [("merged_file", "in_file")]), (node_realign_bold, node_apply_topup, [("out_file", "in_files")]), (node_topup_SEgfm, node_apply_topup, [("out_fieldcoef", "in_topup_fieldcoef"), ("out_movpar", "in_topup_movpar")]), (node_topup_SEgfm, node_apply_topup_to_SBref, [("out_fieldcoef", "in_topup_fieldcoef"), ("out_movpar", "in_topup_movpar")]), (node_coregister_SBref2SEgfm, node_apply_topup_to_SBref, [("out_file", "in_files")]), #corregister to T1 (node_extract_mask, node_epireg, [("out_file", "t1_brain")]), (node_apply_topup_to_SBref, node_epireg, [("out_corrected", "epi")]), (node_epireg, node_invert_epi2reg, [("epi2str_mat", "in_file")]), (node_coregister_SBref2SEgfm, node_mask_fMRI, [("out_file", "in_file") ]), #yeld relevant data to output node (node_coregister_SBref2SEgfm, node_output, [("out_matrix_file", "SBref2SEgfm_mat")]), (node_realign_bold, node_output, [("par_file", "realign_movpar_txt"), ("out_file", "realign_fmri_img")]), (node_mask_fMRI, node_output, [("mask_file", "fmri_mask_img")]), (node_epireg, node_output, [("epi2str_mat", "epi2str_mat")]), (node_epireg, node_output, [("out_file", "epi2str_img")]), (node_topup_SEgfm, node_output, [("out_fieldcoef", "topup_field_coef_img"), ("out_corrected", "sb_ref_unwarped_img")]), (node_apply_topup, node_output, [("out_corrected", "rfmri_unwarped_imgs")]) ]) print("All connections created") return (wf)
# Register a source file to fs space and create a brain mask in source space # The node below creates the Freesurfer source fssource = pe.Node(nio.FreeSurferSource(), name='fssource') fssource.inputs.subject_id = f'sub-{sids[0]}' fssource.inputs.subjects_dir = fs_dir # Extract aparc+aseg brain mask, binarize, and dilate by 1 voxel fs_threshold = pe.Node(fs.Binarize(min=0.5, out_type='nii'), name='fs_threshold') fs_threshold.inputs.dilate = 1 psb6351_wf.connect(fssource, ('aparc_aseg', get_aparc_aseg), fs_threshold, 'in_file') # Transform the binarized aparc+aseg file to the EPI space # use a nearest neighbor interpolation fs_voltransform = pe.Node(fs.ApplyVolTransform(inverse=True), name='fs_transform') fs_voltransform.inputs.subjects_dir = fs_dir fs_voltransform.inputs.interp = 'nearest' psb6351_wf.connect(extractref, 'roi_file', fs_voltransform, 'source_file') psb6351_wf.connect(fs_register, 'out_reg_file', fs_voltransform, 'reg_file') psb6351_wf.connect(fs_threshold, 'binary_file', fs_voltransform, 'target_file') # Mask the functional runs with the extracted mask maskfunc = pe.MapNode(fsl.ImageMaths(suffix='_bet', op_string='-mas'), iterfield=['in_file'], name='maskfunc') psb6351_wf.connect(tshifter, 'out_file', maskfunc, 'in_file') psb6351_wf.connect(fs_voltransform, 'transformed_file', maskfunc, 'in_file2') # Smooth each run using SUSAn with the brightness threshold set to 75%
surfregister = pe.Node(interface=fs.BBRegister(), name='surfregister') surfregister.inputs.init = 'fsl' surfregister.inputs.contrast_type = 't2' """ Use :class:`nipype.interfaces.io.FreeSurferSource` to retrieve various image files that are automatically generated by the recon-all process. """ FreeSurferSource = pe.Node(interface=nio.FreeSurferSource(), name='fssource') """ Use :class:`nipype.interfaces.freesurfer.ApplyVolTransform` to convert the brainmask generated by freesurfer into the realigned functional space. """ ApplyVolTransform = pe.Node(interface=fs.ApplyVolTransform(), name='applyreg') ApplyVolTransform.inputs.inverse = True """ Use :class:`nipype.interfaces.freesurfer.Binarize` to extract a binary brain mask. """ Threshold = pe.Node(interface=fs.Binarize(), name='threshold') Threshold.inputs.min = 10 Threshold.inputs.out_type = 'nii' """ Two different types of functional data smoothing are performed in this workflow. The volume smoothing option performs a standard SPM smoothin. using :class:`nipype.interfaces.spm.Smooth`. In addition, we use a smoothing routine from freesurfer (:class:`nipype.interfaces.freesurfer.Binarize`) to project the functional data from the volume to the subjects' surface, smooth it on the
def create_getmask_flow(name='getmask', dilate_mask=True): """Registers a source file to freesurfer space and create a brain mask in source space Requires fsl tools for initializing registration Parameters ---------- name : string name of workflow dilate_mask : boolean indicates whether to dilate mask or not Example ------- >>> getmask = create_getmask_flow() >>> getmask.inputs.inputspec.source_file = 'mean.nii' >>> getmask.inputs.inputspec.subject_id = 's1' >>> getmask.inputs.inputspec.subjects_dir = '.' >>> getmask.inputs.inputspec.contrast_type = 't2' Inputs:: inputspec.source_file : reference image for mask generation inputspec.subject_id : freesurfer subject id inputspec.subjects_dir : freesurfer subjects directory inputspec.contrast_type : MR contrast of reference image Outputs:: outputspec.mask_file : binary mask file in reference image space outputspec.reg_file : registration file that maps reference image to freesurfer space outputspec.reg_cost : cost of registration (useful for detecting misalignment) """ import nipype.pipeline.engine as pe import nipype.interfaces.utility as niu import nipype.interfaces.freesurfer as fs import nipype.interfaces.io as nio """ Initialize the workflow """ getmask = pe.Workflow(name=name) """ Define the inputs to the workflow. """ inputnode = pe.Node(niu.IdentityInterface(fields=['source_file', 'subject_id', 'subjects_dir', 'contrast_type']), name='inputspec') """ Define all the nodes of the workflow: fssource: used to retrieve aseg.mgz threshold : binarize aseg register : coregister source file to freesurfer space voltransform: convert binarized aseg to source file space """ fssource = pe.Node(nio.FreeSurferSource(), name = 'fssource') threshold = pe.Node(fs.Binarize(min=0.5, out_type='nii'), name='threshold') register = pe.MapNode(fs.BBRegister(init='fsl'), iterfield=['source_file'], name='register') voltransform = pe.MapNode(fs.ApplyVolTransform(inverse=True), iterfield=['source_file', 'reg_file'], name='transform') """ Connect the nodes """ getmask.connect([ (inputnode, fssource, [('subject_id','subject_id'), ('subjects_dir','subjects_dir')]), (inputnode, register, [('source_file', 'source_file'), ('subject_id', 'subject_id'), ('subjects_dir', 'subjects_dir'), ('contrast_type', 'contrast_type')]), (inputnode, voltransform, [('subjects_dir', 'subjects_dir'), ('source_file', 'source_file')]), (fssource, threshold, [(('aparc_aseg', get_aparc_aseg), 'in_file')]), (register, voltransform, [('out_reg_file','reg_file')]), (threshold, voltransform, [('binary_file','target_file')]) ]) """ Add remaining nodes and connections dilate : dilate the transformed file in source space threshold2 : binarize transformed file """ threshold2 = pe.MapNode(fs.Binarize(min=0.5, out_type='nii'), iterfield=['in_file'], name='threshold2') if dilate_mask: threshold2.inputs.dilate = 1 getmask.connect([ (voltransform, threshold2, [('transformed_file', 'in_file')]) ]) """ Setup an outputnode that defines relevant inputs of the workflow. """ outputnode = pe.Node(niu.IdentityInterface(fields=["mask_file", "reg_file", "reg_cost" ]), name="outputspec") getmask.connect([ (register, outputnode, [("out_reg_file", "reg_file")]), (register, outputnode, [("min_cost_file", "reg_cost")]), (threshold2, outputnode, [("binary_file", "mask_file")]), ]) return getmask
def plot_epi_to_t1_coregistration(epi_file, reg_file, ribbon, fssubjects_dir): import pylab as plt from nipy.labs import viz import nibabel as nb import numpy as np import os import nipype.interfaces.freesurfer as fs anat = nb.load(ribbon).get_data() anat[anat > 1] = 1 anat_affine = nb.load(ribbon).get_affine() func = nb.load(epi_file).get_data() func_affine = nb.load(epi_file).get_affine() fig = plt.figure(figsize=(8, 6), edgecolor='k', facecolor='k') slicer = viz.plot_anat(np.asarray(func), np.asarray(func_affine), black_bg=True, cmap=plt.cm.spectral, cut_coords=(-6, 3, 12), figure=fig, axes=[0, .50, 1, .33]) slicer.contour_map(np.asarray(anat), np.asarray(anat_affine), levels=[.51], colors=[ 'r', ]) slicer.title( "Mean EPI with cortical surface contour overlay (before registration)", size=12, color='w', alpha=0) res = fs.ApplyVolTransform(source_file=epi_file, reg_file=reg_file, fs_target=True, subjects_dir=fssubjects_dir).run() func = nb.load(res.outputs.transformed_file).get_data() func_affine = nb.load(res.outputs.transformed_file).get_affine() slicer = viz.plot_anat(np.asarray(func), np.asarray(func_affine), black_bg=True, cmap=plt.cm.spectral, cut_coords=(-6, 3, 12), figure=fig, axes=[0, 0, 1, .33]) slicer.contour_map(np.asarray(anat), np.asarray(anat_affine), levels=[.51], colors=[ 'r', ]) slicer.title( "Mean EPI with cortical surface contour overlay (after registration)", size=12, color='w', alpha=0) plt.savefig("reg_plot.png", facecolor=fig.get_facecolor(), edgecolor='none') return os.path.abspath("reg_plot.png")
def run_dmriprep(dwi_file, bvec_file, bval_file, subjects_dir, working_dir, out_dir): """ Runs dmriprep for acquisitions with just one PE direction. """ from glob import glob import nibabel as nib import nipype.interfaces.freesurfer as fs import nipype.interfaces.fsl as fsl import nipype.interfaces.io as nio import nipype.interfaces.utility as niu import nipype.pipeline.engine as pe import numpy as np from nipype.algorithms.rapidart import ArtifactDetect from nipype.interfaces.dipy import DTI from nipype.interfaces.fsl.utils import AvScale from nipype.utils.filemanip import fname_presuffix from nipype.workflows.dmri.fsl.epi import create_dmri_preprocessing wf = create_dmri_preprocessing(name='dmriprep', use_fieldmap=False, fieldmap_registration=False) wf.inputs.inputnode.ref_num = 0 wf.inputs.inputnode.in_file = dwi_file wf.inputs.inputnode.in_bvec = bvec_file dwi_fname = op.split(dwi_file)[1].split(".nii.gz")[0] bids_sub_name = dwi_fname.split("_")[0] assert bids_sub_name.startswith("sub-") # inputnode = wf.get_node("inputnode") outputspec = wf.get_node("outputnode") # QC: FLIRT translation and rotation parameters flirt = wf.get_node("motion_correct.coregistration") # flirt.inputs.save_mats = True get_tensor = pe.Node(DTI(), name="dipy_tensor") wf.connect(outputspec, "dmri_corrected", get_tensor, "in_file") # wf.connect(inputspec2,"bvals", get_tensor, "in_bval") get_tensor.inputs.in_bval = bval_file wf.connect(outputspec, "bvec_rotated", get_tensor, "in_bvec") scale_tensor = pe.Node(name='scale_tensor', interface=fsl.BinaryMaths()) scale_tensor.inputs.operation = 'mul' scale_tensor.inputs.operand_value = 1000 wf.connect(get_tensor, 'out_file', scale_tensor, 'in_file') fslroi = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name="fslroi") wf.connect(outputspec, "dmri_corrected", fslroi, "in_file") bbreg = pe.Node(fs.BBRegister(contrast_type="t2", init="fsl", out_fsl_file=True, subjects_dir=subjects_dir, epi_mask=True), name="bbreg") # wf.connect(inputspec2,"fsid", bbreg,"subject_id") bbreg.inputs.subject_id = 'freesurfer' # bids_sub_name wf.connect(fslroi, "roi_file", bbreg, "source_file") voltransform = pe.Node(fs.ApplyVolTransform(inverse=True), iterfield=['source_file', 'reg_file'], name='transform') voltransform.inputs.subjects_dir = subjects_dir vt2 = voltransform.clone("transform_aparcaseg") vt2.inputs.interp = "nearest" def binarize_aparc(aparc_aseg): img = nib.load(aparc_aseg) data, aff = img.get_data(), img.affine outfile = fname_presuffix(aparc_aseg, suffix="bin.nii.gz", newpath=op.abspath("."), use_ext=False) nib.Nifti1Image((data > 0).astype(float), aff).to_filename(outfile) return outfile # wf.connect(inputspec2, "mask_nii", voltransform, "target_file") create_mask = pe.Node(niu.Function(input_names=["aparc_aseg"], output_names=["outfile"], function=binarize_aparc), name="bin_aparc") def get_aparc_aseg(subjects_dir, sub): return op.join(subjects_dir, sub, "mri", "aparc+aseg.mgz") create_mask.inputs.aparc_aseg = get_aparc_aseg(subjects_dir, 'freesurfer') wf.connect(create_mask, "outfile", voltransform, "target_file") wf.connect(fslroi, "roi_file", voltransform, "source_file") wf.connect(bbreg, "out_reg_file", voltransform, "reg_file") vt2.inputs.target_file = get_aparc_aseg(subjects_dir, 'freesurfer') # wf.connect(inputspec2, "aparc_aseg", vt2, "target_file") wf.connect(fslroi, "roi_file", vt2, "source_file") wf.connect(bbreg, "out_reg_file", vt2, "reg_file") # AK (2017): THIS NODE MIGHT NOT BE NECESSARY # AK (2018) doesn't know why she said that above.. threshold2 = pe.Node(fs.Binarize(min=0.5, out_type='nii.gz', dilate=1), iterfield=['in_file'], name='threshold2') wf.connect(voltransform, "transformed_file", threshold2, "in_file") # wf.connect(getmotion, "motion_params", datasink, "dti.@motparams") def get_flirt_motion_parameters(flirt_out_mats): def get_params(A): """This is a copy of spm's spm_imatrix where we already know the rotations and translations matrix, shears and zooms (as outputs from fsl FLIRT/avscale) Let A = the 4x4 rotation and translation matrix R = [ c5*c6, c5*s6, s5] [-s4*s5*c6-c4*s6, -s4*s5*s6+c4*c6, s4*c5] [-c4*s5*c6+s4*s6, -c4*s5*s6-s4*c6, c4*c5] """ def rang(b): a = min(max(b, -1), 1) return a Ry = np.arcsin(A[0, 2]) # Rx = np.arcsin(A[1, 2] / np.cos(Ry)) # Rz = np.arccos(A[0, 1] / np.sin(Ry)) if (abs(Ry) - np.pi / 2)**2 < 1e-9: Rx = 0 Rz = np.arctan2(-rang(A[1, 0]), rang(-A[2, 0] / A[0, 2])) else: c = np.cos(Ry) Rx = np.arctan2(rang(A[1, 2] / c), rang(A[2, 2] / c)) Rz = np.arctan2(rang(A[0, 1] / c), rang(A[0, 0] / c)) rotations = [Rx, Ry, Rz] translations = [A[0, 3], A[1, 3], A[2, 3]] return rotations, translations motion_params = open(op.abspath('motion_parameters.par'), 'w') for mat in flirt_out_mats: res = AvScale(mat_file=mat).run() A = np.asarray(res.outputs.rotation_translation_matrix) rotations, translations = get_params(A) for i in rotations + translations: motion_params.write('%f ' % i) motion_params.write('\n') motion_params.close() motion_params = op.abspath('motion_parameters.par') return motion_params getmotion = pe.Node(niu.Function(input_names=["flirt_out_mats"], output_names=["motion_params"], function=get_flirt_motion_parameters), name="get_motion_parameters", iterfield="flirt_out_mats") wf.connect(flirt, "out_matrix_file", getmotion, "flirt_out_mats") art = pe.Node(interface=ArtifactDetect(), name="art") art.inputs.use_differences = [True, True] art.inputs.save_plot = False art.inputs.use_norm = True art.inputs.norm_threshold = 3 art.inputs.zintensity_threshold = 9 art.inputs.mask_type = 'spm_global' art.inputs.parameter_source = 'FSL' wf.connect(getmotion, "motion_params", art, "realignment_parameters") wf.connect(outputspec, "dmri_corrected", art, "realigned_files") datasink = pe.Node(nio.DataSink(), name="sinker") datasink.inputs.base_directory = out_dir datasink.inputs.substitutions = [ ("vol0000_flirt_merged.nii.gz", dwi_fname + '.nii.gz'), ("stats.vol0000_flirt_merged.txt", dwi_fname + ".art.json"), ("motion_parameters.par", dwi_fname + ".motion.txt"), ("_rotated.bvec", ".bvec"), ("aparc+aseg_warped_out", dwi_fname.replace("_dwi", "_aparc+aseg")), ("art.vol0000_flirt_merged_outliers.txt", dwi_fname + ".outliers.txt"), ("vol0000_flirt_merged", dwi_fname), ("_roi_bbreg_freesurfer", "_register"), ("aparc+asegbin_warped_thresh", dwi_fname.replace("_dwi", "_mask")), ("derivatives/dmriprep", "derivatives/{}/dmriprep".format(bids_sub_name)) ] wf.connect(art, "statistic_files", datasink, "dmriprep.art.@artstat") wf.connect(art, "outlier_files", datasink, "dmriprep.art.@artoutlier") wf.connect(outputspec, "dmri_corrected", datasink, "dmriprep.dwi.@corrected") wf.connect(outputspec, "bvec_rotated", datasink, "dmriprep.dwi.@rotated") wf.connect(getmotion, "motion_params", datasink, "dmriprep.art.@motion") wf.connect(get_tensor, "out_file", datasink, "dmriprep.dti.@tensor") wf.connect(get_tensor, "fa_file", datasink, "dmriprep.dti.@fa") wf.connect(get_tensor, "md_file", datasink, "dmriprep.dti.@md") wf.connect(get_tensor, "ad_file", datasink, "dmriprep.dti.@ad") wf.connect(get_tensor, "rd_file", datasink, "dmriprep.dti.@rd") wf.connect(get_tensor, "out_file", datasink, "dmriprep.dti.@scaled_tensor") wf.connect(bbreg, "min_cost_file", datasink, "dmriprep.reg.@mincost") wf.connect(bbreg, "out_fsl_file", datasink, "dmriprep.reg.@fslfile") wf.connect(bbreg, "out_reg_file", datasink, "dmriprep.reg.@reg") wf.connect(threshold2, "binary_file", datasink, "dmriprep.anat.@mask") # wf.connect(vt2, "transformed_file", datasink, "dwi.@aparc_aseg") convert = pe.Node(fs.MRIConvert(out_type="niigz"), name="convert2nii") wf.connect(vt2, "transformed_file", convert, "in_file") wf.connect(convert, "out_file", datasink, "dmriprep.anat.@aparc_aseg") wf.base_dir = working_dir wf.run() copyfile( bval_file, op.join(out_dir, bids_sub_name, "dmriprep", "dwi", op.split(bval_file)[1])) dmri_corrected = glob(op.join(out_dir, '*/dmriprep/dwi', '*.nii.gz'))[0] bvec_rotated = glob(op.join(out_dir, '*/dmriprep/dwi', '*.bvec'))[0] bval_file = glob(op.join(out_dir, '*/dmriprep/dwi', '*.bval'))[0] art_file = glob(op.join(out_dir, '*/dmriprep/art', '*.art.json'))[0] motion_file = glob(op.join(out_dir, '*/dmriprep/art', '*.motion.txt'))[0] outlier_file = glob(op.join(out_dir, '*/dmriprep/art', '*.outliers.txt'))[0] return dmri_corrected, bvec_rotated, art_file, motion_file, outlier_file
def get_dmriprep_pe_workflow(): """Return the dmriprep (phase encoded) nipype workflow Parameters ---------- Returns ------- wf : nipype.pipeline.engine.Workflow Nipype dmriprep workflow Notes ----- This assumes that there are scans with phase-encode directions AP/PA for topup. """ import nipype.interfaces.freesurfer as fs import nipype.interfaces.fsl as fsl import nipype.interfaces.io as nio import nipype.interfaces.utility as niu import nipype.pipeline.engine as pe from nipype.interfaces.dipy import DTI from nipype.workflows.dmri.fsl.artifacts import all_fsl_pipeline inputspec = pe.Node(niu.IdentityInterface(fields=[ 'subject_id', 'dwi_file', 'dwi_file_ap', 'dwi_file_pa', 'bvec_file', 'bval_file', 'subjects_dir', 'out_dir', 'eddy_niter', 'slice_outlier_threshold' ]), name="inputspec") # AK: watch out, other datasets might be encoded LR epi_ap = {'echospacing': 66.5e-3, 'enc_dir': 'y-'} epi_pa = {'echospacing': 66.5e-3, 'enc_dir': 'y'} prep = all_fsl_pipeline(epi_params=epi_ap, altepi_params=epi_pa) # initialize an overall workflow wf = pe.Workflow(name="dmriprep") wf.connect(inputspec, 'dwi_file', prep, 'inputnode.in_file') wf.connect(inputspec, 'bvec_file', prep, 'inputnode.in_bvec') wf.connect(inputspec, 'bval_file', prep, 'inputnode.in_bval') wf.connect(inputspec, 'eddy_niter', prep, 'fsl_eddy.niter') eddy = prep.get_node('fsl_eddy') eddy.inputs.repol = True eddy.inputs.cnr_maps = True eddy.inputs.residuals = True import multiprocessing eddy.inputs.num_threads = multiprocessing.cpu_count() topup = prep.get_node('peb_correction.topup') topup.inputs.checksize = True applytopup = prep.get_node('peb_correction.unwarp') applytopup.inputs.checksize = True eddy.inputs.checksize = True eddy_quad = pe.Node(fsl.EddyQuad(verbose=True, checksize=True), name="eddy_quad") get_path = lambda x: x.split('.nii.gz')[0].split('_fix')[0] wf.connect(prep, ('fsl_eddy.out_corrected', get_path), eddy_quad, "base_name") wf.connect(inputspec, 'bval_file', eddy_quad, 'bval_file') wf.connect(prep, 'Rotate_Bvec.out_file', eddy_quad, 'bvec_file') wf.connect(prep, 'peb_correction.topup.out_field', eddy_quad, 'field') wf.connect(prep, 'gen_index.out_file', eddy_quad, 'idx_file') wf.connect(prep, 'peb_correction.topup.out_enc_file', eddy_quad, 'param_file') # need a mask file for eddy_quad. lets get it from the B0. def get_b0_mask_fn(b0_file): import nibabel as nib from nipype.utils.filemanip import fname_presuffix from dipy.segment.mask import median_otsu import os mask_file = fname_presuffix(b0_file, suffix="_mask", newpath=os.path.abspath('.')) img = nib.load(b0_file) data, aff = img.get_data(), img.affine _, mask = median_otsu(data, 2, 1) nib.Nifti1Image(mask.astype(float), aff).to_filename(mask_file) return mask_file def id_outliers_fn(outlier_report, threshold, dwi_file): """Get list of scans that exceed threshold for number of outliers Parameters ---------- outlier_report: string Path to the fsl_eddy outlier report threshold: int or float If threshold is an int, it is treated as number of allowed outlier slices. If threshold is a float between 0 and 1 (exclusive), it is treated the fraction of allowed outlier slices before we drop the whole volume. dwi_file: string Path to nii dwi file to determine total number of slices Returns ------- drop_scans: numpy.ndarray List of scan indices to drop """ import nibabel as nib import numpy as np import os.path as op import parse with open(op.abspath(outlier_report), 'r') as fp: lines = fp.readlines() p = parse.compile( "Slice {slice:d} in scan {scan:d} is an outlier with " "mean {mean_sd:f} standard deviations off, and mean " "squared {mean_sq_sd:f} standard deviations off.") outliers = [p.parse(l).named for l in lines] scans = {d['scan'] for d in outliers} def num_outliers(scan, outliers): return len([d for d in outliers if d['scan'] == scan]) if 0 < threshold < 1: img = nib.load(dwi_file) try: threshold *= img.header.get_n_slices() except nib.spatialimages.HeaderDataError: print( 'WARNING. We are not sure which dimension has the ' 'slices in this image. So we are using the 3rd dim.', img.shape) threshold *= img.shape[2] drop_scans = np.array( [s for s in scans if num_outliers(s, outliers) > threshold]) outpath = op.abspath("dropped_scans.txt") np.savetxt(outpath, drop_scans, fmt="%d") return drop_scans, outpath id_outliers_node = pe.Node(niu.Function( input_names=["outlier_report", "threshold", "dwi_file"], output_names=["drop_scans", "outpath"], function=id_outliers_fn), name="id_outliers_node") wf.connect(inputspec, 'dwi_file', id_outliers_node, 'dwi_file') wf.connect(inputspec, 'slice_outlier_threshold', id_outliers_node, 'threshold') wf.connect(prep, "fsl_eddy.out_outlier_report", id_outliers_node, "outlier_report") list_merge = pe.Node(niu.Merge(numinputs=2), name="list_merge") wf.connect(inputspec, 'dwi_file_ap', list_merge, 'in1') wf.connect(inputspec, 'dwi_file_pa', list_merge, 'in2') merge = pe.Node(fsl.Merge(dimension='t'), name="mergeAPPA") wf.connect(merge, 'merged_file', prep, 'inputnode.alt_file') wf.connect(list_merge, 'out', merge, 'in_files') fslroi = pe.Node(fsl.ExtractROI(t_min=0, t_size=1), name="fslroi") wf.connect(prep, "outputnode.out_file", fslroi, "in_file") b0mask_node = pe.Node(niu.Function(input_names=['b0_file'], output_names=['mask_file'], function=get_b0_mask_fn), name="getB0Mask") wf.connect(fslroi, 'roi_file', b0mask_node, 'b0_file') wf.connect(b0mask_node, 'mask_file', eddy_quad, 'mask_file') bbreg = pe.Node( fs.BBRegister( contrast_type="t2", init="coreg", out_fsl_file=True, # subjects_dir=subjects_dir, epi_mask=True), name="bbreg") bbreg.inputs.subject_id = 'freesurfer' # bids_sub_name wf.connect(fslroi, "roi_file", bbreg, "source_file") wf.connect(inputspec, 'subjects_dir', bbreg, 'subjects_dir') def drop_outliers_fn(in_file, in_bval, in_bvec, drop_scans): """Drop outlier volumes from dwi file Parameters ---------- in_file: string Path to nii dwi file to drop outlier volumes from in_bval: string Path to bval file to drop outlier volumes from in_bvec: string Path to bvec file to drop outlier volumes from drop_scans: numpy.ndarray List of scan indices to drop Returns ------- out_file: string Path to "thinned" output dwi file out_bval: string Path to "thinned" output bval file out_bvec: string Path to "thinned" output bvec file """ import nibabel as nib import numpy as np import os.path as op from nipype.utils.filemanip import fname_presuffix img = nib.load(op.abspath(in_file)) img_data = img.get_data() img_data_thinned = np.delete(img_data, drop_scans, axis=3) if isinstance(img, nib.nifti1.Nifti1Image): img_thinned = nib.Nifti1Image(img_data_thinned.astype(np.float64), img.affine, header=img.header) elif isinstance(img, nib.nifti2.Nifti2Image): img_thinned = nib.Nifti2Image(img_data_thinned.astype(np.float64), img.affine, header=img.header) else: raise TypeError("in_file does not contain Nifti image datatype.") out_file = fname_presuffix(in_file, suffix="_thinned", newpath=op.abspath('.')) nib.save(img_thinned, op.abspath(out_file)) bval = np.loadtxt(in_bval) bval_thinned = np.delete(bval, drop_scans, axis=0) out_bval = fname_presuffix(in_bval, suffix="_thinned", newpath=op.abspath('.')) np.savetxt(out_bval, bval_thinned) bvec = np.loadtxt(in_bvec) bvec_thinned = np.delete(bvec, drop_scans, axis=1) out_bvec = fname_presuffix(in_bvec, suffix="_thinned", newpath=op.abspath('.')) np.savetxt(out_bvec, bvec_thinned) return out_file, out_bval, out_bvec drop_outliers_node = pe.Node(niu.Function( input_names=["in_file", "in_bval", "in_bvec", "drop_scans"], output_names=["out_file", "out_bval", "out_bvec"], function=drop_outliers_fn), name="drop_outliers_node") # Align the output of drop_outliers_node & also the eddy corrected version to the anatomical space # without resampling. and then for aparc+aseg & the mask, resample to the larger voxel size of the B0 image from # fslroi. Also we need to apply the transformation to both bvecs (dropped & eddied) and I think we can just load # the affine from bbreg (sio.loadmat) and np.dot(coord, aff) for each coord in bvec def get_orig(subjects_dir, sub='freesurfer'): import os.path as op return op.join(subjects_dir, sub, "mri", "orig.mgz") def get_aparc_aseg(subjects_dir, sub='freesurfer'): import os.path as op return op.join(subjects_dir, sub, "mri", "aparc+aseg.mgz") # transform the dropped volume version to anat space w/ out resampling voltransform = pe.Node(fs.ApplyVolTransform(no_resample=True), iterfield=['source_file', 'reg_file'], name='transform') wf.connect(inputspec, 'subjects_dir', voltransform, 'subjects_dir') wf.connect(inputspec, ('subjects_dir', get_aparc_aseg), voltransform, 'target_file') wf.connect(prep, "outputnode.out_file", voltransform, "source_file") wf.connect(bbreg, "out_reg_file", voltransform, "reg_file") def apply_transform_to_bvecs_fn(bvec_file, reg_mat_file): import numpy as np import nipype.utils.filemanip as fm import os aff = np.loadtxt(reg_mat_file) bvecs = np.loadtxt(bvec_file) bvec_trans = [] for bvec in bvecs.T: coord = np.hstack((bvec, [1])) coord_trans = np.dot(coord, aff)[:-1] bvec_trans.append(coord_trans) out_bvec = fm.fname_presuffix(bvec_file, suffix="anat_space", newpath=os.path.abspath('.')) np.savetxt(out_bvec, np.asarray(bvec_trans).T) return out_bvec apply_transform_to_bvecs_node = pe.Node(niu.Function( input_names=['bvec_file', 'reg_mat_file'], output_names=['out_bvec'], function=apply_transform_to_bvecs_fn), name="applyTransformToBvecs") wf.connect(bbreg, 'out_fsl_file', apply_transform_to_bvecs_node, 'reg_mat_file') wf.connect(prep, 'outputnode.out_bvec', apply_transform_to_bvecs_node, 'bvec_file') # ok cool, now lets do the thresholding. wf.connect(id_outliers_node, "drop_scans", drop_outliers_node, "drop_scans") wf.connect(voltransform, "transformed_file", drop_outliers_node, "in_file") wf.connect(inputspec, 'bval_file', drop_outliers_node, 'in_bval') wf.connect(apply_transform_to_bvecs_node, "out_bvec", drop_outliers_node, "in_bvec") # lets compute the tensor on both the dropped volume scan # and also the original, eddy corrected one. get_tensor = pe.Node(DTI(), name="dipy_tensor") wf.connect(drop_outliers_node, "out_file", get_tensor, "in_file") wf.connect(drop_outliers_node, "out_bval", get_tensor, "in_bval") wf.connect(drop_outliers_node, "out_bvec", get_tensor, "in_bvec") get_tensor_eddy = get_tensor.clone('dipy_tensor_eddy') wf.connect(voltransform, 'transformed_file', get_tensor_eddy, "in_file") wf.connect(apply_transform_to_bvecs_node, 'out_bvec', get_tensor_eddy, "in_bvec") wf.connect(inputspec, 'bval_file', get_tensor_eddy, 'in_bval') # AK: What is this, some vestigal node from a previous workflow? # I'm not sure why the tensor gets scaled. but i guess lets scale it for # both the dropped & eddy corrected versions. scale_tensor = pe.Node(name='scale_tensor', interface=fsl.BinaryMaths()) scale_tensor.inputs.operation = 'mul' scale_tensor.inputs.operand_value = 1000 wf.connect(get_tensor, 'out_file', scale_tensor, 'in_file') scale_tensor_eddy = scale_tensor.clone('scale_tensor_eddy') wf.connect(get_tensor_eddy, 'out_file', scale_tensor_eddy, 'in_file') # OK now that anatomical stuff (segmentation & mask) # We'll need: # 1. the B0 image in anat space (fslroi the 'transformed file' of voltransform # 2. the aparc aseg resampled-like the B0 image (mri_convert) # 3. the resample aparc_aseg binarized to be the mask image. def binarize_aparc(aparc_aseg): import nibabel as nib from nipype.utils.filemanip import fname_presuffix import os.path as op img = nib.load(aparc_aseg) data, aff = img.get_data(), img.affine outfile = fname_presuffix(aparc_aseg, suffix="bin.nii.gz", newpath=op.abspath("."), use_ext=False) nib.Nifti1Image((data > 0).astype(float), aff).to_filename(outfile) return outfile create_mask = pe.Node(niu.Function(input_names=["aparc_aseg"], output_names=["outfile"], function=binarize_aparc), name="bin_aparc") get_b0_anat = fslroi.clone('get_b0_anat') wf.connect(voltransform, 'transformed_file', get_b0_anat, 'in_file') # reslice the anat-space aparc+aseg to the DWI resolution reslice_to_dwi = pe.Node(fs.MRIConvert(resample_type="nearest"), name="reslice_to_dwi") wf.connect(get_b0_anat, 'roi_file', reslice_to_dwi, 'reslice_like') wf.connect(inputspec, ('subjects_dir', get_aparc_aseg), reslice_to_dwi, 'in_file') # also reslice the orig i suppose reslice_orig_to_dwi = reslice_to_dwi.clone('resliceT1wToDwi') wf.connect(inputspec, ('subjects_dir', get_orig), reslice_orig_to_dwi, 'in_file') # reslice_orig_to_dwi.inputs.in_file = get_orig(subjects_dir, 'freesurfer') reslice_orig_to_dwi.inputs.out_type = 'niigz' wf.connect(get_b0_anat, 'roi_file', reslice_orig_to_dwi, 'reslice_like') # we assume the freesurfer is the output of BIDS # so the freesurfer output is in /path/to/derivatives/sub-whatever/freesurfer # which means the subject_dir is /path/to/derivatives/sub-whatever # reslice_to_dwi.inputs.in_file = get_aparc_aseg(subjects_dir, 'freesurfer') # now we have a nice aparc+aseg still in anat space but resliced like the dwi file # lets create a mask file from it. wf.connect(reslice_to_dwi, 'out_file', create_mask, 'aparc_aseg') # save all the things datasink = pe.Node(nio.DataSink(), name="sinker") wf.connect(inputspec, 'out_dir', datasink, 'base_directory') wf.connect(inputspec, 'subject_id', datasink, 'container') wf.connect(drop_outliers_node, "out_file", datasink, "dmriprep.dwi.@thinned") wf.connect(drop_outliers_node, "out_bval", datasink, "dmriprep.dwi.@bval_thinned") wf.connect(drop_outliers_node, "out_bvec", datasink, "dmriprep.dwi.@bvec_thinned") # eddy corrected files wf.connect(prep, "outputnode.out_file", datasink, "dmriprep.dwi_eddy.@corrected") wf.connect(prep, "outputnode.out_bvec", datasink, "dmriprep.dwi_eddy.@rotated") wf.connect(inputspec, 'bval_file', datasink, 'dmriprep.dwi_eddy.@bval') # all the eddy stuff except the corrected files wf.connect(prep, "fsl_eddy.out_movement_rms", datasink, "dmriprep.qc.@eddyparamsrms") wf.connect(prep, "fsl_eddy.out_outlier_report", datasink, "dmriprep.qc.@eddyparamsreport") wf.connect(prep, "fsl_eddy.out_restricted_movement_rms", datasink, "dmriprep.qc.@eddyparamsrestrictrms") wf.connect(prep, "fsl_eddy.out_shell_alignment_parameters", datasink, "dmriprep.qc.@eddyparamsshellalign") wf.connect(prep, "fsl_eddy.out_parameter", datasink, "dmriprep.qc.@eddyparams") wf.connect(prep, "fsl_eddy.out_cnr_maps", datasink, "dmriprep.qc.@eddycndr") wf.connect(prep, "fsl_eddy.out_residuals", datasink, "dmriprep.qc.@eddyresid") # the file that told us which volumes to drop wf.connect(id_outliers_node, "outpath", datasink, "dmriprep.qc.@droppedscans") # the tensors of the dropped volumes dwi wf.connect(get_tensor, "out_file", datasink, "dmriprep.dti.@tensor") wf.connect(get_tensor, "fa_file", datasink, "dmriprep.dti.@fa") wf.connect(get_tensor, "md_file", datasink, "dmriprep.dti.@md") wf.connect(get_tensor, "ad_file", datasink, "dmriprep.dti.@ad") wf.connect(get_tensor, "rd_file", datasink, "dmriprep.dti.@rd") wf.connect(get_tensor, "color_fa_file", datasink, "dmriprep.dti.@colorfa") wf.connect(scale_tensor, "out_file", datasink, "dmriprep.dti.@scaled_tensor") # the tensors of the eddied volumes dwi wf.connect(get_tensor_eddy, "out_file", datasink, "dmriprep.dti_eddy.@tensor") wf.connect(get_tensor_eddy, "fa_file", datasink, "dmriprep.dti_eddy.@fa") wf.connect(get_tensor_eddy, "md_file", datasink, "dmriprep.dti_eddy.@md") wf.connect(get_tensor_eddy, "ad_file", datasink, "dmriprep.dti_eddy.@ad") wf.connect(get_tensor_eddy, "rd_file", datasink, "dmriprep.dti_eddy.@rd") wf.connect(get_tensor_eddy, "color_fa_file", datasink, "dmriprep.dti_eddy.@colorfa") wf.connect(scale_tensor_eddy, "out_file", datasink, "dmriprep.dti_eddy.@scaled_tensor") # all the eddy_quad stuff wf.connect(eddy_quad, 'out_qc_json', datasink, "dmriprep.qc.@eddyquad_json") wf.connect(eddy_quad, 'out_qc_pdf', datasink, "dmriprep.qc.@eddyquad_pdf") wf.connect(eddy_quad, 'out_avg_b_png', datasink, "dmriprep.qc.@eddyquad_bpng") wf.connect(eddy_quad, 'out_avg_b0_pe_png', datasink, "dmriprep.qc.@eddyquad_b0png") wf.connect(eddy_quad, 'out_cnr_png', datasink, "dmriprep.qc.@eddyquad_cnr") wf.connect(eddy_quad, 'out_vdm_png', datasink, "dmriprep.qc.@eddyquad_vdm") wf.connect(eddy_quad, 'out_residuals', datasink, 'dmriprep.qc.@eddyquad_resid') # anatomical registration stuff wf.connect(bbreg, "min_cost_file", datasink, "dmriprep.reg.@mincost") wf.connect(bbreg, "out_fsl_file", datasink, "dmriprep.reg.@fslfile") wf.connect(bbreg, "out_reg_file", datasink, "dmriprep.reg.@reg") # anatomical files resliced wf.connect(reslice_to_dwi, 'out_file', datasink, 'dmriprep.anat.@segmentation') wf.connect(create_mask, 'outfile', datasink, 'dmriprep.anat.@mask') wf.connect(reslice_orig_to_dwi, 'out_file', datasink, 'dmriprep.anat.@T1w') def report_fn(dwi_corrected_file, eddy_rms, eddy_report, color_fa_file, anat_mask_file, outlier_indices, eddy_qc_file): from dmriprep.qc import create_report_json report = create_report_json(dwi_corrected_file, eddy_rms, eddy_report, color_fa_file, anat_mask_file, outlier_indices, eddy_qc_file) return report report_node = pe.Node(niu.Function(input_names=[ 'dwi_corrected_file', 'eddy_rms', 'eddy_report', 'color_fa_file', 'anat_mask_file', 'outlier_indices', 'eddy_qc_file' ], output_names=['report'], function=report_fn), name="reportJSON") # for the report, lets show the eddy corrected (full volume) image wf.connect(voltransform, "transformed_file", report_node, 'dwi_corrected_file') wf.connect(eddy_quad, 'out_qc_json', report_node, 'eddy_qc_file') # add the rms movement output from eddy wf.connect(prep, "fsl_eddy.out_movement_rms", report_node, 'eddy_rms') wf.connect(prep, "fsl_eddy.out_outlier_report", report_node, 'eddy_report') wf.connect(id_outliers_node, 'drop_scans', report_node, 'outlier_indices') # the mask file to check our registration, and the colorFA file go in the report wf.connect(create_mask, "outfile", report_node, 'anat_mask_file') wf.connect(get_tensor, "color_fa_file", report_node, 'color_fa_file') # save that report! wf.connect(report_node, 'report', datasink, 'dmriprep.report.@report') # this part is done last, to get the filenames *just right* # its super annoying. def name_files_nicely(dwi_file, subject_id): import os.path as op dwi_fname = op.split(dwi_file)[1].split(".nii.gz")[0] substitutions = [ ("vol0000_flirt_merged.nii.gz", dwi_fname + '.nii.gz'), ("stats.vol0000_flirt_merged.txt", dwi_fname + ".art.json"), ("motion_parameters.par", dwi_fname + ".motion.txt"), ("_rotated.bvec", ".bvec"), ("art.vol0000_flirt_merged_outliers.txt", dwi_fname + ".outliers.txt"), ("vol0000_flirt_merged", dwi_fname), ("_roi_bbreg_freesurfer", "_register"), ("dwi/eddy_corrected", "dwi/%s" % dwi_fname), ("dti/eddy_corrected", "dti/%s" % dwi_fname.replace("_dwi", "")), ("reg/eddy_corrected", "reg/%s" % dwi_fname.replace("_dwi", "")), ("aparc+aseg_outbin", dwi_fname.replace("_dwi", "_mask")), ("aparc+aseg_out", dwi_fname.replace("_dwi", "_aparc+aseg")), ("art.eddy_corrected_outliers", dwi_fname.replace("dwi", "outliers")), ("color_fa", "colorfa"), ("orig_out", dwi_fname.replace("_dwi", "_T1w")), ("stats.eddy_corrected", dwi_fname.replace("dwi", "artStats")), ("eddy_corrected.eddy_parameters", dwi_fname + ".eddy_parameters"), ("qc/eddy_corrected", "qc/" + dwi_fname), ("derivatives/dmriprep", "derivatives/{}/dmriprep".format(subject_id)), ("_rotatedanat_space_thinned", ""), ("_thinned", ""), ("eddy_corrected", dwi_fname), ("_warped", ""), ("_maths", "_scaled"), ("dropped_scans", dwi_fname.replace("_dwi", "_dwi_dropped_scans")), ("report.json", dwi_fname.replace("_dwi", "_dwi_report.json")) ] return substitutions node_name_files_nicely = pe.Node(niu.Function( input_names=['dwi_file', 'subject_id'], output_names=['substitutions'], function=name_files_nicely), name="name_files_nicely") wf.connect(inputspec, 'dwi_file', node_name_files_nicely, 'dwi_file') wf.connect(inputspec, 'subject_id', node_name_files_nicely, 'subject_id') wf.connect(node_name_files_nicely, 'substitutions', datasink, 'substitutions') return wf
def create_confound_removal_workflow(workflow_name="confound_removal"): inputnode = pe.Node(util.IdentityInterface( fields=["subject_id", "timeseries", "reg_file", "motion_parameters"]), name="inputs") # Get the Freesurfer aseg volume from the Subjects Directory getaseg = pe.Node(io.FreeSurferSource(subjects_dir=fs.Info.subjectsdir()), name="getaseg") # Binarize the Aseg to use as a whole brain mask asegmask = pe.Node(fs.Binarize(min=0.5, dilate=2), name="asegmask") # Extract and erode a mask of the deep cerebral white matter extractwm = pe.Node(fs.Binarize(match=[2, 41], erode=3), name="extractwm") # Extract and erode a mask of the ventricles and CSF extractcsf = pe.Node(fs.Binarize(match=[4, 5, 14, 15, 24, 31, 43, 44, 63], erode=1), name="extractcsf") # Mean the timeseries across the fourth dimension meanfunc = pe.MapNode(fsl.MeanImage(), iterfield=["in_file"], name="meanfunc") # Invert the anatomical coregistration and resample the masks regwm = pe.MapNode(fs.ApplyVolTransform(inverse=True, interp="nearest"), iterfield=["source_file", "reg_file"], name="regwm") regcsf = pe.MapNode(fs.ApplyVolTransform(inverse=True, interp="nearest"), iterfield=["source_file", "reg_file"], name="regcsf") regbrain = pe.MapNode(fs.ApplyVolTransform(inverse=True, interp="nearest"), iterfield=["source_file", "reg_file"], name="regbrain") # Convert to Nifti for FSL tools convertwm = pe.MapNode(fs.MRIConvert(out_type="niigz"), iterfield=["in_file"], name="convertwm") convertcsf = pe.MapNode(fs.MRIConvert(out_type="niigz"), iterfield=["in_file"], name="convertcsf") convertbrain = pe.MapNode(fs.MRIConvert(out_type="niigz"), iterfield=["in_file"], name="convertbrain") # Add the mask images together for a report image addconfmasks = pe.MapNode(fsl.ImageMaths(suffix="conf", op_string="-mul 2 -add", out_data_type="char"), iterfield=["in_file", "in_file2"], name="addconfmasks") # Overlay and slice the confound mask overlaied on mean func for reporting confoverlay = pe.MapNode(fsl.Overlay(auto_thresh_bg=True, stat_thresh=(.7, 2)), iterfield=["background_image", "stat_image"], name="confoverlay") confslice = pe.MapNode(fsl.Slicer(image_width=800, label_slices=False), iterfield=["in_file"], name="confslice") confslice.inputs.sample_axial = 2 # Extract the mean signal from white matter and CSF masks wmtcourse = pe.MapNode(fs.SegStats(exclude_id=0, avgwf_txt_file=True), iterfield=["segmentation_file", "in_file"], name="wmtcourse") csftcourse = pe.MapNode(fs.SegStats(exclude_id=0, avgwf_txt_file=True), iterfield=["segmentation_file", "in_file"], name="csftcourse") # Extract the mean signal from over the whole brain globaltcourse = pe.MapNode(fs.SegStats(exclude_id=0, avgwf_txt_file=True), iterfield=["segmentation_file", "in_file"], name="globaltcourse") # Build the confound design matrix conf_inputs = [ "motion_params", "global_waveform", "wm_waveform", "csf_waveform" ] confmatrix = pe.MapNode(util.Function(input_names=conf_inputs, output_names=["confound_matrix"], function=make_confound_matrix), iterfield=conf_inputs, name="confmatrix") # Regress the confounds out of the timeseries confregress = pe.MapNode(fsl.FilterRegressor(filter_all=True), iterfield=["in_file", "design_file", "mask"], name="confregress") # Rename the confound mask png renamepng = pe.MapNode(util.Rename(format_string="confound_sources.png"), iterfield=["in_file"], name="renamepng") # Define the outputs outputnode = pe.Node( util.IdentityInterface(fields=["timeseries", "confound_sources"]), name="outputs") # Define and connect the confound workflow confound = pe.Workflow(name=workflow_name) confound.connect([ (inputnode, meanfunc, [("timeseries", "in_file")]), (inputnode, getaseg, [("subject_id", "subject_id")]), (getaseg, extractwm, [("aseg", "in_file")]), (getaseg, extractcsf, [("aseg", "in_file")]), (getaseg, asegmask, [("aseg", "in_file")]), (extractwm, regwm, [("binary_file", "target_file")]), (extractcsf, regcsf, [("binary_file", "target_file")]), (asegmask, regbrain, [("binary_file", "target_file")]), (meanfunc, regwm, [("out_file", "source_file")]), (meanfunc, regcsf, [("out_file", "source_file")]), (meanfunc, regbrain, [("out_file", "source_file")]), (inputnode, regwm, [("reg_file", "reg_file")]), (inputnode, regcsf, [("reg_file", "reg_file")]), (inputnode, regbrain, [("reg_file", "reg_file")]), (regwm, convertwm, [("transformed_file", "in_file")]), (regcsf, convertcsf, [("transformed_file", "in_file")]), (regbrain, convertbrain, [("transformed_file", "in_file")]), (convertwm, addconfmasks, [("out_file", "in_file")]), (convertcsf, addconfmasks, [("out_file", "in_file2")]), (addconfmasks, confoverlay, [("out_file", "stat_image")]), (meanfunc, confoverlay, [("out_file", "background_image")]), (confoverlay, confslice, [("out_file", "in_file")]), (confslice, renamepng, [("out_file", "in_file")]), (regwm, wmtcourse, [("transformed_file", "segmentation_file")]), (inputnode, wmtcourse, [("timeseries", "in_file")]), (regcsf, csftcourse, [("transformed_file", "segmentation_file")]), (inputnode, csftcourse, [("timeseries", "in_file")]), (regbrain, globaltcourse, [("transformed_file", "segmentation_file")]), (inputnode, globaltcourse, [("timeseries", "in_file")]), (inputnode, confmatrix, [("motion_parameters", "motion_params")]), (wmtcourse, confmatrix, [("avgwf_txt_file", "wm_waveform")]), (csftcourse, confmatrix, [("avgwf_txt_file", "csf_waveform")]), (globaltcourse, confmatrix, [("avgwf_txt_file", "global_waveform")]), (confmatrix, confregress, [("confound_matrix", "design_file")]), (inputnode, confregress, [("timeseries", "in_file")]), (convertbrain, confregress, [("out_file", "mask")]), (confregress, outputnode, [("out_file", "timeseries")]), (renamepng, outputnode, [("out_file", "confound_sources")]), ]) return confound
def create_spm_preproc(c, name='preproc'): """ """ from nipype.workflows.smri.freesurfer.utils import create_getmask_flow import nipype.algorithms.rapidart as ra import nipype.interfaces.spm as spm import nipype.interfaces.utility as niu import nipype.pipeline.engine as pe import nipype.interfaces.io as nio import nipype.interfaces.freesurfer as fs workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=[ 'functionals', 'subject_id', 'subjects_dir', 'fwhm', 'norm_threshold', 'zintensity_threshold', 'tr', 'do_slicetime', 'sliceorder', 'parameters', 'node', 'csf_prob', 'wm_prob', 'gm_prob' ]), name='inputspec') poplist = lambda x: x.pop() sym_func = pe.Node(niu.Function(input_names=['in_file'], output_names=['out_link'], function=do_symlink), name='func_symlink') # REALIGN realign = pe.Node(niu.Function( input_names=[ 'node', 'in_file', 'tr', 'do_slicetime', 'sliceorder', 'parameters' ], output_names=['out_file', 'par_file', 'parameter_source'], function=mod_realign), name="mod_realign") workflow.connect(inputnode, 'parameters', realign, 'parameters') workflow.connect(inputnode, 'functionals', realign, 'in_file') workflow.connect(inputnode, 'tr', realign, 'tr') workflow.connect(inputnode, 'do_slicetime', realign, 'do_slicetime') workflow.connect(inputnode, 'sliceorder', realign, 'sliceorder') workflow.connect(inputnode, 'node', realign, 'node') # TAKE MEAN IMAGE mean = art_mean_workflow() workflow.connect(realign, 'out_file', mean, 'inputspec.realigned_files') workflow.connect(realign, 'par_file', mean, 'inputspec.realignment_parameters') workflow.connect(realign, 'parameter_source', mean, 'inputspec.parameter_source') # CREATE BRAIN MASK maskflow = create_getmask_flow() workflow.connect([(inputnode, maskflow, [('subject_id', 'inputspec.subject_id'), ('subjects_dir', 'inputspec.subjects_dir')])]) maskflow.inputs.inputspec.contrast_type = 't2' workflow.connect(mean, 'outputspec.mean_image', maskflow, 'inputspec.source_file') # SEGMENT segment = pe.Node(spm.Segment(csf_output_type=[True, True, False], gm_output_type=[True, True, False], wm_output_type=[True, True, False]), name='segment') mergefunc = lambda in1, in2, in3: [in1, in2, in3] merge = pe.Node(niu.Function(input_names=['in1', 'in2', 'in3'], output_names=['out'], function=mergefunc), name='merge') workflow.connect(inputnode, 'csf_prob', merge, 'in3') workflow.connect(inputnode, 'wm_prob', merge, 'in2') workflow.connect(inputnode, 'gm_prob', merge, 'in1') sym_prob = sym_func workflow.connect(merge, 'out', sym_prob, 'in_file') workflow.connect(sym_prob, 'out_link', segment, 'tissue_prob_maps') xform_mask = pe.Node(fs.ApplyVolTransform(fs_target=True), name='transform_mask') workflow.connect(maskflow, ('outputspec.reg_file', pickfirst), xform_mask, 'reg_file') workflow.connect(maskflow, ('outputspec.mask_file', pickfirst), xform_mask, 'source_file') workflow.connect(xform_mask, "transformed_file", segment, 'mask_image') fssource = maskflow.get_node('fssource') convert2nii = pe.Node(fs.MRIConvert(in_type='mgz', out_type='nii'), name='convert2nii') workflow.connect(fssource, 'brain', convert2nii, 'in_file') workflow.connect(convert2nii, 'out_file', segment, 'data') # NORMALIZE normalize = pe.MapNode(spm.Normalize(jobtype='write'), name='normalize', iterfield=['apply_to_files']) normalize_struct = normalize.clone('normalize_struct') normalize_mask = normalize.clone('normalize_mask') workflow.connect(segment, 'transformation_mat', normalize, 'parameter_file') workflow.connect(segment, 'transformation_mat', normalize_mask, 'parameter_file') workflow.connect(segment, 'transformation_mat', normalize_struct, 'parameter_file') workflow.connect(convert2nii, 'out_file', normalize_struct, 'apply_to_files') workflow.connect(xform_mask, "transformed_file", normalize_mask, 'apply_to_files') xform_image = pe.MapNode(fs.ApplyVolTransform(fs_target=True), name='xform_image', iterfield=['source_file']) workflow.connect(maskflow, ('outputspec.reg_file', pickfirst), xform_image, 'reg_file') workflow.connect(realign, 'out_file', xform_image, "source_file") workflow.connect(xform_image, "transformed_file", normalize, "apply_to_files") #SMOOTH smooth = pe.Node(spm.Smooth(), name='smooth') workflow.connect(inputnode, 'fwhm', smooth, 'fwhm') workflow.connect(normalize, 'normalized_files', smooth, 'in_files') # ART artdetect = pe.Node(ra.ArtifactDetect(mask_type='file', use_differences=[True, False], use_norm=True, save_plot=True), name='artdetect') workflow.connect(realign, 'parameter_source', artdetect, 'parameter_source') workflow.connect([(inputnode, artdetect, [('norm_threshold', 'norm_threshold'), ('zintensity_threshold', 'zintensity_threshold')])]) workflow.connect([(realign, artdetect, [('out_file', 'realigned_files'), ('par_file', 'realignment_parameters')])]) workflow.connect(maskflow, ('outputspec.mask_file', poplist), artdetect, 'mask_file') # OUTPUTS outputnode = pe.Node(niu.IdentityInterface(fields=[ "realignment_parameters", "smoothed_files", "mask_file", "mean_image", "reg_file", "reg_cost", 'outlier_files', 'outlier_stats', 'outlier_plots', 'norm_components', 'mod_csf', 'unmod_csf', 'mod_wm', 'unmod_wm', 'mod_gm', 'unmod_gm', 'mean', 'normalized_struct', 'normalization_parameters', 'reverse_normalize_parameters' ]), name="outputspec") workflow.connect([ (maskflow, outputnode, [("outputspec.reg_file", "reg_file")]), (maskflow, outputnode, [("outputspec.reg_cost", "reg_cost")]), (realign, outputnode, [('par_file', 'realignment_parameters')]), (smooth, outputnode, [('smoothed_files', 'smoothed_files')]), (artdetect, outputnode, [('outlier_files', 'outlier_files'), ('statistic_files', 'outlier_stats'), ('plot_files', 'outlier_plots'), ('norm_files', 'norm_components')]) ]) workflow.connect(normalize_mask, "normalized_files", outputnode, "mask_file") workflow.connect(segment, 'modulated_csf_image', outputnode, 'mod_csf') workflow.connect(segment, 'modulated_wm_image', outputnode, 'mod_wm') workflow.connect(segment, 'modulated_gm_image', outputnode, 'mod_gm') workflow.connect(segment, 'normalized_csf_image', outputnode, 'unmod_csf') workflow.connect(segment, 'normalized_wm_image', outputnode, 'unmod_wm') workflow.connect(segment, 'normalized_gm_image', outputnode, 'unmod_gm') workflow.connect(mean, 'outputspec.mean_image', outputnode, 'mean') workflow.connect(normalize_struct, 'normalized_files', outputnode, 'normalized_struct') workflow.connect(segment, 'transformation_mat', outputnode, 'normalization_parameters') workflow.connect(segment, 'inverse_transformation_mat', outputnode, 'reverse_normalize_parameters') # CONNECT TO CONFIG workflow.inputs.inputspec.fwhm = c.fwhm workflow.inputs.inputspec.subjects_dir = c.surf_dir workflow.inputs.inputspec.norm_threshold = c.norm_thresh workflow.inputs.inputspec.zintensity_threshold = c.z_thresh workflow.inputs.inputspec.node = c.motion_correct_node workflow.inputs.inputspec.tr = c.TR workflow.inputs.inputspec.do_slicetime = c.do_slicetiming workflow.inputs.inputspec.sliceorder = c.SliceOrder workflow.inputs.inputspec.csf_prob = c.csf_prob workflow.inputs.inputspec.gm_prob = c.grey_prob workflow.inputs.inputspec.wm_prob = c.white_prob workflow.inputs.inputspec.parameters = {"order": c.order} workflow.base_dir = c.working_dir workflow.config = {'execution': {'crashdump_dir': c.crash_dir}} datagrabber = get_dataflow(c) workflow.connect(datagrabber, 'func', inputnode, 'functionals') infosource = pe.Node(niu.IdentityInterface(fields=['subject_id']), name='subject_names') if not c.test_mode: infosource.iterables = ('subject_id', c.subjects) else: infosource.iterables = ('subject_id', c.subjects[:1]) workflow.connect(infosource, 'subject_id', inputnode, 'subject_id') workflow.connect(infosource, 'subject_id', datagrabber, 'subject_id') sub = lambda x: [('_subject_id_%s' % x, '')] sinker = pe.Node(nio.DataSink(), name='sinker') workflow.connect(infosource, 'subject_id', sinker, 'container') workflow.connect(infosource, ('subject_id', sub), sinker, 'substitutions') sinker.inputs.base_directory = c.sink_dir outputspec = workflow.get_node('outputspec') workflow.connect(outputspec, 'realignment_parameters', sinker, 'spm_preproc.realignment_parameters') workflow.connect(outputspec, 'smoothed_files', sinker, 'spm_preproc.smoothed_outputs') workflow.connect(outputspec, 'outlier_files', sinker, 'spm_preproc.art.@outlier_files') workflow.connect(outputspec, 'outlier_stats', sinker, 'spm_preproc.art.@outlier_stats') workflow.connect(outputspec, 'outlier_plots', sinker, 'spm_preproc.art.@outlier_plots') workflow.connect(outputspec, 'norm_components', sinker, 'spm_preproc.art.@norm') workflow.connect(outputspec, 'reg_file', sinker, 'spm_preproc.bbreg.@reg_file') workflow.connect(outputspec, 'reg_cost', sinker, 'spm_preproc.bbreg.@reg_cost') workflow.connect(outputspec, 'mask_file', sinker, 'spm_preproc.mask.@mask_file') workflow.connect(outputspec, 'mod_csf', sinker, 'spm_preproc.segment.mod.@csf') workflow.connect(outputspec, 'mod_wm', sinker, 'spm_preproc.segment.mod.@wm') workflow.connect(outputspec, 'mod_gm', sinker, 'spm_preproc.segment.mod.@gm') workflow.connect(outputspec, 'unmod_csf', sinker, 'spm_preproc.segment.unmod.@csf') workflow.connect(outputspec, 'unmod_wm', sinker, 'spm_preproc.segment.unmod.@wm') workflow.connect(outputspec, 'unmod_gm', sinker, 'spm_preproc.segment.unmod.@gm') workflow.connect(outputspec, 'mean', sinker, 'spm_preproc.mean') workflow.connect(outputspec, 'normalized_struct', sinker, 'spm_preproc.normalized_struct') workflow.connect(outputspec, 'normalization_parameters', sinker, 'spm_preproc.normalization_parameters.@forward') workflow.connect(outputspec, 'reverse_normalize_parameters', sinker, 'spm_preproc.normalization_parameters.@reverse') return workflow
preproc_wf.connect(coregister, 'out_fsl_file', outputspec, 'fsl_reg_file') preproc_wf.connect(coregister, 'min_cost_file', outputspec, 'reg_cost') # Register a source file to fs space fssource = pe.Node(nio.FreeSurferSource(subjects_dir=subjects_dir), name='fssource') preproc_wf.connect(subj_iterable, 'subject_id', fssource, 'subject_id') # Extract aparc+aseg brain mask and binarize fs_threshold = pe.Node(fs.Binarize(min=0.5, out_type='nii'), name='fs_threshold') preproc_wf.connect(fssource, ('aparc_aseg', get_aparc_aseg), fs_threshold, 'in_file') # Transform the binarized aparc+aseg file to the 1st volume of 1st run space fs_voltransform = pe.MapNode(fs.ApplyVolTransform(inverse=True, subjects_dir=subjects_dir), iterfield=['source_file', 'reg_file'], name='fs_transform') preproc_wf.connect(extractref, 'roi_file', fs_voltransform, 'source_file') preproc_wf.connect(coregister, 'out_reg_file', fs_voltransform, 'reg_file') preproc_wf.connect(fs_threshold, 'binary_file', fs_voltransform, 'target_file') # Dilate the binarized mask by 1 voxel that is now in the EPI space fs_threshold2 = pe.MapNode(fs.Binarize(min=0.5, out_type='nii', dilate=1), iterfield=['in_file'], name='fs_threshold2') preproc_wf.connect(fs_voltransform, 'transformed_file', fs_threshold2, 'in_file') preproc_wf.connect(fs_threshold2, 'binary_file', outputspec, 'mask_file') # Mask the functional runs with the extracted mask
# Transform right hemisphere surf2volNode_rh = surf2volNode_lh.clone('surf2vol_rh') surf2volNode_rh.inputs.hemi = 'rh' # Merge the hemispheres mergeHemisNode = Node(fsl.BinaryMaths(), name='mergeHemis') mergeHemisNode.inputs.operation = 'add' mergeHemisNode.inputs.output_type = 'NIFTI_GZ' # ### Registration # In[ ]: # Rotate high-res (1mm) WM-border to match dwi data w/o resampling applyReg_anat2diff_1mm = Node(freesurfer.ApplyVolTransform(), name='wmoutline2diff_1mm') applyReg_anat2diff_1mm.inputs.inverse = True applyReg_anat2diff_1mm.inputs.interp = 'nearest' applyReg_anat2diff_1mm.inputs.no_resample = True applyReg_anat2diff_1mm.inputs.args = '--no-save-reg' # Rotate high-res (1mm) WM-border to match dwi data with resampling applyReg_anat2diff = applyReg_anat2diff_1mm.clone('wmoutline2diff') applyReg_anat2diff.inputs.no_resample = False applyReg_anat2diff.inputs.interp = 'trilin' # Filter out low voxels produced by trilin. interp. thresholdNode = Node(fsl.maths.Threshold(), name='remove_interp_residuals') thresholdNode.inputs.thresh = 0.1 thresholdNode.inputs.output_type = 'NIFTI_GZ'
def create_spm_preproc(c, name='preproc'): """Create an spm preprocessing workflow with freesurfer registration and artifact detection. The workflow realigns and smooths and registers the functional images with the subject's freesurfer space. Example ------- >>> preproc = create_spm_preproc() >>> preproc.base_dir = '.' >>> preproc.inputs.inputspec.fwhm = 6 >>> preproc.inputs.inputspec.subject_id = 's1' >>> preproc.inputs.inputspec.subjects_dir = '.' >>> preproc.inputs.inputspec.functionals = ['f3.nii', 'f5.nii'] >>> preproc.inputs.inputspec.norm_threshold = 1 >>> preproc.inputs.inputspec.zintensity_threshold = 3 Inputs:: inputspec.functionals : functional runs use 4d nifti inputspec.subject_id : freesurfer subject id inputspec.subjects_dir : freesurfer subjects dir inputspec.fwhm : smoothing fwhm inputspec.norm_threshold : norm threshold for outliers inputspec.zintensity_threshold : intensity threshold in z-score Outputs:: outputspec.realignment_parameters : realignment parameter files outputspec.smoothed_files : smoothed functional files outputspec.outlier_files : list of outliers outputspec.outlier_stats : statistics of outliers outputspec.outlier_plots : images of outliers outputspec.mask_file : binary mask file in reference image space outputspec.reg_file : registration file that maps reference image to freesurfer space outputspec.reg_cost : cost of registration (useful for detecting misalignment) """ from nipype.workflows.smri.freesurfer.utils import create_getmask_flow import nipype.algorithms.rapidart as ra import nipype.interfaces.spm as spm import nipype.interfaces.utility as niu import nipype.pipeline.engine as pe import nipype.interfaces.io as nio """ Initialize the workflow """ workflow = pe.Workflow(name=name) """ Define the inputs to this workflow """ inputnode = pe.Node(niu.IdentityInterface(fields=[ 'functionals', 'subject_id', 'subjects_dir', 'fwhm', 'norm_threshold', 'zintensity_threshold', 'tr', 'do_slicetime', 'sliceorder', 'node', 'csf_prob', 'wm_prob', 'gm_prob' ]), name='inputspec') """ Setup the processing nodes and create the mask generation and coregistration workflow """ poplist = lambda x: x.pop() #realign = pe.Node(spm.Realign(), name='realign') sym_func = pe.Node(niu.Function(input_names=['in_file'], output_names=['out_link'], function=do_symlink), name='func_symlink') realign = pe.Node(niu.Function( input_names=['node', 'in_file', 'tr', 'do_slicetime', 'sliceorder'], output_names=['out_file', 'par_file'], function=mod_realign), name="mod_realign") mean = art_mean_workflow() workflow.connect(realign, 'out_file', mean, 'inputspec.realigned_files') workflow.connect(realign, 'par_file', mean, 'inputspec.realignment_parameters') mean.inputs.inputspec.parameter_source = 'FSL' # Modular realign puts it in FSL format for consistency #workflow.connect(inputnode, 'functionals', realign, 'in_file') workflow.connect(inputnode, 'functionals', sym_func, 'in_file') workflow.connect(sym_func, 'out_link', realign, 'in_file') workflow.connect(inputnode, 'tr', realign, 'tr') workflow.connect(inputnode, 'do_slicetime', realign, 'do_slicetime') workflow.connect(inputnode, 'sliceorder', realign, 'sliceorder') workflow.connect(inputnode, 'node', realign, 'node') maskflow = create_getmask_flow() workflow.connect([(inputnode, maskflow, [('subject_id', 'inputspec.subject_id'), ('subjects_dir', 'inputspec.subjects_dir')])]) maskflow.inputs.inputspec.contrast_type = 't2' workflow.connect(mean, 'outputspec.mean_image', maskflow, 'inputspec.source_file') smooth = pe.Node(spm.Smooth(), name='smooth') normalize = pe.Node(spm.Normalize(jobtype='write'), name='normalize') normalize_struct = normalize.clone('normalize_struct') segment = pe.Node(spm.Segment(csf_output_type=[True, True, False], gm_output_type=[True, True, False], wm_output_type=[True, True, False]), name='segment') mergefunc = lambda in1, in2, in3: [in1, in2, in3] # merge = pe.Node(niu.Merge(),name='merge') merge = pe.Node(niu.Function(input_names=['in1', 'in2', 'in3'], output_names=['out'], function=mergefunc), name='merge') workflow.connect(inputnode, 'csf_prob', merge, 'in3') workflow.connect(inputnode, 'wm_prob', merge, 'in2') workflow.connect(inputnode, 'gm_prob', merge, 'in1') #workflow.connect(merge,'out', segment,'tissue_prob_maps') sym_prob = sym_func.clone('sym_prob') workflow.connect(merge, 'out', sym_prob, 'in_file') workflow.connect(sym_prob, 'out_link', segment, 'tissue_prob_maps') workflow.connect(maskflow, ('outputspec.mask_file', pickfirst), segment, 'mask_image') workflow.connect(inputnode, 'fwhm', smooth, 'fwhm') #sym_brain = sym_func.clone('sym_brain') #workflow.connect(realign, 'mean_image', normalize, 'source') #workflow.connect(maskflow,'fssource.brain',segment,'data') fssource = maskflow.get_node('fssource') import nipype.interfaces.freesurfer as fs convert_brain = pe.Node(interface=fs.ApplyVolTransform(inverse=True), name='convert') workflow.connect(fssource, 'brain', convert_brain, 'target_file') workflow.connect(maskflow, ('outputspec.reg_file', pickfirst), convert_brain, 'reg_file') workflow.connect(mean, 'outputspec.mean_image', convert_brain, 'source_file') convert2nii = pe.Node(fs.MRIConvert(in_type='mgz', out_type='nii'), name='convert2nii') workflow.connect(convert_brain, 'transformed_file', convert2nii, 'in_file') workflow.connect(convert2nii, 'out_file', segment, 'data') workflow.connect(segment, 'transformation_mat', normalize, 'parameter_file') workflow.connect(segment, 'transformation_mat', normalize_struct, 'parameter_file') workflow.connect(convert2nii, 'out_file', normalize_struct, 'apply_to_files') workflow.connect(realign, 'out_file', normalize, 'apply_to_files') #normalize.inputs.template='/software/spm8/templates/EPI.nii' workflow.connect(normalize, 'normalized_files', smooth, 'in_files') #workflow.connect(realign, 'realigned_files', smooth, 'in_files') artdetect = pe.Node(ra.ArtifactDetect(mask_type='file', parameter_source='FSL', use_differences=[True, False], use_norm=True, save_plot=True), name='artdetect') workflow.connect([(inputnode, artdetect, [('norm_threshold', 'norm_threshold'), ('zintensity_threshold', 'zintensity_threshold')])]) workflow.connect([(realign, artdetect, [('out_file', 'realigned_files'), ('par_file', 'realignment_parameters')])]) workflow.connect(maskflow, ('outputspec.mask_file', poplist), artdetect, 'mask_file') """ Define the outputs of the workflow and connect the nodes to the outputnode """ outputnode = pe.Node(niu.IdentityInterface(fields=[ "realignment_parameters", "smoothed_files", "mask_file", "mean_image", "reg_file", "reg_cost", 'outlier_files', 'outlier_stats', 'outlier_plots', 'norm_components', 'mod_csf', 'unmod_csf', 'mod_wm', 'unmod_wm', 'mod_gm', 'unmod_gm', 'mean', 'normalized_struct', 'struct_in_functional_space', 'normalization_parameters', 'reverse_normalize_parameters' ]), name="outputspec") workflow.connect([ (maskflow, outputnode, [("outputspec.reg_file", "reg_file")]), (maskflow, outputnode, [("outputspec.reg_cost", "reg_cost")]), (maskflow, outputnode, [(("outputspec.mask_file", poplist), "mask_file")]), (realign, outputnode, [('par_file', 'realignment_parameters')]), (smooth, outputnode, [('smoothed_files', 'smoothed_files')]), (artdetect, outputnode, [('outlier_files', 'outlier_files'), ('statistic_files', 'outlier_stats'), ('plot_files', 'outlier_plots'), ('norm_files', 'norm_components')]) ]) workflow.connect(segment, 'modulated_csf_image', outputnode, 'mod_csf') workflow.connect(segment, 'modulated_wm_image', outputnode, 'mod_wm') workflow.connect(segment, 'modulated_gm_image', outputnode, 'mod_gm') workflow.connect(segment, 'normalized_csf_image', outputnode, 'unmod_csf') workflow.connect(segment, 'normalized_wm_image', outputnode, 'unmod_wm') workflow.connect(segment, 'normalized_gm_image', outputnode, 'unmod_gm') workflow.connect(mean, 'outputspec.mean_image', outputnode, 'mean') workflow.connect(normalize_struct, 'normalized_files', outputnode, 'normalized_struct') workflow.connect(segment, 'transformation_mat', outputnode, 'normalization_parameters') workflow.connect(segment, 'inverse_transformation_mat', outputnode, 'reverse_normalize_parameters') workflow.connect(convert2nii, 'out_file', outputnode, 'struct_in_functional_space') workflow.inputs.inputspec.fwhm = c.fwhm workflow.inputs.inputspec.subjects_dir = c.surf_dir workflow.inputs.inputspec.norm_threshold = c.norm_thresh workflow.inputs.inputspec.zintensity_threshold = c.z_thresh workflow.inputs.inputspec.node = c.motion_correct_node workflow.inputs.inputspec.tr = c.TR workflow.inputs.inputspec.do_slicetime = c.do_slicetiming workflow.inputs.inputspec.sliceorder = c.SliceOrder workflow.inputs.inputspec.csf_prob = c.csf_prob workflow.inputs.inputspec.gm_prob = c.grey_prob workflow.inputs.inputspec.wm_prob = c.white_prob workflow.base_dir = c.working_dir workflow.config = {'execution': {'crashdump_dir': c.crash_dir}} datagrabber = get_dataflow(c) workflow.connect(datagrabber, 'func', inputnode, 'functionals') infosource = pe.Node(niu.IdentityInterface(fields=['subject_id']), name='subject_names') if not c.test_mode: infosource.iterables = ('subject_id', c.subjects) else: infosource.iterables = ('subject_id', c.subjects[:1]) workflow.connect(infosource, 'subject_id', inputnode, 'subject_id') workflow.connect(infosource, 'subject_id', datagrabber, 'subject_id') sub = lambda x: [('_subject_id_%s' % x, '')] sinker = pe.Node(nio.DataSink(), name='sinker') workflow.connect(infosource, 'subject_id', sinker, 'container') workflow.connect(infosource, ('subject_id', sub), sinker, 'substitutions') sinker.inputs.base_directory = c.sink_dir outputspec = workflow.get_node('outputspec') workflow.connect(outputspec, 'realignment_parameters', sinker, 'spm_preproc.realignment_parameters') workflow.connect(outputspec, 'smoothed_files', sinker, 'spm_preproc.smoothed_outputs') workflow.connect(outputspec, 'outlier_files', sinker, 'spm_preproc.art.@outlier_files') workflow.connect(outputspec, 'outlier_stats', sinker, 'spm_preproc.art.@outlier_stats') workflow.connect(outputspec, 'outlier_plots', sinker, 'spm_preproc.art.@outlier_plots') workflow.connect(outputspec, 'norm_components', sinker, 'spm_preproc.art.@norm') workflow.connect(outputspec, 'reg_file', sinker, 'spm_preproc.bbreg.@reg_file') workflow.connect(outputspec, 'reg_cost', sinker, 'spm_preproc.bbreg.@reg_cost') workflow.connect(outputspec, 'mask_file', sinker, 'spm_preproc.mask.@mask_file') workflow.connect(outputspec, 'mod_csf', sinker, 'spm_preproc.segment.mod.@csf') workflow.connect(outputspec, 'mod_wm', sinker, 'spm_preproc.segment.mod.@wm') workflow.connect(outputspec, 'mod_gm', sinker, 'spm_preproc.segment.mod.@gm') workflow.connect(outputspec, 'unmod_csf', sinker, 'spm_preproc.segment.unmod.@csf') workflow.connect(outputspec, 'unmod_wm', sinker, 'spm_preproc.segment.unmod.@wm') workflow.connect(outputspec, 'unmod_gm', sinker, 'spm_preproc.segment.unmod.@gm') workflow.connect(outputspec, 'mean', sinker, 'spm_preproc.mean') workflow.connect(outputspec, 'normalized_struct', sinker, 'spm_preproc.normalized_struct') workflow.connect(outputspec, 'normalization_parameters', sinker, 'spm_preproc.normalization_parameters.@forward') workflow.connect(outputspec, 'reverse_normalize_parameters', sinker, 'spm_preproc.normalization_parameters.@reverse') workflow.connect(outputspec, 'struct_in_functional_space', sinker, 'spm_preproc.struct_in_func_space') return workflow
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
datasource.inputs.base_directory = datadir datasource.inputs.template = '%s/*%s.nii.gz' datasource.inputs.template_args = dict( filtered_func=[['subject_id', 'filtered']], mean_image=[['subject_id', 'mean']]) roiproc.connect(inputnode, 'subject_id', datasource, 'subject_id') fssource = pe.Node(nio.FreeSurferSource(), name='fssource') fssource.inputs.subjects_dir = surfacedir register = pe.Node(fs.BBRegister(init='fsl', contrast_type='t2'), name='register') register.inputs.subjects_dir = surfacedir voltransform = pe.Node(fs.ApplyVolTransform(inverse=True, interp='nearest'), name='transform') voltransform.inputs.subjects_dir = surfacedir def choose_aseg(aparc_files): from glob import glob import os all_files = glob(os.path.join(aparc_files[0].split('aparc')[0], '*yeo*')) for fname in all_files: if 'aparc+yeo17' in fname: return fname raise ValueError('No aparc+aseg file found') """
def create_reg_workflow(name='registration'): """Create a FEAT preprocessing workflow together with freesurfer Parameters ---------- name : name of workflow (default: 'registration') Inputs:: inputspec.source_files : files (filename or list of filenames to register) inputspec.mean_image : reference image to use inputspec.anatomical_image : anatomical image to coregister to inputspec.target_image : registration target Outputs:: outputspec.func2anat_transform : FLIRT transform outputspec.anat2target_transform : FLIRT+FNIRT transform outputspec.transformed_files : transformed files in target space outputspec.transformed_mean : mean image in target space """ register = Workflow(name=name) inputnode = Node(interface=IdentityInterface(fields=[ 'source_files', 'mean_image', 'subject_id', 'subjects_dir', 'target_image' ]), name='inputspec') outputnode = Node(interface=IdentityInterface(fields=[ 'func2anat_transform', 'out_reg_file', 'anat2target_transform', 'transforms', 'transformed_mean', 'segmentation_files', 'anat2target', 'aparc' ]), name='outputspec') # Get the subject's freesurfer source directory fssource = Node(FreeSurferSource(), name='fssource') fssource.run_without_submitting = True register.connect(inputnode, 'subject_id', fssource, 'subject_id') register.connect(inputnode, 'subjects_dir', fssource, 'subjects_dir') convert = Node(freesurfer.MRIConvert(out_type='nii'), name="convert") register.connect(fssource, 'T1', convert, 'in_file') # Coregister the median to the surface bbregister = Node(freesurfer.BBRegister(), name='bbregister') bbregister.inputs.init = 'fsl' bbregister.inputs.contrast_type = 't2' bbregister.inputs.out_fsl_file = True bbregister.inputs.epi_mask = True register.connect(inputnode, 'subject_id', bbregister, 'subject_id') register.connect(inputnode, 'mean_image', bbregister, 'source_file') register.connect(inputnode, 'subjects_dir', bbregister, 'subjects_dir') """ Estimate the tissue classes from the anatomical image. But use spm's segment as FSL appears to be breaking. """ stripper = Node(fsl.BET(), name='stripper') register.connect(convert, 'out_file', stripper, 'in_file') fast = Node(fsl.FAST(), name='fast') register.connect(stripper, 'out_file', fast, 'in_files') """ Binarize the segmentation """ binarize = MapNode(fsl.ImageMaths(op_string='-nan -thr 0.9 -ero -bin'), iterfield=['in_file'], name='binarize') register.connect(fast, 'partial_volume_files', binarize, 'in_file') """ Apply inverse transform to take segmentations to functional space """ applyxfm = MapNode(freesurfer.ApplyVolTransform(inverse=True, interp='nearest'), iterfield=['target_file'], name='inverse_transform') register.connect(inputnode, 'subjects_dir', applyxfm, 'subjects_dir') register.connect(bbregister, 'out_reg_file', applyxfm, 'reg_file') register.connect(binarize, 'out_file', applyxfm, 'target_file') register.connect(inputnode, 'mean_image', applyxfm, 'source_file') """ Apply inverse transform to aparc file """ aparcxfm = Node(freesurfer.ApplyVolTransform(inverse=True, interp='nearest'), name='aparc_inverse_transform') register.connect(inputnode, 'subjects_dir', aparcxfm, 'subjects_dir') register.connect(bbregister, 'out_reg_file', aparcxfm, 'reg_file') register.connect(fssource, ('aparc_aseg', get_aparc_aseg), aparcxfm, 'target_file') register.connect(inputnode, 'mean_image', aparcxfm, 'source_file') """ Convert the BBRegister transformation to ANTS ITK format """ convert2itk = Node(C3dAffineTool(), name='convert2itk') convert2itk.inputs.fsl2ras = True convert2itk.inputs.itk_transform = True register.connect(bbregister, 'out_fsl_file', convert2itk, 'transform_file') register.connect(inputnode, 'mean_image', convert2itk, 'source_file') register.connect(stripper, 'out_file', convert2itk, 'reference_file') """ Compute registration between the subject's structural and MNI template This is currently set to perform a very quick registration. However, the registration can be made significantly more accurate for cortical structures by increasing the number of iterations All parameters are set using the example from: #https://github.com/stnava/ANTs/blob/master/Scripts/newAntsExample.sh """ reg = Node(ants.Registration(), name='antsRegister') reg.inputs.output_transform_prefix = "output_" reg.inputs.transforms = ['Rigid', 'Affine', 'SyN'] reg.inputs.transform_parameters = [(0.1, ), (0.1, ), (0.2, 3.0, 0.0)] reg.inputs.number_of_iterations = [[10000, 11110, 11110]] * 2 + [[ 100, 30, 20 ]] reg.inputs.dimension = 3 reg.inputs.write_composite_transform = True reg.inputs.collapse_output_transforms = True reg.inputs.initial_moving_transform_com = True reg.inputs.metric = ['Mattes'] * 2 + [['Mattes', 'CC']] reg.inputs.metric_weight = [1] * 2 + [[0.5, 0.5]] reg.inputs.radius_or_number_of_bins = [32] * 2 + [[32, 4]] reg.inputs.sampling_strategy = ['Regular'] * 2 + [[None, None]] reg.inputs.sampling_percentage = [0.3] * 2 + [[None, None]] reg.inputs.convergence_threshold = [1.e-8] * 2 + [-0.01] reg.inputs.convergence_window_size = [20] * 2 + [5] reg.inputs.smoothing_sigmas = [[4, 2, 1]] * 2 + [[1, 0.5, 0]] reg.inputs.sigma_units = ['vox'] * 3 reg.inputs.shrink_factors = [[3, 2, 1]] * 2 + [[4, 2, 1]] reg.inputs.use_estimate_learning_rate_once = [True] * 3 reg.inputs.use_histogram_matching = [False] * 2 + [True] reg.inputs.winsorize_lower_quantile = 0.005 reg.inputs.winsorize_upper_quantile = 0.995 reg.inputs.float = True reg.inputs.output_warped_image = 'output_warped_image.nii.gz' reg.inputs.num_threads = 4 reg.plugin_args = {'qsub_args': '-l nodes=1:ppn=4'} register.connect(stripper, 'out_file', reg, 'moving_image') register.connect(inputnode, 'target_image', reg, 'fixed_image') """ Concatenate the affine and ants transforms into a list """ merge = Node(Merge(2), iterfield=['in2'], name='mergexfm') register.connect(convert2itk, 'itk_transform', merge, 'in2') register.connect(reg, 'composite_transform', merge, 'in1') """ Transform the mean image. First to anatomical and then to target """ warpmean = Node(ants.ApplyTransforms(), name='warpmean') warpmean.inputs.input_image_type = 3 warpmean.inputs.interpolation = 'Linear' warpmean.inputs.invert_transform_flags = [False, False] warpmean.inputs.terminal_output = 'file' warpmean.inputs.args = '--float' warpmean.inputs.num_threads = 4 register.connect(inputnode, 'target_image', warpmean, 'reference_image') register.connect(inputnode, 'mean_image', warpmean, 'input_image') register.connect(merge, 'out', warpmean, 'transforms') """ Assign all the output files """ register.connect(reg, 'warped_image', outputnode, 'anat2target') register.connect(warpmean, 'output_image', outputnode, 'transformed_mean') register.connect(applyxfm, 'transformed_file', outputnode, 'segmentation_files') register.connect(aparcxfm, 'transformed_file', outputnode, 'aparc') register.connect(bbregister, 'out_fsl_file', outputnode, 'func2anat_transform') register.connect(bbregister, 'out_reg_file', outputnode, 'out_reg_file') register.connect(reg, 'composite_transform', outputnode, 'anat2target_transform') register.connect(merge, 'out', outputnode, 'transforms') return register
surfregister.inputs.init = 'fsl' surfregister.inputs.contrast_type = 't2' """ Use :class:`nipype.interfaces.io.FreeSurferSource` to retrieve various image files that are automatically generated by the recon-all process. """ FreeSurferSource = pe.Node(interface=nio.FreeSurferSource(), name='fssource') """ Use :class:`nipype.interfaces.freesurfer.ApplyVolTransform` to convert the brainmask generated by freesurfer into the realigned functional space. """ ApplyVolTransform = pe.Node(interface=fs.ApplyVolTransform(), name='applyreg') ApplyVolTransform.inputs.inverse = True """ Use :class:`nipype.interfaces.freesurfer.Binarize` to extract a binary brain mask. """ Threshold = pe.Node(interface=fs.Binarize(),name='threshold') Threshold.inputs.min = 10 Threshold.inputs.out_type = 'nii' """ Two different types of functional data smoothing are performed in this workflow. The volume smoothing option performs a standard SPM smoothin. using
def create_get_stats_flow(name='getstats', withreg=False): """Retrieves stats from labels Parameters ---------- name : string name of workflow withreg : boolean indicates whether to register source to label Example ------- Inputs:: inputspec.source_file : reference image for mask generation inputspec.label_file : label file from which to get ROIs (optionally with registration) inputspec.reg_file : bbreg file (assumes reg from source to label inputspec.inverse : boolean whether to invert the registration inputspec.subjects_dir : freesurfer subjects directory Outputs:: outputspec.stats_file : stats file """ import nipype.pipeline.engine as pe import nipype.interfaces.freesurfer as fs import nipype.interfaces.utility as niu """ Initialize the workflow """ getstats = pe.Workflow(name=name) """ Define the inputs to the workflow. """ if withreg: inputnode = pe.Node(niu.IdentityInterface(fields=['source_file', 'label_file', 'reg_file', 'subjects_dir','inverse']), name='inputspec') else: inputnode = pe.Node(niu.IdentityInterface(fields=['source_file', 'label_file']), name='inputspec') statnode = pe.MapNode(fs.SegStats(), iterfield=['segmentation_file','in_file'], name='segstats') """ Convert between source and label spaces if registration info is provided """ if withreg: voltransform = pe.MapNode(fs.ApplyVolTransform(inverse=True, interp='nearest'), iterfield=['source_file', 'reg_file'], name='transform') getstats.connect(inputnode, 'reg_file', voltransform, 'reg_file') getstats.connect(inputnode, 'source_file', voltransform, 'source_file') getstats.connect(inputnode, 'label_file', voltransform, 'target_file') getstats.connect(inputnode, 'subjects_dir', voltransform, 'subjects_dir') def switch_labels(inverse, transform_output, source_file, label_file): if inverse: return transform_output, source_file else: return label_file, transform_output chooser = pe.MapNode(niu.Function(input_names = ['inverse', 'transform_output', 'source_file', 'label_file'], output_names = ['label_file', 'source_file'], function=switch_labels), iterfield=['transform_output','source_file'], name='chooser') getstats.connect(inputnode,'source_file', chooser, 'source_file') getstats.connect(inputnode,'label_file', chooser, 'label_file') getstats.connect(inputnode,'inverse', chooser, 'inverse') getstats.connect(voltransform, 'transformed_file', chooser, 'transform_output') getstats.connect(chooser, 'label_file', statnode, 'segmentation_file') getstats.connect(chooser, 'source_file', statnode, 'in_file') else: getstats.connect(inputnode, 'label_file', statnode, 'segmentation_file') getstats.connect(inputnode, 'source_file', statnode, 'in_file') """ Setup an outputnode that defines relevant inputs of the workflow. """ outputnode = pe.Node(niu.IdentityInterface(fields=["stats_file" ]), name="outputspec") getstats.connect([ (statnode, outputnode, [("summary_file", "stats_file")]), ]) return getstats
def freesurfer_preproc(wf, cfg, strat_pool, pipe_num, opt=None): ''' {"name": "freesurfer_preproc", "config": ["surface_analysis"], "switch": ["run_freesurfer"], "option_key": "None", "option_val": "None", "inputs": [["desc-preproc_T1w", "desc-reorient_T1w", "T1w"]], "outputs": ["space-T1w_desc-brain_mask", "freesurfer_subject_dir", "label-CSF_mask", "label-WM_mask", "label-GM_mask", "surface_curvature", "pial_surface_mesh", "smoothed_surface_mesh", "spherical_surface_mesh", "sulcal_depth_surface_maps", "cortical_thickness_surface_maps", "cortical_volume_surface_maps", "white_matter_surface_mesh", "raw_average"]} ''' reconall = pe.Node(interface=freesurfer.ReconAll(), name=f'anat_freesurfer_{pipe_num}') freesurfer_subject_dir = os.path.join( cfg.pipeline_setup['working_directory']['path'], f'anat_preproc_freesurfer_{pipe_num}', 'anat_freesurfer') if not os.path.exists(freesurfer_subject_dir): os.makedirs(freesurfer_subject_dir) reconall.inputs.directive = 'all' reconall.inputs.subjects_dir = freesurfer_subject_dir reconall.inputs.openmp = cfg.pipeline_setup['system_config'][ 'num_OMP_threads'] node, out = strat_pool.get_data( ["desc-preproc_T1w", "desc-reorient_T1w", "T1w"]) wf.connect(node, out, reconall, 'T1_files') # register FS brain mask to native space fs_brain_mask_to_native = pe.Node(interface=freesurfer.ApplyVolTransform(), name='fs_brain_mask_to_native') fs_brain_mask_to_native.inputs.reg_header = True wf.connect(reconall, 'brainmask', fs_brain_mask_to_native, 'source_file') wf.connect(reconall, 'rawavg', fs_brain_mask_to_native, 'target_file') wf.connect(reconall, 'subjects_dir', fs_brain_mask_to_native, 'subjects_dir') # convert brain mask file from .mgz to .nii.gz fs_brain_mask_to_nifti = pe.Node(util.Function(input_names=['in_file'], output_names=['out_file'], function=mri_convert), name='fs_brainmask_to_nifti') wf.connect(fs_brain_mask_to_native, 'transformed_file', fs_brain_mask_to_nifti, 'in_file') # binarize the brain mask binarize_fs_brain_mask = pe.Node(interface=fsl.maths.MathsCommand(), name='binarize_fs_brainmask') binarize_fs_brain_mask.inputs.args = '-bin' wf.connect(fs_brain_mask_to_nifti, 'out_file', binarize_fs_brain_mask, 'in_file') # fill holes fill_fs_brain_mask = pe.Node(interface=afni.MaskTool(), name='fill_fs_brainmask') fill_fs_brain_mask.inputs.fill_holes = True fill_fs_brain_mask.inputs.outputtype = 'NIFTI_GZ' wf.connect(binarize_fs_brain_mask, 'out_file', fill_fs_brain_mask, 'in_file') # register FS segmentations (aseg.mgz) to native space fs_aseg_to_native = pe.Node(interface=freesurfer.ApplyVolTransform(), name='fs_aseg_to_native') fs_aseg_to_native.inputs.reg_header = True fs_aseg_to_native.inputs.interp = 'nearest' fs_aseg_to_native.inputs.subjects_dir = freesurfer_subject_dir wf.connect(reconall, 'aseg', fs_aseg_to_native, 'source_file') wf.connect(reconall, 'rawavg', fs_aseg_to_native, 'target_file') # convert registered FS segmentations from .mgz to .nii.gz fs_aseg_to_nifti = pe.Node(util.Function(input_names=['in_file'], output_names=['out_file'], function=mri_convert), name='fs_aseg_to_nifti') fs_aseg_to_nifti.inputs.args = '-rt nearest' wf.connect(fs_aseg_to_native, 'transformed_file', fs_aseg_to_nifti, 'in_file') pick_tissue = pe.Node(util.Function( input_names=['multiatlas_Labels'], output_names=['csf_mask', 'gm_mask', 'wm_mask'], function=pick_tissue_from_labels_file), name=f'anat_preproc_freesurfer_tissue_mask') pick_tissue.inputs.include_ventricles = True wf.connect(fs_aseg_to_nifti, 'out_file', pick_tissue, 'multiatlas_Labels') outputs = { 'space-T1w_desc-brain_mask': (fill_fs_brain_mask, 'out_file'), 'freesurfer_subject_dir': (reconall, 'subjects_dir'), 'label-CSF_mask': (pick_tissue, 'csf_mask'), 'label-WM_mask': (pick_tissue, 'wm_mask'), 'label-GM_mask': (pick_tissue, 'gm_mask'), 'surface_curvature': (reconall, 'curv'), 'pial_surface_mesh': (reconall, 'pial'), 'smoothed_surface_mesh': (reconall, 'smoothwm'), 'spherical_surface_mesh': (reconall, 'sphere'), 'sulcal_depth_surface_maps': (reconall, 'sulc'), 'cortical_thickness_surface_maps': (reconall, 'thickness'), 'cortical_volume_surface_maps': (reconall, 'volume'), 'white_matter_surface_mesh': (reconall, 'white'), 'raw_average': (reconall, 'rawavg') } return (wf, outputs)