def tshift(self, in_file=None, out_file=None, suffix=None, interp="heptic"): mycwd = os.getcwd() os.chdir(self._output_dir) in_file, out_file = self.FuncHandler(in_file, out_file, suffix) #out_file = out_file.replace(".nii.gz","") mytshift = afni.TShift(in_file=in_file, interp=interp, outputtype='NIFTI_GZ') #https://nipype.readthedocs.io/en/latest/interfaces/generated/interfaces.afni/preprocess.html#tshift #mytshift.inputs.args = "-prefix %s & %s " % (out_file, out_file.) mytshift.run() os.rename(in_file.replace(".nii.gz", "_tshift.nii.gz"), out_file) os.chdir(mycwd) self.refit(in_file=out_file, args="-view orig") #remove temp files if type(in_file) == models.BIDSImageFile: in_file = os.path.join(self._output_dir, in_file.filename) if "_desc-temp" in in_file: os.remove(in_file)
def slicetime(file, sliceorder): print "running slicetiming" slicetime = afni.TShift(outputtype='NIFTI_GZ') slicetime.inputs.in_file = file if type(sliceorder) == list: custom_order = open(os.path.abspath('afni_custom_order_file.txt'), 'w') tpattern = [] for i in xrange(len(sliceorder)): tpattern.append((i * tr / float(Nz), sliceorder[i])) tpattern.sort(key=lambda x: x[1]) for i, t in enumerate(tpattern): print '%f\n' % (t[0]) custom_order.write('%f\n' % (t[0])) custom_order.close() order_file = 'afni_custom_order_file.txt' elif type(sliceorder) == str: order_file = sliceorder else: raise TypeError('sliceorder must be filepath or list') slicetime.inputs.args = '-tpattern @%s' % os.path.abspath(order_file) slicetime.inputs.tr = str(tr) + 's' slicetime.inputs.outputtype = 'NIFTI_GZ' slicetime.inputs.out_file = os.path.abspath(split_filename(file)[1] +\ "_tshift.nii.gz") res = slicetime.run() file_to_realign = res.outputs.out_file return file_to_realign
def test_tshift(): input_map = dict( args=dict(argstr='%s', ), environ=dict(usedefault=True, ), ignore=dict(argstr='-ignore %s', ), ignore_exception=dict(usedefault=True, ), in_file=dict( argstr='%s', mandatory=True, ), interp=dict(argstr='-%s', ), out_file=dict(argstr='-prefix %s', ), outputtype=dict(), rlt=dict(argstr='-rlt', ), rltplus=dict(argstr='-rlt+', ), suffix=dict(), tpattern=dict(argstr='-tpattern %s', ), tr=dict(argstr='-TR %s', ), tslice=dict( argstr='-slice %s', xor=['tzero'], ), tzero=dict( argstr='-tzero %s', xor=['tslice'], ), ) instance = afni.TShift() for key, metadata in input_map.items(): for metakey, value in metadata.items(): yield assert_equal, getattr(instance.inputs.traits()[key], metakey), value
def init_bold_stc_wf(tr, tpattern, name='bold_stc_wf'): """ This workflow performs :abbr:`STC (slice-timing correction)` over the input :abbr:`BOLD (blood-oxygen-level dependent)` image. .. workflow:: :graph2use: orig :simple_form: yes from fmriprep.workflows.bold import init_bold_stc_wf wf = init_bold_stc_wf( metadata={"RepetitionTime": 2.0, "SliceTiming": [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]}, ) **Parameters** name : str Name of workflow (default: ``bold_stc_wf``) **Inputs** bold_file BOLD series NIfTI file skip_vols Number of non-steady-state volumes detected at beginning of ``bold_file`` **Outputs** stc_file Slice-timing corrected BOLD series NIfTI file """ workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=['bold_file', 'skip_vols']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=['stc_file']), name='outputnode') # It would be good to fingerprint memory use of afni.TShift slice_timing_correction = pe.Node( afni.TShift(tr=tr, tpattern=tpattern, outputtype='NIFTI_GZ'), name='slice_timing_correction') copy_xform = pe.Node(CopyXForm(), name='copy_xform') workflow.connect([ (inputnode, slice_timing_correction, [('bold_file', 'in_file'), ('skip_vols', 'ignore')]), (slice_timing_correction, copy_xform, [('out_file', 'in_file')]), (inputnode, copy_xform, [('bold_file', 'hdr_file')]), (copy_xform, outputnode, [('out_file', 'stc_file')]), ]) return workflow
def _slice_time(func_file, t_r, write_dir, caching=False, terminal_output='allatonce', environ=None): if environ is None: environ = {'AFNI_DECONFLICT': 'OVERWRITE'} if caching: memory = Memory(write_dir) tshift = memory.cache(afni.TShift) tshift.interface().set_default_terminal_output(terminal_output) else: tshift = afni.TShift(terminal_output=terminal_output).run out_tshift = tshift(in_file=func_file, out_file=fname_presuffix(func_file, suffix='_tshifted', newpath=write_dir), tpattern='altplus', tr=str(t_r), environ=environ) return out_tshift.outputs.out_file
def __init__(self, settings): # call base constructor super().__init__(settings) # define input/output node self.set_input(['func']) self.set_output([ 'refimg', 'func_stc_despike', 'warp_func_2_refimg', 'func_aligned' ]) # define datasink substitutions self.set_subs([('MOCOparams', '_moco')]) # define datasink regular expression substitutions self.set_resubs([ ('_moco_before\d{1,3}/', ''), # get rid of _moco_before subfolders ('sub-(?P<subject>\w+)_', 'func/sub-\g<subject>_'), # place files under func folder ('func/(?P<filename>\S+).nii.gz', '\g<filename>.nii.gz' ), # ...except for the QC files, it should NOT have a func folder ('func/sub-(?P<subject>\w+)_ses-(?P<session>\w+)_', 'func/ses-\g<session>/sub-\g<subject>_ses-\g<session>_' ) # add session folders if they exist ]) # extract slice timing so we can pass it to slice time correction self.extract_stc = MapNode(Function(input_names=['epi', 'bids_dir'], output_names=['slicetiming', 'TR'], function=extract_slicetime), iterfield=['epi'], name='extract_slicetime') self.extract_stc.inputs.bids_dir = settings['bids_dir'] # Despike epi data (create 2 for permutations with slice time correction) self.despike = MapNode(ExtendedDespike( args="-ignore {} -NEW -nomask".format( settings['func_reference_frame']), outputtype="NIFTI_GZ"), iterfield=['in_file'], name='despike') # skip despike node self.skip_despike = MapNode(IdentityInterface(fields=['epi']), iterfield=['epi'], name='skip_despike') # despike pool node self.despike_pool = MapNode(IdentityInterface(fields=['epi']), iterfield=['epi'], name='despike_pool') # timeshift data self.tshift = MapNode(afni.TShift( args="-heptic", ignore=settings['func_reference_frame'], tzero=0, outputtype="NIFTI_GZ"), iterfield=['in_file', 'tpattern', 'tr'], name='tshift') # skip stc node self.skip_stc = MapNode(IdentityInterface(fields=['epi']), iterfield=['epi'], name='skip_stc') # despike/stc pool node self.stc_despike_pool = MapNode(IdentityInterface(fields=['epi']), iterfield=['epi'], name='stc_despike_pool') # Setup basefile for volreg (pre slice time correction/despike) self.refrunonly = Node( # this will grab only the first run to feed as a basefile Function(input_names=['epi', 'run'], output_names=['epi'], function=lambda epi, run: epi[run]), name='refrunonly') self.refrunonly.inputs.run = settings['func_reference_run'] self.extractroi = Node( # get reference frame of first run fsl.ExtractROI(t_min=settings['func_reference_frame'], t_size=1, output_type='NIFTI_GZ'), name='extractroi') # Setup basefile for volreg (post slice time correction/despike) self.refrunonly_post = Node( # this will grab only the first run to feed as a basefile Function(input_names=['epi', 'run'], output_names=['epi'], function=lambda epi, run: epi[run]), name='refrunonly_post') self.refrunonly_post.inputs.run = settings['func_reference_run'] self.extractroi_post = Node( # get reference frame of first run fsl.ExtractROI(t_min=settings['func_reference_frame'], t_size=1, output_type='NIFTI_GZ'), name='extractroi_post') # Moco (after) self.moco = MapNode(Function( input_names=[ 'fixed_image', 'moving_image', 'transform', 'writewarp' ], output_names=['warp', 'mocoparams', 'warped_img'], function=antsMotionCorr), iterfield=['moving_image'], name='moco') self.moco.inputs.transform = 'Rigid' self.moco.inputs.writewarp = True self.moco.n_procs = settings['num_threads'] # Moco (before) self.moco_before = MapNode(afni.Volreg( args="-heptic -maxite {}".format(25), verbose=True, zpad=10, outputtype="NIFTI_GZ"), iterfield=['in_file'], name='moco_before') # Calc FD self.calcFD = MapNode(Function( input_names=[ 'func', 'moco_params', 'brain_radius', 'threshold', 'filtered_threshold', 'TR', 'min_bpm', 'max_bpm' ], output_names=['FD', 'tmask', 'filt_moco', 'filt_FD', 'filt_tmask'], function=calcFD), iterfield=['moco_params', 'TR'], name='calcFD') self.calcFD.inputs.min_bpm = settings['min_bpm'] self.calcFD.inputs.max_bpm = settings['max_bpm'] self.calcFD.inputs.brain_radius = settings['brain_radius'] self.calcFD.inputs.threshold = settings['FD_threshold'] self.calcFD.inputs.filtered_threshold = settings[ 'FD_filtered_threshold']
#Basic interface class generates identity mappings NodeHash_6040006ae640 = pe.Node(utility.IdentityInterface(fields=['func','slicetiming_txt']), name = 'NodeName_6040006ae640') NodeHash_6040006ae640.inputs.func = func NodeHash_6040006ae640.inputs.slicetiming_txt = slicetiming_txt #Custom interface wrapping function TR NodeHash_6000004b9860 = pe.MapNode(interface = info_get.TR, name = 'NodeName_6000004b9860', iterfield = ['in_file']) #Custom interface wrapping function Str2Float NodeHash_6040006ae9a0 = pe.MapNode(interface = utils_convert.Str2Float, name = 'NodeName_6040006ae9a0', iterfield = ['str']) #Custom interface wrapping function Float2Str NodeHash_6040004aee80 = pe.MapNode(interface = utils_convert.Float2Str, name = 'NodeName_6040004aee80', iterfield = ['float']) #Wraps command **3dTshift** NodeHash_6040004ad140 = pe.MapNode(interface = afni.TShift(), name = 'NodeName_6040004ad140', iterfield = ['in_file', 'tr']) NodeHash_6040004ad140.inputs.rltplus = True NodeHash_6040004ad140.inputs.outputtype = "NIFTI_GZ" NodeHash_6040004ad140.inputs.terminal_output = 'allatonce' #Generic datasink module to store structured outputs NodeHash_6080008b3d40 = pe.Node(interface = io.DataSink(), name = 'NodeName_6080008b3d40') NodeHash_6080008b3d40.inputs.base_directory = SinkDir NodeHash_6080008b3d40.inputs.regexp_substitutions = [("func_slicetimed/_NodeName_.{13}", "")] #Basic interface class generates identity mappings NodeHash_6080008b5660 = pe.Node(utility.IdentityInterface(fields=['func_slicetimed','TR']), name = 'NodeName_6080008b5660') #Custom interface wrapping function JoinVal2Dict NodeHash_6040004afde0 = pe.Node(interface = utils_convert.JoinVal2Dict, name = 'NodeName_6040004afde0')
def coregister_fmri_session(session_data, t_r, write_dir, brain_volume, use_rats_tool=True, slice_timing=True, prior_rigid_body_registration=False, caching=False, voxel_size_x=.1, voxel_size_y=.1, verbose=True, **environ_kwargs): """ Coregistration of the subject's functional and anatomical images. The functional volume is aligned to the anatomical, first with a rigid body registration and then on a per-slice basis (only a fine correction, this is mostly for correction of EPI distortion). Parameters ---------- session_data : sammba.registration.SessionData Single animal data, giving paths to its functional and anatomical image, as well as it identifier. t_r : float Repetition time for the EPI, in seconds. write_dir : str Directory to save the output and temporary images. brain_volume : int Volume of the brain in mm3 used for brain extraction. Typically 400 for mouse and 1800 for rat. use_rats_tool : bool, optional If True, brain mask is computed using RATS Mathematical Morphology. Otherwise, a histogram-based brain segmentation is used. prior_rigid_body_registration : bool, optional If True, a rigid-body registration of the anat to the func is performed prior to the warp. Useful if the images headers have missing/wrong information. voxel_size_x : float, optional Resampling resolution for the x-axis, in mm. voxel_size_y : float, optional Resampling resolution for the y-axis, in mm. caching : bool, optional Wether or not to use caching. verbose : bool, optional If True, all steps are verbose. Note that caching implies some verbosity in any case. environ_kwargs : extra arguments keywords Extra arguments keywords, passed to interfaces environ variable. Returns ------- the same sequence with each animal_data updated: the following attributes are added - `output_dir_` : str Path to the output directory. - `coreg_func_` : str Path to paths to the coregistered functional image. - `coreg_anat_` : str Path to paths to the coregistered functional image. - `coreg_transform_` : str Path to the transform from anat to func. Notes ----- If `use_rats_tool` is turned on, RATS tool is used for brain extraction and has to be cited. For more information, see `RATS <http://www.iibi.uiowa.edu/content/rats-overview/>`_ """ func_filename = session_data.func anat_filename = session_data.anat environ = {'AFNI_DECONFLICT': 'OVERWRITE'} for (key, value) in environ_kwargs.items(): environ[key] = value if verbose: terminal_output = 'allatonce' else: terminal_output = 'none' if use_rats_tool: if segmentation.interfaces.Info().version() is None: raise ValueError('Can not locate RATS') else: ComputeMask = segmentation.MathMorphoMask else: ComputeMask = segmentation.HistogramMask if ants.base.Info().version is None: raise ValueError('Can not locate ANTS') if caching: memory = Memory(write_dir) tshift = memory.cache(afni.TShift) clip_level = memory.cache(afni.ClipLevel) volreg = memory.cache(afni.Volreg) allineate = memory.cache(afni.Allineate) tstat = memory.cache(afni.TStat) compute_mask = memory.cache(ComputeMask) calc = memory.cache(afni.Calc) allineate = memory.cache(afni.Allineate) allineate2 = memory.cache(afni.Allineate) unifize = memory.cache(afni.Unifize) bias_correct = memory.cache(ants.N4BiasFieldCorrection) catmatvec = memory.cache(afni.CatMatvec) warp = memory.cache(afni.Warp) resample = memory.cache(afni.Resample) slicer = memory.cache(afni.ZCutUp) warp_apply = memory.cache(afni.NwarpApply) qwarp = memory.cache(afni.Qwarp) merge = memory.cache(afni.Zcat) copy_geom = memory.cache(fsl.CopyGeom) overwrite = False for step in [ tshift, volreg, allineate, allineate2, tstat, compute_mask, calc, unifize, resample, slicer, warp_apply, qwarp, merge ]: step.interface().set_default_terminal_output(terminal_output) else: tshift = afni.TShift(terminal_output=terminal_output).run clip_level = afni.ClipLevel().run volreg = afni.Volreg(terminal_output=terminal_output).run allineate = afni.Allineate(terminal_output=terminal_output).run allineate2 = afni.Allineate(terminal_output=terminal_output ).run # TODO: remove after fixed bug tstat = afni.TStat(terminal_output=terminal_output).run compute_mask = ComputeMask().run calc = afni.Calc(terminal_output=terminal_output).run unifize = afni.Unifize(terminal_output=terminal_output).run bias_correct = ants.N4BiasFieldCorrection( terminal_output=terminal_output).run catmatvec = afni.CatMatvec().run warp = afni.Warp().run resample = afni.Resample(terminal_output=terminal_output).run slicer = afni.ZCutUp(terminal_output=terminal_output).run warp_apply = afni.NwarpApply(terminal_output=terminal_output).run qwarp = afni.Qwarp(terminal_output=terminal_output).run merge = afni.Zcat(terminal_output=terminal_output).run copy_geom = fsl.CopyGeom(terminal_output=terminal_output).run overwrite = True session_data._check_inputs() output_dir = os.path.join(os.path.abspath(write_dir), session_data.animal_id) session_data._set_output_dir_(output_dir) current_dir = os.getcwd() os.chdir(output_dir) output_files = [] ####################################### # Correct functional for slice timing # ####################################### if slice_timing: out_tshift = tshift(in_file=func_filename, outputtype='NIFTI_GZ', tpattern='altplus', tr=str(t_r), environ=environ) func_filename = out_tshift.outputs.out_file output_files.append(func_filename) ################################################ # Register functional volumes to the first one # ################################################ # XXX why do you need a thresholded image ? out_clip_level = clip_level(in_file=func_filename) out_calc_threshold = calc(in_file_a=func_filename, expr='ispositive(a-{0}) * a'.format( out_clip_level.outputs.clip_val), outputtype='NIFTI_GZ') thresholded_filename = out_calc_threshold.outputs.out_file out_volreg = volreg( # XXX dfile not saved in_file=thresholded_filename, outputtype='NIFTI_GZ', environ=environ, oned_file=fname_presuffix(thresholded_filename, suffix='Vr.1Dfile.1D', use_ext=False), oned_matrix_save=fname_presuffix(thresholded_filename, suffix='Vr.aff12.1D', use_ext=False)) # Apply the registration to the whole head out_allineate = allineate(in_file=func_filename, master=func_filename, in_matrix=out_volreg.outputs.oned_matrix_save, out_file=fname_presuffix(func_filename, suffix='Av'), environ=environ) # 3dAllineate removes the obliquity. This is not a good way to readd it as # removes motion correction info in the header if it were an AFNI file...as # it happens it's NIfTI which does not store that so irrelevant! out_copy_geom = copy_geom(dest_file=out_allineate.outputs.out_file, in_file=out_volreg.outputs.out_file) allineated_filename = out_copy_geom.outputs.out_file # Create a (hopefully) nice mean image for use in the registration out_tstat = tstat(in_file=allineated_filename, args='-mean', outputtype='NIFTI_GZ', environ=environ) # Update outputs output_files.extend([ thresholded_filename, out_volreg.outputs.oned_matrix_save, out_volreg.outputs.out_file, out_volreg.outputs.md1d_file, allineated_filename, out_tstat.outputs.out_file ]) ########################################### # Corret anat and func for intensity bias # ########################################### # Correct the functional average for intensities bias out_bias_correct = bias_correct(input_image=out_tstat.outputs.out_file) unbiased_func_filename = out_bias_correct.outputs.output_image # Bias correct the antomical image out_unifize = unifize(in_file=anat_filename, outputtype='NIFTI_GZ', environ=environ) unbiased_anat_filename = out_unifize.outputs.out_file # Update outputs output_files.extend([unbiased_func_filename, unbiased_anat_filename]) ############################################# # Rigid-body registration anat -> mean func # ############################################# if prior_rigid_body_registration: # Mask the mean functional volume outside the brain. out_clip_level = clip_level(in_file=unbiased_func_filename) out_compute_mask_func = compute_mask( in_file=unbiased_func_filename, volume_threshold=brain_volume, intensity_threshold=int(out_clip_level.outputs.clip_val)) out_cacl_func = calc(in_file_a=unbiased_func_filename, in_file_b=out_compute_mask_func.outputs.out_file, expr='a*b', outputtype='NIFTI_GZ', environ=environ) # Mask the anatomical volume outside the brain. out_clip_level = clip_level(in_file=unbiased_anat_filename) out_compute_mask_anat = compute_mask( in_file=unbiased_anat_filename, volume_threshold=brain_volume, intensity_threshold=int(out_clip_level.outputs.clip_val)) out_cacl_anat = calc(in_file_a=unbiased_anat_filename, in_file_b=out_compute_mask_anat.outputs.out_file, expr='a*b', outputtype='NIFTI_GZ', environ=environ) # Compute the transformation from functional to anatomical brain # XXX: why in this sense out_allineate = allineate2( in_file=out_cacl_func.outputs.out_file, reference=out_cacl_anat.outputs.out_file, out_matrix=fname_presuffix(out_cacl_func.outputs.out_file, suffix='_shr.aff12.1D', use_ext=False), center_of_mass='', warp_type='shift_rotate', out_file=fname_presuffix(out_cacl_func.outputs.out_file, suffix='_shr'), environ=environ) rigid_transform_file = out_allineate.outputs.out_matrix output_files.extend([ out_compute_mask_func.outputs.out_file, out_cacl_func.outputs.out_file, out_compute_mask_anat.outputs.out_file, out_cacl_anat.outputs.out_file, rigid_transform_file, out_allineate.outputs.out_file ]) # apply the inverse transform to register the anatomical to the func catmatvec_out_file = fname_presuffix(rigid_transform_file, suffix='INV') out_catmatvec = catmatvec(in_file=[(rigid_transform_file, 'I')], oneline=True, out_file=catmatvec_out_file) output_files.append(out_catmatvec.outputs.out_file) out_allineate = allineate(in_file=unbiased_anat_filename, master=unbiased_func_filename, in_matrix=out_catmatvec.outputs.out_file, out_file=fname_presuffix( unbiased_anat_filename, suffix='_shr_in_func_space'), environ=environ) allineated_anat_filename = out_allineate.outputs.out_file output_files.append(allineated_anat_filename) else: allineated_anat_filename = unbiased_anat_filename ############################################ # Nonlinear registration anat -> mean func # ############################################ # 3dWarp doesn't put the obliquity in the header, so do it manually # This step generates one file per slice and per time point, so we are # making sure they are removed at the end out_warp = warp(in_file=allineated_anat_filename, oblique_parent=unbiased_func_filename, interp='quintic', gridset=unbiased_func_filename, outputtype='NIFTI_GZ', verbose=True, environ=environ) registered_anat_filename = out_warp.outputs.out_file registered_anat_oblique_filename = fix_obliquity(registered_anat_filename, unbiased_func_filename, verbose=verbose) # Concatenate all the anat to func tranforms mat_filename = fname_presuffix(registered_anat_filename, suffix='_warp.mat', use_ext=False) # XXX Handle this correctly according to caching if not os.path.isfile(mat_filename): np.savetxt(mat_filename, [out_warp.runtime.stdout], fmt='%s') output_files.append(mat_filename) transform_filename = fname_presuffix(registered_anat_filename, suffix='_anat_to_func.aff12.1D', use_ext=False) if prior_rigid_body_registration: _ = catmatvec(in_file=[(mat_filename, 'ONELINE'), (rigid_transform_file, 'ONELINE')], oneline=True, out_file=transform_filename) else: _ = catmatvec(in_file=[(mat_filename, 'ONELINE')], oneline=True, out_file=transform_filename) ################################################## # Per-slice non-linear registration func -> anat # ################################################## # Slice anatomical image anat_img = nibabel.load(registered_anat_oblique_filename) anat_n_slices = anat_img.header.get_data_shape()[2] sliced_registered_anat_filenames = [] for slice_n in range(anat_n_slices): out_slicer = slicer(in_file=registered_anat_oblique_filename, keep='{0} {0}'.format(slice_n), out_file=fname_presuffix( registered_anat_oblique_filename, suffix='Sl%d' % slice_n), environ=environ) oblique_slice = fix_obliquity(out_slicer.outputs.out_file, registered_anat_oblique_filename, verbose=verbose) sliced_registered_anat_filenames.append(oblique_slice) # Slice mean functional sliced_bias_corrected_filenames = [] img = nibabel.load(func_filename) n_slices = img.header.get_data_shape()[2] for slice_n in range(n_slices): out_slicer = slicer(in_file=unbiased_func_filename, keep='{0} {0}'.format(slice_n), out_file=fname_presuffix(unbiased_func_filename, suffix='Sl%d' % slice_n), environ=environ) oblique_slice = fix_obliquity(out_slicer.outputs.out_file, unbiased_func_filename, verbose=verbose) sliced_bias_corrected_filenames.append(oblique_slice) # Below line is to deal with slices where there is no signal (for example # rostral end of some anatomicals) # The inverse warp frequently fails, Resampling can help it work better # XXX why specifically .1 in voxel_size ? voxel_size_z = anat_img.header.get_zooms()[2] resampled_registered_anat_filenames = [] for sliced_registered_anat_filename in sliced_registered_anat_filenames: out_resample = resample(in_file=sliced_registered_anat_filename, voxel_size=(voxel_size_x, voxel_size_y, voxel_size_z), outputtype='NIFTI_GZ', environ=environ) resampled_registered_anat_filenames.append( out_resample.outputs.out_file) resampled_bias_corrected_filenames = [] for sliced_bias_corrected_filename in sliced_bias_corrected_filenames: out_resample = resample(in_file=sliced_bias_corrected_filename, voxel_size=(voxel_size_x, voxel_size_y, voxel_size_z), outputtype='NIFTI_GZ', environ=environ) resampled_bias_corrected_filenames.append( out_resample.outputs.out_file) # single slice non-linear functional to anatomical registration warped_slices = [] warp_filenames = [] for (resampled_bias_corrected_filename, resampled_registered_anat_filename) in zip( resampled_bias_corrected_filenames, resampled_registered_anat_filenames): warped_slice = fname_presuffix(resampled_bias_corrected_filename, suffix='_qw') out_qwarp = qwarp( in_file=resampled_bias_corrected_filename, base_file=resampled_registered_anat_filename, iwarp=True, # XXX: is this necessary noneg=True, blur=[0], nmi=True, noXdis=True, allineate=True, allineate_opts='-parfix 1 0 -parfix 2 0 -parfix 3 0 ' '-parfix 4 0 -parfix 5 0 -parfix 6 0 ' '-parfix 7 0 -parfix 9 0 ' '-parfix 10 0 -parfix 12 0', out_file=warped_slice, environ=environ) warped_slices.append(out_qwarp.outputs.warped_source) warp_filenames.append(out_qwarp.outputs.source_warp) output_files.append(out_qwarp.outputs.base_warp) # There are files geenrated by the allineate option output_files.extend([ fname_presuffix(out_qwarp.outputs.warped_source, suffix='_Allin'), fname_presuffix(out_qwarp.outputs.warped_source, suffix='_Allin.nii', use_ext=False), fname_presuffix(out_qwarp.outputs.warped_source, suffix='_Allin.aff12.1D', use_ext=False) ]) # Resample the mean volume back to the initial resolution, voxel_size = nibabel.load(unbiased_func_filename).header.get_zooms() resampled_warped_slices = [] for warped_slice in warped_slices: out_resample = resample(in_file=warped_slice, voxel_size=voxel_size, outputtype='NIFTI_GZ', environ=environ) resampled_warped_slices.append(out_resample.outputs.out_file) # fix the obliquity resampled_warped_slices_oblique = [] for (sliced_registered_anat_filename, resampled_warped_slice) in zip(sliced_registered_anat_filenames, resampled_warped_slices): oblique_slice = fix_obliquity(resampled_warped_slice, sliced_registered_anat_filename, verbose=verbose) resampled_warped_slices_oblique.append(oblique_slice) # slice functional sliced_func_filenames = [] for slice_n in range(n_slices): out_slicer = slicer(in_file=allineated_filename, keep='{0} {0}'.format(slice_n), out_file=fname_presuffix(allineated_filename, suffix='Sl%d' % slice_n), environ=environ) oblique_slice = fix_obliquity(out_slicer.outputs.out_file, allineated_filename, verbose=verbose) sliced_func_filenames.append(oblique_slice) # Apply the precomputed warp slice by slice warped_func_slices = [] for (sliced_func_filename, warp_filename) in zip(sliced_func_filenames, warp_filenames): out_warp_apply = warp_apply(in_file=sliced_func_filename, master=sliced_func_filename, warp=warp_filename, out_file=fname_presuffix( sliced_func_filename, suffix='_qw'), environ=environ) warped_func_slices.append(out_warp_apply.outputs.out_file) # Finally, merge all slices ! out_merge_func = merge(in_files=warped_func_slices, outputtype='NIFTI_GZ', environ=environ) # Fix the obliquity merged_oblique = fix_obliquity(out_merge_func.outputs.out_file, allineated_filename, verbose=verbose) # Update the fmri data setattr(session_data, "coreg_func_", merged_oblique) setattr(session_data, "coreg_anat_", registered_anat_oblique_filename) setattr(session_data, "coreg_transform_", transform_filename) os.chdir(current_dir) # Collect the outputs output_files.extend(sliced_registered_anat_filenames + sliced_bias_corrected_filenames + resampled_registered_anat_filenames + resampled_bias_corrected_filenames + warped_slices + warp_filenames + resampled_warped_slices_oblique + sliced_func_filenames + warped_func_slices) if not caching: for out_file in output_files: if os.path.isfile(out_file): os.remove(out_file)
import sys import nipype import nipype.pipeline as pe import nipype.interfaces.io as io import nipype.interfaces.afni as afni #Flexibly collect data from disk to feed into workflows. io_SelectFiles = pe.Node(io.SelectFiles(templates={'subj':['001', '002']}), name='io_SelectFiles') ) io_SelectFiles.inputs.base_directory = '/input' io_SelectFiles.inputs.subj = ['001', '002'] #Wraps the executable command ``3dTshift``. afni_TShift = pe.Node(interface = afni.TShift(), name='afni_TShift') #Wraps the executable command ``3dvolreg``. afni_Volreg = pe.Node(interface = afni.Volreg(), name='afni_Volreg') #Wraps the executable command ``align_epi_anat.py``. afni_AlignEpiAnatPy = pe.Node(interface = afni.AlignEpiAnatPy(), name='afni_AlignEpiAnatPy') afni_AlignEpiAnatPy.inputs.epi_base = 0 afni_AlignEpiAnatPy.inputs.anat2epi = False afni_AlignEpiAnatPy.inputs.epi2anat = True afni_AlignEpiAnatPy.inputs.volreg = 'off' afni_AlignEpiAnatPy.inputs.tshift = 'off' afni_AlignEpiAnatPy.inputs.outputtype = 'NIFTI_GZ' #Generic datasink module to store structured outputs io_DataSink = pe.Node(interface = io.DataSink(), name='io_DataSink')
def init_bold_stc_wf(metadata, name='bold_stc_wf'): """ This workflow performs :abbr:`STC (slice-timing correction)` over the input :abbr:`BOLD (blood-oxygen-level dependent)` image. .. workflow:: :graph2use: orig :simple_form: yes from fmriprep.workflows.bold import init_bold_stc_wf wf = init_bold_stc_wf( metadata={"RepetitionTime": 2.0, "SliceTiming": [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]}, ) **Parameters** metadata : dict BIDS metadata for BOLD file name : str Name of workflow (default: ``bold_stc_wf``) **Inputs** bold_file BOLD series NIfTI file skip_vols Number of non-steady-state volumes detected at beginning of ``bold_file`` **Outputs** stc_file Slice-timing corrected BOLD series NIfTI file """ workflow = pe.Workflow(name=name) inputnode = pe.Node( niu.IdentityInterface(fields=['bold_file', 'skip_vols']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=['stc_file']), name='outputnode') LOGGER.log(25, 'Slice-timing correction will be included.') def create_custom_slice_timing_file_func(metadata): import os slice_timings_sec = ["%f" % t for t in metadata["SliceTiming"]] out_file = os.path.abspath("timings.1D") with open(out_file, "w") as fp: fp.write("\t".join(slice_timings_sec)) return out_file create_custom_slice_timing_file = pe.Node( niu.Function(function=create_custom_slice_timing_file_func), name="create_custom_slice_timing_file", mem_gb=DEFAULT_MEMORY_MIN_GB) create_custom_slice_timing_file.inputs.metadata = metadata # It would be good to fingerprint memory use of afni.TShift slice_timing_correction = pe.Node(afni.TShift( outputtype='NIFTI_GZ', tr='{}s'.format(metadata["RepetitionTime"])), name='slice_timing_correction') copy_xform = pe.Node(CopyXForm(), name='copy_xform', mem_gb=0.1) def _prefix_at(x): return "@%s" % x workflow.connect([ (inputnode, slice_timing_correction, [('bold_file', 'in_file'), ('skip_vols', 'ignore')]), (create_custom_slice_timing_file, slice_timing_correction, [(('out', _prefix_at), 'tpattern')]), (slice_timing_correction, copy_xform, [('out_file', 'in_file')]), (inputnode, copy_xform, [('bold_file', 'hdr_file')]), (copy_xform, outputnode, [('out_file', 'stc_file')]), ]) return workflow
def mod_realign(node, in_file, tr, do_slicetime, sliceorder, parameters={}): import nipype.interfaces.fsl as fsl import nipype.interfaces.spm as spm import nipype.interfaces.nipy as nipy import os parameter_source = "FSL" keys = parameters.keys() if node == "nipy": realign = nipy.FmriRealign4d() realign.inputs.in_file = in_file realign.inputs.tr = tr if "loops" in keys: realign.inputs.loops = parameters["loops"] if "speedup" in keys: realign.inputs.speedup = parameters["speedup"] if "between_loops" in keys: realign.inputs.between_loops = parameters["between_loops"] if do_slicetime: realign.inputs.slice_order = sliceorder realign.inputs.time_interp = True res = realign.run() out_file = res.outputs.out_file par_file = res.outputs.par_file elif node == "fsl": if not isinstance(in_file, list): in_file = [in_file] out_file = [] par_file = [] # get the first volume of first run as ref file if not do_slicetime: extract = fsl.ExtractROI() extract.inputs.t_min = 0 extract.inputs.t_size = 1 extract.inputs.in_file = in_file[0] ref_vol = extract.run().outputs.roi_file for idx, file in enumerate(in_file): if do_slicetime: slicetime = fsl.SliceTimer() slicetime.inputs.in_file = file sliceorder_file = os.path.abspath('FSL_custom_order.txt') with open(sliceorder_file, 'w') as custom_order_fp: for t in sliceorder: custom_order_fp.write('%d\n' % (t + 1)) slicetime.inputs.custom_order = sliceorder_file slicetime.inputs.time_repetition = tr res = slicetime.run() file_to_realign = res.outputs.slice_time_corrected_file if not idx: extract = fsl.ExtractROI() extract.inputs.t_min = 0 extract.inputs.t_size = 1 extract.inputs.in_file = file_to_realign ref_vol = extract.run().outputs.roi_file else: file_to_realign = file realign = fsl.MCFLIRT(interpolation='spline', ref_file=ref_vol) realign.inputs.save_plots = True realign.inputs.mean_vol = True realign.inputs.in_file = file_to_realign realign.inputs.out_file = 'fsl_corr_' + \ os.path.split(file_to_realign)[1] Realign_res = realign.run() out_file.append(Realign_res.outputs.out_file) par_file.append(Realign_res.outputs.par_file) elif node == 'spm': import numpy as np import nibabel as nib import nipype.interfaces.freesurfer as fs if not isinstance(in_file, list): in_file = [in_file] new_in_file = [] for f in in_file: if f.endswith('.nii.gz'): convert = fs.MRIConvert() convert.inputs.in_file = f convert.inputs.out_type = 'nii' convert.inputs.in_type = 'niigz' f = convert.run().outputs.out_file new_in_file.append(f) else: new_in_file.append(f) if do_slicetime: img = nib.load(new_in_file[0]) num_slices = img.shape[2] st = spm.SliceTiming() st.inputs.in_files = new_in_file st.inputs.num_slices = num_slices st.inputs.time_repetition = tr st.inputs.time_acquisition = tr - tr / num_slices st.inputs.slice_order = (np.asarray(sliceorder) + 1).astype(int).tolist() st.inputs.ref_slice = 1 res_st = st.run() file_to_realign = res_st.outputs.timecorrected_files else: file_to_realign = new_in_file par_file = [] realign = spm.Realign() realign.inputs.in_files = file_to_realign #realign.inputs.out_prefix = 'spm_corr_' res = realign.run() parameters = res.outputs.realignment_parameters if not isinstance(parameters, list): parameters = [parameters] par_file = parameters parameter_source = 'SPM' fsl.ImageMaths(in_file=res.outputs.realigned_files, out_file=res.outputs.realigned_files, op_string='-nan').run() out_file = res.outputs.realigned_files elif node == 'afni': import nipype.interfaces.afni as afni import nibabel as nib import numpy as np if not isinstance(in_file, list): in_file = [in_file] img = nib.load(in_file[0]) Nz = img.shape[2] out_file = [] par_file = [] # get the first volume of first run as ref file if not do_slicetime: extract = fsl.ExtractROI() extract.inputs.t_min = 0 extract.inputs.t_size = 1 extract.inputs.in_file = in_file[0] ref_vol = extract.run().outputs.roi_file for idx, file in enumerate(in_file): if do_slicetime: slicetime = afni.TShift() slicetime.inputs.in_file = file custom_order = open( os.path.abspath('afni_custom_order_file.txt'), 'w') tpattern = [] for i in xrange(len(sliceorder)): tpattern.append((i * tr / float(Nz), sliceorder[i])) tpattern.sort(key=lambda x: x[1]) for i, t in enumerate(tpattern): print '%f\n' % (t[0]) custom_order.write('%f\n' % (t[0])) custom_order.close() slicetime.inputs.args = '-tpattern @%s' % os.path.abspath( 'afni_custom_order_file.txt') slicetime.inputs.tr = str(tr) + 's' slicetime.inputs.outputtype = 'NIFTI_GZ' res = slicetime.run() file_to_realign = res.outputs.out_file if not idx: extract = fsl.ExtractROI() extract.inputs.t_min = 0 extract.inputs.t_size = 1 extract.inputs.in_file = file_to_realign ref_vol = extract.run().outputs.roi_file else: file_to_realign = file realign = afni.Volreg() realign.inputs.in_file = file_to_realign realign.inputs.out_file = "afni_corr_" + os.path.split( file_to_realign)[1] realign.inputs.oned_file = "afni_realignment_parameters.par" realign.inputs.basefile = ref_vol Realign_res = realign.run() out_file.append(Realign_res.outputs.out_file) parameters = Realign_res.outputs.oned_file if not isinstance(parameters, list): parameters = [parameters] for i, p in enumerate(parameters): foo = np.genfromtxt(p) boo = foo[:, [1, 2, 0, 4, 5, 3]] boo[:, :3] = boo[:, :3] * np.pi / 180 np.savetxt(os.path.abspath('realignment_parameters_%d.par' % i), boo, delimiter='\t') par_file.append( os.path.abspath('realignment_parameters_%d.par' % i)) #par_file.append(Realign_res.outputs.oned_file) return out_file, par_file, parameter_source
def init_bold_stc_wf(metadata, name='bold_stc_wf'): """ Create a workflow for :abbr:`STC (slice-timing correction)`. This workflow performs :abbr:`STC (slice-timing correction)` over the input :abbr:`BOLD (blood-oxygen-level dependent)` image. Workflow Graph .. workflow:: :graph2use: orig :simple_form: yes from fmriprep.workflows.bold import init_bold_stc_wf wf = init_bold_stc_wf( metadata={"RepetitionTime": 2.0, "SliceTiming": [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]}, ) Parameters ---------- metadata : :obj:`dict` BIDS metadata for BOLD file name : :obj:`str` Name of workflow (default: ``bold_stc_wf``) Inputs ------ bold_file BOLD series NIfTI file skip_vols Number of non-steady-state volumes detected at beginning of ``bold_file`` Outputs ------- stc_file Slice-timing corrected BOLD series NIfTI file """ from niworkflows.engine.workflows import LiterateWorkflow as Workflow from niworkflows.interfaces.utils import CopyXForm workflow = Workflow(name=name) workflow.__desc__ = """\ BOLD runs were slice-time corrected using `3dTshift` from AFNI {afni_ver} [@afni, RRID:SCR_005927]. """.format(afni_ver=''.join(['%02d' % v for v in afni.Info().version() or []])) inputnode = pe.Node( niu.IdentityInterface(fields=['bold_file', 'skip_vols']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=['stc_file']), name='outputnode') LOGGER.log(25, 'Slice-timing correction will be included.') # It would be good to fingerprint memory use of afni.TShift slice_timing_correction = pe.Node(afni.TShift( outputtype='NIFTI_GZ', tr='{}s'.format(metadata["RepetitionTime"]), slice_timing=metadata['SliceTiming'], slice_encoding_direction=metadata.get('SliceEncodingDirection', 'k')), name='slice_timing_correction') copy_xform = pe.Node(CopyXForm(), name='copy_xform', mem_gb=0.1) workflow.connect([ (inputnode, slice_timing_correction, [('bold_file', 'in_file'), ('skip_vols', 'ignore')]), (slice_timing_correction, copy_xform, [('out_file', 'in_file')]), (inputnode, copy_xform, [('bold_file', 'hdr_file')]), (copy_xform, outputnode, [('out_file', 'stc_file')]), ]) return workflow
def SLICETIMER2(): import nipype.pipeline.engine as pe import matplotlib import os os.system('clear') from glob import glob from nilearn import plotting from nilearn import image from nipype.interfaces.utility import Function import nipype.interfaces.utility as util import nipype.interfaces.fsl.utils as fsl from nipype.interfaces import afni #--- 2) Record intial working directory INITDIR = os.getcwd() #--- 3) Prompt user for directory containing DICOM FILES NIFTIFILE = input( 'Please drag in the nifti\n file you wish to slicetime\n(ensure there is no blank space at the end)\n' ) SLICENUM = input('Please enter the slice number you want to correct to') print('alt+z = alternating in the plus direction\n') print('alt+z2 = alternating, starting at slice #1 instead of #0\n') print('alt-z = alternating in the minus direction\n') print('alt-z2 = alternating, starting at slice #nz-2 instead of #nz-1\n') print('seq+z = seqplus = sequential in the plus direction\n') print('seq-z = seqminus = sequential in the minus direction\n') AQORDER = input( 'Please enter the string for slice acquisition order (see above)') TR = input('Please enter the TR(s)') inputnode = pe.Node(interface=util.IdentityInterface( fields=['file', 'slicenum', 'aqorder', 'tr']), name='inputspec') if type(NIFTIFILE) == str: inputnode.inputs.file = NIFTIFILE NIFTIDIR = os.path.split(NIFTIFILE)[0] os.chdir(NIFTIDIR) elif type(NIFTIFILE) == list: inputnode.iterables = ([('file', NIFTIFILE)]) NIFTIDIR = os.path.split(NIFTIFILE[0])[0] os.chdir(NIFTIDIR) if type(SLICENUM) == int: inputnode.inputs.slicenum = SLICENUM elif type(SLICENUM) == list: inputnode.iterables = ([('slicenum', SLICENUM)]) if type(AQORDER) == str: inputnode.inputs.aqorder = AQORDER elif type(AQORDER) == list: inputnode.iterables = ([('aqorder', AQORDER)]) inputnode.inputs.tr = str(TR) + 's' slicetimer = pe.Node(interface=afni.TShift(), name='SLICETIMED') slicetimer.inputs.outputtype = ('NIFTI_GZ') #--- 7) Set up workflow workflow = pe.Workflow(name='SLICETIMER2') workflow.base_dir = os.getcwd() def tshiftplot(pre_file, post_file): import matplotlib.patches as mpatches import matplotlib.pyplot as plt import matplotlib import numpy as np import nibabel as nib img1 = nib.load(pre_file) data = img1.get_data() img2 = nib.load(post_file) data2 = img2.get_data() fig, ax = plt.subplots(figsize=(5, 10)) mid = round(data.shape[0] / 2) for i in range(data.shape[2]): for j in range(1): ax = plt.subplot2grid((data.shape[2], 1), (i, j)) ax.plot(data[mid, mid, i, 1:20], 'ro') ax.plot(data[mid, mid, i, 1:20], 'r-') ax.plot(data2[mid, mid, i, 1:20], 'g^') ax.plot(data2[mid, mid, i, 1:20], 'g-') print('ploting slice' + ' ' + str(i + 1)) ax.yaxis.set_visible(False) green_patch = mpatches.Patch(color='green', label='The shifted data') legend2 = plt.legend(handles=[green_patch], loc=4) plt.gca().add_artist(legend2) red_patch = mpatches.Patch(color='red', label='The original data') plt.legend(handles=[red_patch], loc=3) plt.show() TSHIFTPLOT = pe.Node(Function(input_names=['pre_file', 'post_file'], output_names=['fig'], function=tshiftplot), name='TSHIFTPLOT') #--- 8) Connect nodes. workflow.connect(inputnode, 'file', slicetimer, 'in_file') workflow.connect(inputnode, 'slicenum', slicetimer, 'tslice') workflow.connect(inputnode, 'aqorder', slicetimer, 'tpattern') workflow.connect(inputnode, 'tr', slicetimer, 'tr') workflow.connect(inputnode, 'file', TSHIFTPLOT, 'pre_file') workflow.connect(slicetimer, 'out_file', TSHIFTPLOT, 'post_file') workflow.write_graph(graph2use='exec') #--- 9) Run workflow result = workflow.run() print "Node completed. Returning to intital directory\n" os.chdir(INITDIR)
#Generic datagrabber module that wraps around glob in an io_S3DataGrabber = pe.Node(io.S3DataGrabber(outfields=["outfiles"]), name='io_S3DataGrabber') io_S3DataGrabber.inputs.bucket = 'openneuro' io_S3DataGrabber.inputs.sort_filelist = True io_S3DataGrabber.inputs.template = 'sub-01/anat/sub-01_T1w.nii.gz' io_S3DataGrabber.inputs.anon = True io_S3DataGrabber.inputs.bucket_path = 'ds000101/ds000101_R2.0.0/uncompressed/' io_S3DataGrabber.inputs.local_directory = '/tmp' #Wraps command **bet** fsl_BET = pe.Node(interface=fsl.BET(), name='fsl_BET', iterfield=['']) #Wraps command **3dTshift** afni_TShift = pe.Node(interface=afni.TShift(), name='afni_TShift', iterfield=['']) #Wraps command **3dUnifize** afni_Unifize = pe.Node(interface=afni.Unifize(), name='afni_Unifize', iterfield=['']) #Generic datagrabber module that wraps around glob in an io_S3DataGrabber_2 = pe.Node(io.S3DataGrabber(), name='io_S3DataGrabber_2') #Wraps command **fslreorient2std** fsl_Reorient2Std = pe.Node(interface=fsl.Reorient2Std(), name='fsl_Reorient2Std', iterfield=[''])
def slt_workflow(slicetiming_txt="alt+z",SinkTag="func_preproc",wf_name="slicetiming_correction"): """ Modified version of porcupine generated slicetiming code: `source: -` Creates a slice time corrected functional image. Workflow inputs: :param func: The reoriented functional file. :param SinkDir: :param SinkTag: The output directory in which the returned images (see workflow outputs) could be found in a subdirectory directory specific for this workflow. Workflow outputs: :return: slt_workflow - workflow Balint Kincses [email protected] 2018 """ # This is a Nipype generator. Warning, here be dragons. # !/usr/bin/env python import sys import os import nipype import nipype.pipeline as pe import nipype.interfaces.utility as utility import PUMI.func_preproc.info.info_get as info_get import PUMI.utils.utils_convert as utils_convert import nipype.interfaces.afni as afni import PUMI.utils.globals as globals SinkDir = os.path.abspath(globals._SinkDir_ + "/" + SinkTag) if not os.path.exists(SinkDir): os.makedirs(SinkDir) # Basic interface class generates identity mappings inputspec = pe.Node(utility.IdentityInterface(fields=['func', 'slicetiming_txt']), name='inputspec') inputspec.inputs.func = func inputspec.inputs.slicetiming_txt = slicetiming_txt # Custom interface wrapping function TR #NodeHash_6000004b9860 = pe.MapNode(interface=info_get.TR, name='NodeName_6000004b9860', iterfield=['in_file']) TRvalue = pe.Node(interface=info_get.TR, name='TRvalue') # Custom interface wrapping function Str2Float func_str2float = pe.Node(interface=utils_convert.Str2Float, name='func_str2float') # Custom interface wrapping function Float2Str func_str2float_2 = pe.Node(interface=utils_convert.Float2Str, name='func_str2float_2') # Wraps command **3dTshift** sltcor = pe.Node(interface=afni.TShift(), name='sltcor') sltcor.inputs.rltplus = True sltcor.inputs.outputtype = "NIFTI_GZ" #sltcor.inputs.terminal_output = 'allatonce' # Basic interface class generates identity mappings outputspec = pe.Node(utility.IdentityInterface(fields=['slicetimed', 'TR']), name='outputspec') #todo: qc timeseries # Custom interface wrapping function JoinVal2Dict #func_joinval2dict = pe.Node(interface=utils_convert.JoinVal2Dict, # name='func_joinval2dict') # Generic datasink module to store structured outputs ds = pe.Node(interface=io.DataSink(), name='ds') ds.inputs.base_directory = SinkDir #ds.inputs.regexp_substitutions = [("func_slicetimed/_NodeName_.{13}", "")] # Create a workflow to connect all those nodes analysisflow = nipype.Workflow(wf_name) analysisflow.connect(inputspec, 'slicetiming_txt', sltcor, 'tpattern') analysisflow.connect(func_str2float, 'float', outputspec, 'TR') analysisflow.connect(inputspec, 'func', sltcor, 'in_file') analysisflow.connect(inputspec, 'func', TRvalue, 'in_file') analysisflow.connect(func_str2float_2, 'str', sltcor, 'tr') analysisflow.connect(TRvalue, 'TR', func_str2float_2, 'float') #analysisflow.connect(ds, 'out_file', func_joinval2dict, 'keys') #analysisflow.connect(func_str2float, 'float', func_joinval2dict, 'vals') analysisflow.connect(TRvalue, 'TR', func_str2float, 'str') analysisflow.connect(sltcor, 'out_file', ds, 'slicetimed') analysisflow.connect(sltcor, 'out_file', outputspec, 'slicetimed') return analysisflow
def hmc_afni(name='fMRI_HMC_afni', st_correct=False, despike=False, deoblique=False, start_idx=None, stop_idx=None): """ A :abbr:`HMC (head motion correction)` workflow for functional scans .. workflow:: from mriqc.workflows.functional import hmc_afni wf = hmc_afni() """ workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface( fields=['in_file', 'fd_radius', 'start_idx', 'stop_idx']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=['out_file', 'out_fd']), name='outputnode') if (start_idx is not None) or (stop_idx is not None): drop_trs = pe.Node(afni.Calc(expr='a', outputtype='NIFTI_GZ'), name='drop_trs') workflow.connect([ (inputnode, drop_trs, [('in_file', 'in_file_a'), ('start_idx', 'start_idx'), ('stop_idx', 'stop_idx')]), ]) else: drop_trs = pe.Node(niu.IdentityInterface(fields=['out_file']), name='drop_trs') workflow.connect([ (inputnode, drop_trs, [('in_file', 'out_file')]), ]) get_mean_RPI = pe.Node(afni.TStat(options='-mean', outputtype='NIFTI_GZ'), name='get_mean_RPI') # calculate hmc parameters hmc = pe.Node(afni.Volreg(args='-Fourier -twopass', zpad=4, outputtype='NIFTI_GZ'), name='motion_correct') get_mean_motion = get_mean_RPI.clone('get_mean_motion') hmc_A = hmc.clone('motion_correct_A') hmc_A.inputs.md1d_file = 'max_displacement.1D' # Compute the frame-wise displacement fdnode = pe.Node(nac.FramewiseDisplacement(normalize=False, parameter_source="AFNI"), name='ComputeFD') workflow.connect([ (inputnode, fdnode, [('fd_radius', 'radius')]), (get_mean_RPI, hmc, [('out_file', 'basefile')]), (hmc, get_mean_motion, [('out_file', 'in_file')]), (get_mean_motion, hmc_A, [('out_file', 'basefile')]), (hmc_A, outputnode, [('out_file', 'out_file')]), (hmc_A, fdnode, [('oned_file', 'in_file')]), (fdnode, outputnode, [('out_file', 'out_fd')]), ]) # Slice timing correction, despiking, and deoblique st_corr = pe.Node(afni.TShift(outputtype='NIFTI_GZ'), name='TimeShifts') deoblique_node = pe.Node(afni.Refit(deoblique=True), name='deoblique') despike_node = pe.Node(afni.Despike(outputtype='NIFTI_GZ'), name='despike') if st_correct and despike and deoblique: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, despike_node, [('out_file', 'in_file')]), (despike_node, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, get_mean_RPI, [('out_file', 'in_file')]), (deoblique_node, hmc, [('out_file', 'in_file')]), (deoblique_node, hmc_A, [('out_file', 'in_file')]), ]) elif st_correct and despike: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, despike_node, [('out_file', 'in_file')]), (despike_node, get_mean_RPI, [('out_file', 'in_file')]), (despike_node, hmc, [('out_file', 'in_file')]), (despike_node, hmc_A, [('out_file', 'in_file')]), ]) elif st_correct and deoblique: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, get_mean_RPI, [('out_file', 'in_file')]), (deoblique_node, hmc, [('out_file', 'in_file')]), (deoblique_node, hmc_A, [('out_file', 'in_file')]), ]) elif st_correct: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, get_mean_RPI, [('out_file', 'in_file')]), (st_corr, hmc, [('out_file', 'in_file')]), (st_corr, hmc_A, [('out_file', 'in_file')]), ]) elif despike and deoblique: workflow.connect([ (drop_trs, despike_node, [('out_file', 'in_file')]), (despike_node, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, get_mean_RPI, [('out_file', 'in_file')]), (deoblique_node, hmc, [('out_file', 'in_file')]), (deoblique_node, hmc_A, [('out_file', 'in_file')]), ]) elif despike: workflow.connect([ (drop_trs, despike_node, [('out_file', 'in_file')]), (despike_node, get_mean_RPI, [('out_file', 'in_file')]), (despike_node, hmc, [('out_file', 'in_file')]), (despike_node, hmc_A, [('out_file', 'in_file')]), ]) elif deoblique: workflow.connect([ (drop_trs, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, get_mean_RPI, [('out_file', 'in_file')]), (deoblique_node, hmc, [('out_file', 'in_file')]), (deoblique_node, hmc_A, [('out_file', 'in_file')]), ]) else: workflow.connect([ (drop_trs, get_mean_RPI, [('out_file', 'in_file')]), (drop_trs, hmc, [('out_file', 'in_file')]), (drop_trs, hmc_A, [('out_file', 'in_file')]), ]) return workflow
#motcor_sltimes_wf.connect(motion_correct, 'out_file', motion_sltime_correct, 'in_file') #motcor_sltimes_wf.connect(motion_sltime_correct, 'slice_time_corrected_file', outputspec, 'motion_sltime_corrected_files') elif slice_timer is 'AFNI': # Motion correct functional runs motion_correct = pe.MapNode(afni.Volreg(outputtype='NIFTI_GZ'), name='motion_correct', iterfield=['in_file']) motcor_sltimes_wf.connect(datasource, 'mri_files', motion_correct, 'in_file') motcor_sltimes_wf.connect(extractref, 'roi_file', motion_correct, 'basefile') motcor_sltimes_wf.connect(motion_correct, 'oned_file', outputspec, 'motion_parameters') # Slice timing correction motion_sltime_correct = pe.MapNode(afni.TShift(outputtype='NIFTI_GZ'), name='motion_sltime_correct', iterfield=['in_file']) motion_sltime_correct.inputs.tr = '2.0s' motion_sltime_correct.inputs.tpattern = 'altplus' motcor_sltimes_wf.connect(motion_correct, 'out_file', motion_sltime_correct, 'in_file') motcor_sltimes_wf.connect(motion_sltime_correct, 'out_file', outputspec, 'motion_sltime_corrected_files') # Plot the estimated motion parameters plot_motion = pe.MapNode(fsl.PlotMotionParams(in_source='fsl'), name='plot_motion', iterfield=['in_file']) plot_motion.iterables = ('plot_type', ['rotations', 'translations']) if slice_timer is 'NIPY':
def init_epi_hmc_wf(metadata, bold_file_size_gb, ignore, name='epi_hmc_wf'): """ Performs :abbr:`HMC (head motion correction)` over the input :abbr:`EPI (echo-planar imaging)` image. """ workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface(fields=['epi']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['xforms', 'epi_hmc', 'epi_split', 'epi_mask', 'ref_image', 'ref_image_brain', 'movpar_file', 'n_volumes_to_discard', 'epi_mask_report']), name='outputnode') def normalize_motion_func(in_file, format): import os import numpy as np from nipype.utils.misc import normalize_mc_params mpars = np.loadtxt(in_file) # mpars is N_t x 6 mpars = np.apply_along_axis(func1d=normalize_mc_params, axis=1, arr=mpars, source=format) np.savetxt("motion_params.txt", mpars) return os.path.abspath("motion_params.txt") normalize_motion = pe.Node(niu.Function(function=normalize_motion_func), name="normalize_motion", run_without_submitting=True) normalize_motion.inputs.format = "FSL" # Head motion correction (hmc) hmc = pe.Node(fsl.MCFLIRT( save_mats=True, save_plots=True), name='EPI_hmc') hmc.interface.estimated_memory_gb = bold_file_size_gb * 3 hcm2itk = pe.MapNode(c3.C3dAffineTool(fsl2ras=True, itk_transform=True), iterfield=['transform_file'], name='hcm2itk') enhance_and_skullstrip_epi_wf = init_enhance_and_skullstrip_epi_wf() gen_ref = pe.Node(EstimateReferenceImage(), name="gen_ref") workflow.connect([ (inputnode, gen_ref, [('epi', 'in_file')]), (gen_ref, enhance_and_skullstrip_epi_wf, [('ref_image', 'inputnode.in_file')]), (gen_ref, hmc, [('ref_image', 'ref_file')]), (enhance_and_skullstrip_epi_wf, outputnode, [('outputnode.bias_corrected_file', 'ref_image'), ('outputnode.mask_file', 'epi_mask'), ('outputnode.out_report', 'epi_mask_report'), ('outputnode.skull_stripped_file', 'ref_image_brain')]), ]) split = pe.Node(fsl.Split(dimension='t'), name='split') split.interface.estimated_memory_gb = bold_file_size_gb * 3 if "SliceTiming" in metadata and 'slicetiming' not in ignore: LOGGER.info('Slice-timing correction will be included.') def create_custom_slice_timing_file_func(metadata): import os slice_timings = metadata["SliceTiming"] slice_timings_ms = [str(t) for t in slice_timings] out_file = "timings.1D" with open("timings.1D", "w") as fp: fp.write("\t".join(slice_timings_ms)) return os.path.abspath(out_file) create_custom_slice_timing_file = pe.Node( niu.Function(function=create_custom_slice_timing_file_func), name="create_custom_slice_timing_file", run_without_submitting=True) create_custom_slice_timing_file.inputs.metadata = metadata slice_timing_correction = pe.Node(interface=afni.TShift(), name='slice_timing_correction') slice_timing_correction.inputs.outputtype = 'NIFTI_GZ' slice_timing_correction.inputs.tr = str(metadata["RepetitionTime"]) + "s" def prefix_at(x): return "@" + x workflow.connect([ (inputnode, slice_timing_correction, [('epi', 'in_file')]), (gen_ref, slice_timing_correction, [('n_volumes_to_discard', 'ignore')]), (create_custom_slice_timing_file, slice_timing_correction, [ (('out', prefix_at), 'tpattern')]), (slice_timing_correction, hmc, [('out_file', 'in_file')]) ]) else: workflow.connect([ (inputnode, hmc, [('epi', 'in_file')]) ]) workflow.connect([ (hmc, hcm2itk, [('mat_file', 'transform_file')]), (gen_ref, hcm2itk, [('ref_image', 'source_file'), ('ref_image', 'reference_file')]), (hcm2itk, outputnode, [('itk_transform', 'xforms')]), (hmc, normalize_motion, [('par_file', 'in_file')]), (normalize_motion, outputnode, [('out', 'movpar_file')]), (inputnode, split, [('epi', 'in_file')]), (split, outputnode, [('out_files', 'epi_split')]), ]) return workflow
def hmc_afni(name='fMRI_HMC_afni', st_correct=False, despike=False, deoblique=False): """A head motion correction (HMC) workflow for functional scans""" workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface( fields=['in_file', 'fd_radius', 'start_idx', 'stop_idx']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['out_file', 'out_fd']), name='outputnode') drop_trs = pe.Node(afni.Calc(expr='a', outputtype='NIFTI_GZ'), name='drop_trs') reorient = pe.Node(afni.Resample( orientation='RPI', outputtype='NIFTI_GZ'), name='reorient') get_mean_RPI = pe.Node(afni.TStat( options='-mean', outputtype='NIFTI_GZ'), name='get_mean_RPI') # calculate hmc parameters hmc = pe.Node( afni.Volreg(args='-Fourier -twopass', zpad=4, outputtype='NIFTI_GZ'), name='motion_correct') get_mean_motion = get_mean_RPI.clone('get_mean_motion') hmc_A = hmc.clone('motion_correct_A') hmc_A.inputs.md1d_file = 'max_displacement.1D' # Compute the frame-wise displacement calc_fd = pe.Node(niu.Function( function=fd_jenkinson, input_names=['in_file', 'rmax'], output_names=['out_fd']), name='calc_fd') workflow.connect([ (inputnode, drop_trs, [('in_file', 'in_file_a'), ('start_idx', 'start_idx'), ('stop_idx', 'stop_idx')]), (inputnode, calc_fd, [('fd_radius', 'rmax')]), (reorient, get_mean_RPI, [('out_file', 'in_file')]), (reorient, hmc, [('out_file', 'in_file')]), (get_mean_RPI, hmc, [('out_file', 'basefile')]), (hmc, get_mean_motion, [('out_file', 'in_file')]), (reorient, hmc_A, [('out_file', 'in_file')]), (get_mean_motion, hmc_A, [('out_file', 'basefile')]), (hmc_A, outputnode, [('out_file', 'out_file')]), (hmc_A, calc_fd, [('oned_matrix_save', 'in_file')]), (calc_fd, outputnode, [('out_fd', 'out_fd')]), ]) # Slice timing correction, despiking, and deoblique st_corr = pe.Node(afni.TShift(outputtype='NIFTI_GZ'), name='TimeShifts') deoblique_node = pe.Node(afni.Refit(deoblique=True), name='deoblique') despike_node = pe.Node(afni.Despike(outputtype='NIFTI_GZ'), name='despike') if st_correct and despike and deoblique: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, despike_node, [('out_file', 'in_file')]), (despike_node, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, reorient, [('out_file', 'in_file')]) ]) elif st_correct and despike: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, despike_node, [('out_file', 'in_file')]), (despike_node, reorient, [('out_file', 'in_file')]), ]) elif st_correct and deoblique: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, reorient, [('out_file', 'in_file')]) ]) elif st_correct: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, reorient, [('out_file', 'in_file')]) ]) elif despike and deoblique: workflow.connect([ (drop_trs, despike_node, [('out_file', 'in_file')]), (despike_node, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, reorient, [('out_file', 'in_file')]) ]) elif despike: workflow.connect([ (drop_trs, despike_node, [('out_file', 'in_file')]), (despike_node, reorient, [('out_file', 'in_file')]), ]) elif deoblique: workflow.connect([ (drop_trs, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, reorient, [('out_file', 'in_file')]) ]) else: workflow.connect([ (drop_trs, reorient, [('out_file', 'in_file')]), ]) return workflow
def afni_slicetime(in_file=traits.Undefined, out_file=traits.Undefined, tr=traits.Undefined, tr_units='s', ignore_first=traits.Undefined, slice_mode=traits.Undefined, ref_slice=traits.Undefined, tzero=traits.Undefined, out_type='NIFTI_GZ'): """ Return a nipype interface to the AFNI 3dTshift command. Parameters ---------- in_file: str Path to the input file out_file: str Path to the output file. tr: int or str The TR of the input dataset tr_units: str The units of `tr`. Choices: ('s', 'ms') ignore_first: int Number of acquisitions thrown away from the beginning of the dataset. tzero: float Align each slice to time offset `tzero`. The value of 'tzero' must be between the minimum and maximum slice temporal offsets. Note: The default alignment time is the average of the 'tpattern' values (either from the dataset header or from the -tpattern option) ref_slice: int Align each slice to the time offset of the given `ref_slice` index. Note: only one of the tzero and slice options can be used. -tslice flag slice_mode: str Choices: 'alt+z' or 'altplus' = alternating in the plus direction 'alt+z2' = alternating, starting at slice #1 instead of #0 'alt-z' or 'altminus' = alternating in the minus direction 'alt-z2' = alternating, starting at slice #nz-2 instead of #nz-1 'seq+z' or 'seqplus' = sequential in the plus direction 'seq-z' or 'seqminus' = sequential in the minus direction @filename = read temporal offsets from 'filename' out_type: str ('NIFTI_GZ' or 'AFNI' or 'NIFTI') AFNI output filetype Returns ------- tshift: nipype interface """ import nipype.interfaces.afni as afni tshift = afni.TShift() if isdefined(tr): tr = '{}{}'.format(tr, tr_units) if isdefined(in_file): if not isdefined(out_file): out_file = op.join(op.dirname(in_file), 'tshift_' + remove_ext(op.basename(in_file))) tshift.inputs.in_file = in_file tshift.inputs.out_file = out_file tshift.inputs.tpattern = slice_mode tshift.inputs.tzero = tzero tshift.inputs.tr = tr tshift.inputs.tslice = ref_slice tshift.inputs.ignore = ignore_first tshift.inputs.outputtype = out_type #res = tshift.run() return tshift
def hmc_afni(settings, name='fMRI_HMC_afni', st_correct=False, despike=False, deoblique=False, start_idx=None, stop_idx=None): """ A :abbr:`HMC (head motion correction)` workflow for functional scans .. workflow:: from mriqc.workflows.functional import hmc_afni wf = hmc_afni({'biggest_file_size_gb': 1}) """ biggest_file_gb = settings.get("biggest_file_size_gb", 1) workflow = pe.Workflow(name=name) inputnode = pe.Node(niu.IdentityInterface( fields=['in_file', 'fd_radius', 'start_idx', 'stop_idx']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface( fields=['out_file', 'out_fd']), name='outputnode') if (start_idx is not None) or (stop_idx is not None): drop_trs = pe.Node(afni.Calc(expr='a', outputtype='NIFTI_GZ'), name='drop_trs') workflow.connect([ (inputnode, drop_trs, [('in_file', 'in_file_a'), ('start_idx', 'start_idx'), ('stop_idx', 'stop_idx')]), ]) else: drop_trs = pe.Node(niu.IdentityInterface(fields=['out_file']), name='drop_trs') workflow.connect([ (inputnode, drop_trs, [('in_file', 'out_file')]), ]) gen_ref = pe.Node(nwr.EstimateReferenceImage(mc_method="AFNI"), name="gen_ref") # calculate hmc parameters hmc = pe.Node( afni.Volreg(args='-Fourier -twopass', zpad=4, outputtype='NIFTI_GZ'), name='motion_correct', mem_gb=biggest_file_gb * 2.5) # Compute the frame-wise displacement fdnode = pe.Node(nac.FramewiseDisplacement(normalize=False, parameter_source="AFNI"), name='ComputeFD') workflow.connect([ (inputnode, fdnode, [('fd_radius', 'radius')]), (gen_ref, hmc, [('ref_image', 'basefile')]), (hmc, outputnode, [('out_file', 'out_file')]), (hmc, fdnode, [('oned_file', 'in_file')]), (fdnode, outputnode, [('out_file', 'out_fd')]), ]) # Slice timing correction, despiking, and deoblique st_corr = pe.Node(afni.TShift(outputtype='NIFTI_GZ'), name='TimeShifts') deoblique_node = pe.Node(afni.Refit(deoblique=True), name='deoblique') despike_node = pe.Node(afni.Despike(outputtype='NIFTI_GZ'), name='despike') if st_correct and despike and deoblique: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, despike_node, [('out_file', 'in_file')]), (despike_node, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, gen_ref, [('out_file', 'in_file')]), (deoblique_node, hmc, [('out_file', 'in_file')]), ]) elif st_correct and despike: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, despike_node, [('out_file', 'in_file')]), (despike_node, gen_ref, [('out_file', 'in_file')]), (despike_node, hmc, [('out_file', 'in_file')]), ]) elif st_correct and deoblique: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, gen_ref, [('out_file', 'in_file')]), (deoblique_node, hmc, [('out_file', 'in_file')]), ]) elif st_correct: workflow.connect([ (drop_trs, st_corr, [('out_file', 'in_file')]), (st_corr, gen_ref, [('out_file', 'in_file')]), (st_corr, hmc, [('out_file', 'in_file')]), ]) elif despike and deoblique: workflow.connect([ (drop_trs, despike_node, [('out_file', 'in_file')]), (despike_node, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, gen_ref, [('out_file', 'in_file')]), (deoblique_node, hmc, [('out_file', 'in_file')]), ]) elif despike: workflow.connect([ (drop_trs, despike_node, [('out_file', 'in_file')]), (despike_node, gen_ref, [('out_file', 'in_file')]), (despike_node, hmc, [('out_file', 'in_file')]), ]) elif deoblique: workflow.connect([ (drop_trs, deoblique_node, [('out_file', 'in_file')]), (deoblique_node, gen_ref, [('out_file', 'in_file')]), (deoblique_node, hmc, [('out_file', 'in_file')]), ]) else: workflow.connect([ (drop_trs, gen_ref, [('out_file', 'in_file')]), (drop_trs, hmc, [('out_file', 'in_file')]), ]) return workflow
def init_single_subject_wf( name, output_dir, layout, bold_mag_files, bold_mag_metadata, bold_phase_files, bold_phase_metadata, sbref_mag_files, sbref_mag_metadata, sbref_phase_files, sbref_phase_metadata, t1w_files, t1w_metadata, t2w_files, t2w_metadata, ): workflow = pe.Workflow(name=name) # name the nodes inputnode = pe.Node( niu.IdentityInterface(fields=[ 'bold_mag_files', 'bold_mag_metadata', 'bold_phase_files', 'bold_phase_metadata', 'sbref_mag_files', 'sbref_mag_metadata', 'sbref_phase_files', 'sbref_phase_metadata', 't1w_files', 't1w_metadata', 't2w_files', 't2w_metadata', ]), name='inputnode', iterables=[ ('bold_mag_files', bold_mag_files), ('bold_mag_metadata', bold_mag_metadata), ('bold_phase_files', bold_phase_files), ('bold_phase_metadata', bold_phase_metadata), ('sbref_mag_files', sbref_mag_files), ('sbref_mag_metadata', sbref_mag_metadata), ('sbref_phase_files', sbref_phase_files), ('sbref_phase_metadata', sbref_phase_metadata), ], synchronize=True, ) inputnode.inputs.t1w_files = t1w_files inputnode.inputs.t1w_metadata = t1w_metadata inputnode.inputs.t2w_files = t2w_files inputnode.inputs.t2w_metadata = t2w_metadata outputnode = pe.Node( niu.IdentityInterface(fields=[ 'preproc_bold_files', 'preproc_phase_files', 'motion_parameters' ]), name='outputnode', ) # Generate single-band reference image-based field maps sbref_phdiff_wf = init_phdiff_wf(name='sbref_phdiff_wf', create_phasediff=True, omp_nthreads=1, fmap_bspline=None) workflow.connect( inputnode, ('sbref_phase_files', pick_first), sbref_phdiff_wf, 'inputnode.phase1', ) workflow.connect( inputnode, ('sbref_phase_files', pick_second), sbref_phdiff_wf, 'inputnode.phase2', ) workflow.connect( inputnode, ('sbref_mag_files', pick_first), sbref_phdiff_wf, 'inputnode.magnitude', ) workflow.connect( inputnode, ('sbref_phase_metadata', pick_first), sbref_phdiff_wf, 'inputnode.phase1_metadata', ) workflow.connect( inputnode, ('sbref_phase_metadata', pick_second), sbref_phdiff_wf, 'inputnode.phase2_metadata', ) # Generate dynamic field maps # Somehow select the first two echoes docma_wf = init_docma_wf(omp_nthreads=1, name='docma_wf') bold_mag_splitter = pe.MapNode( interface=fsl.Split(dimension='t'), name='bold_mag_splitter', iterfield=['in_file'], ) bold_phase_splitter = pe.MapNode( interface=fsl.Split(dimension='t'), name='bold_phase_splitter', iterfield=['in_file'], ) workflow.connect(inputnode, 'bold_mag_files', bold_mag_splitter, 'in_file') workflow.connect(inputnode, 'bold_phase_files', bold_phase_splitter, 'in_file') """ bold_phdiff_wf = init_phdiff_wf(name='bold_phdiff_wf', create_phasediff=True, omp_nthreads=1, fmap_bspline=None) workflow.connect(inputnode, ('bold_phase_files', pick_first), bold_phdiff_wf, 'inputnode.phase1') workflow.connect(inputnode, ('bold_phase_files', pick_second), bold_phdiff_wf, 'inputnode.phase2') workflow.connect(inputnode, ('bold_mag_files', pick_first), bold_phdiff_wf, 'inputnode.magnitude') workflow.connect(inputnode, ('bold_phase_metadata', pick_first), bold_phdiff_wf, 'inputnode.phase1_metadata') workflow.connect(inputnode, ('bold_phase_metadata', pick_second), bold_phdiff_wf, 'inputnode.phase2_metadata') """ """ # Skullstrip BOLD files on a volume-wise basis # Need to feed in 3D files from first echo bold_mag_buffer = pe.Node( interface=niu.IdentityInterface(fields=['bold_mag_files']), name='bold_mag_buffer') bold_mag_buffer.iterables = ('bold_mag_files', (bold_mag_splitter.outputs.out_files, pick_first)) bold_skullstrip_wf = init_skullstrip_bold_wf(name='bold_skullstrip_wf') workflow.connect(bold_mag_buffer, 'bold_mag_files', bold_skullstrip_wf, 'inputnode.in_file') # Apply volume-wise brain masks to corresponding volumes from all echoes bold_skullstrip_apply = pe.MapNode( fsl.ApplyMask(), name='bold_skullstrip_apply', iterfield=['in_file'], ) workflow.connect(inputnode, 'bold_mag_files', bold_skullstrip_apply, 'in_file') workflow.connect(bold_skullstrip_wf, 'outputnode.mask_file', bold_skullstrip_apply, 'mask_file') """ """ # Unwarp BOLD data # Must be applied to each volume and each echo independently # Will also need to be done to the phase data, post preproc but pre-MC bold_unwarp_wf = init_sdc_unwarp_wf(name='bold_unwarp_wf', debug=False, omp_nthreads=1, fmap_demean=True) first_echo_metadata = pe.Node(interface=Function(['input'], ['output'], pick_first), name='first_echo_metadata') workflow.connect(bold_phdiff_wf, 'outputnode.fmap', bold_unwarp_wf, 'inputnode.fmap') workflow.connect(bold_phdiff_wf, 'outputnode.fmap_mask', bold_unwarp_wf, 'inputnode.fmap_mask') workflow.connect(bold_phdiff_wf, 'outputnode.fmap_ref', bold_unwarp_wf, 'inputnode.fmap_ref') workflow.connect(inputnode, ('bold_mag_files', pick_first), bold_unwarp_wf, 'inputnode.in_reference') workflow.connect(bold_skullstrip_apply, ('out_file', pick_first), bold_unwarp_wf, 'inputnode.in_reference_brain') workflow.connect(bold_skullstrip_wf, ('outputnode.mask_file', pick_first), bold_unwarp_wf, 'inputnode.in_mask') workflow.connect(inputnode, 'bold_mag_metadata', first_echo_metadata, 'input') workflow.connect(first_echo_metadata, 'output', bold_unwarp_wf, 'inputnode.metadata') """ # Process BOLD phase data for distortion correction bold_phase_wf = init_phase_processing_wf(name='phase_processing_wf') workflow.connect(inputnode, 'bold_phase_files', bold_phase_wf, 'inputnode.phase_files') workflow.connect(inputnode, 'bold_mag_files', bold_phase_wf, 'inputnode.magnitude_files') # Phaseprep preprocessing workflow to prepare phase data for phase-denoising reference_wf = init_bold_reference_wf(name='reference_wf') workflow.connect( bold_motionCorrection_applyMag, ('out_file', pick_first), reference_wf, 'inputnode.bold_file', ) workflow.connect(inputnode, ('sbref_mag_files', pick_first), reference_wf, 'inputnode.sbref_file') # This workflow is set up for single-echo data, so we need to # split or iterate over echoes here phaseprep_wf = create_preprocess_phase_wf(name='phaseprep_wf') workflow.connect(inputnode, 'bold_phase_files', phaseprep_wf, 'inputnode.input_phase') workflow.connect(inputnode, 'bold_mag_files', phaseprep_wf, 'inputnode.input_mag') # These ones are constant across echoes workflow.connect( bold_motionCorrection_estimate, 'oned_matrix_save', phaseprep_wf, 'inputnode.motion_par', ) workflow.connect(reference_wf, 'outputnode.bold_mask', phaseprep_wf, 'inputnode.mask_file') # Perform motion correction for first echo only bold_motionCorrection_estimate = pe.Node( interface=afni.Volreg(outputtype='NIFTI_GZ'), name='bold_motionCorrection_estimate', ) get_motpar_name_node = pe.Node( interface=Function(['source_file'], ['out_file'], get_motpar_name), name='get_motpar_name', ) workflow.connect( inputnode, ('bold_mag_files', pick_first), bold_motionCorrection_estimate, 'in_file', ) workflow.connect(inputnode, ('bold_mag_files', pick_first), get_motpar_name_node, 'source_file') workflow.connect( get_motpar_name_node, 'out_file', bold_motionCorrection_estimate, 'oned_matrix_save', ) workflow.connect( inputnode, ('sbref_mag_files', pick_first), bold_motionCorrection_estimate, 'basefile', ) # Apply motion parameters to all echoes, for both magnitude and phase data bold_motionCorrection_applyMag = pe.MapNode( interface=afni.Allineate(outputtype='NIFTI_GZ'), name='bold_motionCorrection_applyMag', iterfield=['in_file'], ) workflow.connect( bold_motionCorrection_estimate, 'oned_matrix_save', bold_motionCorrection_applyMag, 'in_matrix', ) workflow.connect(inputnode, 'bold_mag_files', bold_motionCorrection_applyMag, 'in_file') workflow.connect( inputnode, ('sbref_mag_files', pick_first), bold_motionCorrection_applyMag, 'reference', ) # Perform slice timing correction on magnitude and phase data bold_stc_getParams = pe.MapNode( interface=Function(['metadata'], ['slice_timing'], get_slice_timing), name='bold_stc_getParams', iterfield=['metadata'], ) workflow.connect(inputnode, 'bold_mag_metadata', bold_stc_getParams, 'metadata') bold_magnitude_stc = pe.MapNode( interface=afni.TShift(outputtype='NIFTI_GZ'), name='bold_magnitude_stc', iterfield=['in_file', 'slice_timing'], ) workflow.connect(bold_motionCorrection_applyMag, 'out_file', bold_magnitude_stc, 'in_file') workflow.connect(bold_stc_getParams, 'slice_timing', bold_magnitude_stc, 'slice_timing') # Use SBRef from first echo as reference image. # No need to coregister functional data to SBRef because it was used for # the motion correction. # Coregister reference image to structural coreg_est = pe.Node(interface=afni.Allineate(out_matrix='sbref2anat.1D'), name='sbref2anat_estimate') workflow.connect(inputnode, ('sbref_mag_files', pick_first), coreg_est, 'in_file') workflow.connect(inputnode, ('t1w_files', pick_first), coreg_est, 'reference') # Apply xform to mag data coreg_apply_mag = pe.MapNode( interface=afni.Allineate(outputtype='NIFTI_GZ'), name='sbref2anat_apply_mag', iterfield=['in_file'], ) workflow.connect(coreg_est, 'out_matrix', coreg_apply_mag, 'in_matrix') workflow.connect(bold_magnitude_stc, 'out_file', coreg_apply_mag, 'in_file') workflow.connect(inputnode, ('sbref_mag_files', pick_first), coreg_apply_mag, 'reference') # Apply xform to phase data coreg_apply_phase = pe.MapNode( interface=afni.Allineate(outputtype='NIFTI_GZ'), name='sbref2anat_apply_phase', iterfield=['in_file'], ) workflow.connect(coreg_est, 'out_matrix', coreg_apply_phase, 'in_matrix') workflow.connect(phaseprep_wf, 'outputnode.uw_phase', coreg_apply_phase, 'in_file') workflow.connect(inputnode, ('sbref_mag_files', pick_first), coreg_apply_phase, 'reference') # Apply xform to magnitude sbref data coreg_apply_sbref = pe.MapNode( interface=afni.Allineate(outputtype='NIFTI_GZ'), name='sbref2anat_apply_sbref', iterfield=['in_file'], ) workflow.connect(coreg_est, 'out_matrix', coreg_apply_sbref, 'in_matrix') workflow.connect(inputnode, 'sbref_mag_files', coreg_apply_sbref, 'in_file') workflow.connect(inputnode, ('sbref_mag_files', pick_first), coreg_apply_sbref, 'reference') # Collect outputs workflow.connect(bold_motionCorrection_estimate, 'oned_file', outputnode, 'motion_parameters') workflow.connect(coreg_apply_mag, 'out_file', outputnode, 'preproc_bold_files') workflow.connect(coreg_apply_phase, 'out_file', outputnode, 'preproc_phase_files') # Output BOLD mag files derivativesnode1 = pe.MapNode( interface=Function(['in_file', 'output_dir'], ['out_file'], copy_files), name='derivativesnode_bold_mag', iterfield=['in_file'], ) derivativesnode1.inputs.output_dir = output_dir workflow.connect(outputnode, 'preproc_bold_files', derivativesnode1, 'in_file') # Output BOLD phase files derivativesnode2 = pe.MapNode( interface=Function(['in_file', 'output_dir'], ['out_file'], copy_files), name='derivativesnode_bold_phase', iterfield=['in_file'], ) derivativesnode2.inputs.output_dir = output_dir workflow.connect(outputnode, 'preproc_phase_files', derivativesnode2, 'in_file') # Output motion parameters derivativesnode3 = pe.Node( interface=Function(['in_file', 'output_dir'], ['out_file'], copy_files), name='derivativesnode_motpars', ) derivativesnode3.inputs.output_dir = output_dir workflow.connect(outputnode, 'motion_parameters', derivativesnode3, 'in_file') return workflow
AD.inputs.parameter_source = 'AFNI' #AD.inputs.realigned_files = 'motion_func' #AD.inputs.realignment_parameters = 'motion_par' AD.inputs.zintensity_threshold = 1.0 AD.inputs.global_threshold = 9.0 #AD.inputs.use_norm = 'TRUE' psb6351_wf.connect(volreg, 'out_file', AD, 'realigned_files') psb6351_wf.connect(volreg, 'oned_file', AD, 'realignment_parameters') # Below is the command that runs AFNI's 3dTshift command # this is the node that performs the slice timing correction # I input the study func files as a list and the slice timing # as a list of lists. I'm using a MapNode to iterate over the two. # this should allow me to parallelize this on the HPC tshifter = pe.MapNode(afni.TShift(), iterfield=['in_file', 'slice_timing'], name='tshifter') tshifter.inputs.tr = '1.76' tshifter.inputs.slice_timing = slice_timing_list tshifter.inputs.outputtype = 'NIFTI_GZ' psb6351_wf.connect(volreg, 'out_file', tshifter, 'in_file') # Calculate the transformation matrix from EPI space to FreeSurfer space # using the BBRegister command fs_register = pe.Node(fs.BBRegister(init='fsl'), name='fs_register') fs_register.inputs.contrast_type = 't2' fs_register.inputs.out_fsl_file = True fs_register.inputs.subject_id = f'sub-{sids[0]}' fs_register.inputs.subjects_dir = fs_dir psb6351_wf.connect(extractref, 'roi_file', fs_register, 'source_file')
def init_bold_stc_wf(metadata, name='bold_stc_wf'): """ This workflow performs :abbr:`STC (slice-timing correction)` over the input :abbr:`BOLD (blood-oxygen-level dependent)` image. .. workflow:: :graph2use: orig :simple_form: yes from fmriprep.workflows.bold import init_bold_stc_wf wf = init_bold_stc_wf( metadata={"RepetitionTime": 2.0, "SliceTiming": [0.0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9]}, ) **Parameters** metadata : dict BIDS metadata for BOLD file name : str Name of workflow (default: ``bold_stc_wf``) **Inputs** bold_file BOLD series NIfTI file skip_vols Number of non-steady-state volumes detected at beginning of ``bold_file`` **Outputs** stc_file Slice-timing corrected BOLD series NIfTI file """ workflow = Workflow(name=name) workflow.__desc__ = """\ BOLD runs were slice-time corrected using `3dTshift` from AFNI {afni_ver} [@afni, RRID:SCR_005927]. """.format(afni_ver=''.join(list(afni.TShift().version or '<ver>'))) inputnode = pe.Node(niu.IdentityInterface(fields=['bold_file', 'skip_vols']), name='inputnode') outputnode = pe.Node(niu.IdentityInterface(fields=['stc_file']), name='outputnode') LOGGER.log(25, 'Slice-timing correction will be included.') # It would be good to fingerprint memory use of afni.TShift slice_timing_correction = pe.Node( afni.TShift(outputtype='NIFTI_GZ', tr='{}s'.format(metadata["RepetitionTime"]), slice_timing=metadata['SliceTiming']), name='slice_timing_correction') copy_xform = pe.Node(CopyXForm(), name='copy_xform', mem_gb=0.1) workflow.connect([ (inputnode, slice_timing_correction, [('bold_file', 'in_file'), ('skip_vols', 'ignore')]), (slice_timing_correction, copy_xform, [('out_file', 'in_file')]), (inputnode, copy_xform, [('bold_file', 'hdr_file')]), (copy_xform, outputnode, [('out_file', 'stc_file')]), ]) return workflow