def _run_interface(self, runtime): ref_name = self.inputs.in_file ref_nii = nb.load(ref_name) n_volumes_to_discard = _get_vols_to_discard(ref_nii) self._results["n_volumes_to_discard"] = n_volumes_to_discard out_ref_fname = os.path.join(runtime.cwd, "ref_bold.nii.gz") if isdefined(self.inputs.sbref_file): out_ref_fname = os.path.join(runtime.cwd, "ref_sbref.nii.gz") ref_name = self.inputs.sbref_file ref_nii = nb.squeeze_image(nb.load(ref_name)) # If reference is only 1 volume, return it directly if len(ref_nii.shape) == 3: ref_nii.header.extensions.clear() ref_nii.to_filename(out_ref_fname) self._results['ref_image'] = out_ref_fname return runtime else: # Reset this variable as it no longer applies # and value for the output is stored in self._results n_volumes_to_discard = 0 # Slicing may induce inconsistencies with shape-dependent values in extensions. # For now, remove all. If this turns out to be a mistake, we can select extensions # that don't break pipeline stages. ref_nii.header.extensions.clear() if n_volumes_to_discard == 0: if ref_nii.shape[-1] > 40: ref_name = os.path.join(runtime.cwd, "slice.nii.gz") nb.Nifti1Image(ref_nii.dataobj[:, :, :, 20:40], ref_nii.affine, ref_nii.header).to_filename(ref_name) if self.inputs.mc_method == "AFNI": res = afni.Volreg(in_file=ref_name, args='-Fourier -twopass', zpad=4, outputtype='NIFTI_GZ').run() elif self.inputs.mc_method == "FSL": res = fsl.MCFLIRT(in_file=ref_name, ref_vol=0, interpolation='sinc').run() mc_slice_nii = nb.load(res.outputs.out_file) median_image_data = np.median(mc_slice_nii.get_fdata(), axis=3) else: median_image_data = np.median( ref_nii.dataobj[:, :, :, :n_volumes_to_discard], axis=3) nb.Nifti1Image(median_image_data, ref_nii.affine, ref_nii.header).to_filename(out_ref_fname) self._results["ref_image"] = out_ref_fname return runtime
def motion(file_to_realign, ref_vol): print "running realignment" realign = afni.Volreg() realign.inputs.in_file = file_to_realign realign.inputs.outputtype = 'NIFTI_GZ' realign.inputs.out_file = os.path.abspath("afni_corr_" +\ split_filename(file_to_realign)[1] +\ ".nii.gz") realign.inputs.oned_file = "afni_realignment_parameters.par" realign.inputs.basefile = ref_vol Realign_res = realign.run() out_file = Realign_res.outputs.out_file par_file = Realign_res.outputs.oned_file return out_file, par_file
def _run_interface(self, runtime): if isdefined(self.inputs.sbref_file): self._results['ref_image'] = self.inputs.sbref_file return runtime in_nii = nb.load(self.inputs.in_file) data_slice = in_nii.dataobj[:, :, :, :50] # Slicing may induce inconsistencies with shape-dependent values in extensions. # For now, remove all. If this turns out to be a mistake, we can select extensions # that don't break pipeline stages. in_nii.header.extensions.clear() n_volumes_to_discard = _get_vols_to_discard(in_nii) out_ref_fname = os.path.join(runtime.cwd, "ref_image.nii.gz") if n_volumes_to_discard == 0: if in_nii.shape[-1] > 40: slice_fname = os.path.join(runtime.cwd, "slice.nii.gz") nb.Nifti1Image(data_slice[:, :, :, 20:40], in_nii.affine, in_nii.header).to_filename(slice_fname) else: slice_fname = self.inputs.in_file if self.inputs.mc_method == "AFNI": res = afni.Volreg(in_file=slice_fname, args='-Fourier -twopass', zpad=4, outputtype='NIFTI_GZ').run() elif self.inputs.mc_method == "FSL": res = fsl.MCFLIRT(in_file=slice_fname, ref_vol=0, interpolation='sinc').run() mc_slice_nii = nb.load(res.outputs.out_file) median_image_data = np.median(mc_slice_nii.get_data(), axis=3) else: median_image_data = np.median( data_slice[:, :, :, :n_volumes_to_discard], axis=3) nb.Nifti1Image(median_image_data, in_nii.affine, in_nii.header).to_filename(out_ref_fname) self._results["ref_image"] = out_ref_fname self._results["n_volumes_to_discard"] = n_volumes_to_discard return runtime
def _run_interface(self, runtime): in_nii = nb.load(self.inputs.in_file) data_slice = in_nii.dataobj[:, :, :, :50] global_signal = data_slice.mean(axis=0).mean(axis=0).mean(axis=0) n_volumes_to_discard = is_outlier(global_signal) out_ref_fname = os.path.abspath("ref_image.nii.gz") if n_volumes_to_discard == 0: if in_nii.shape[-1] > 40: slice = data_slice[:, :, :, 20:40] slice_fname = os.path.abspath("slice.nii.gz") nb.Nifti1Image(slice, in_nii.affine, in_nii.header).to_filename(slice_fname) else: slice_fname = self.inputs.in_file if self.inputs.mc_method == "AFNI": res = afni.Volreg(in_file=slice_fname, args='-Fourier -twopass', zpad=4, outputtype='NIFTI_GZ').run() elif self.inputs.mc_method == "FSL": res = fsl.MCFLIRT(in_file=slice_fname, ref_vol=0, interpolation='sinc').run() mc_slice_nii = nb.load(res.outputs.out_file) median_image_data = np.median(mc_slice_nii.get_data(), axis=3) nb.Nifti1Image(median_image_data, mc_slice_nii.affine, mc_slice_nii.header).to_filename(out_ref_fname) else: median_image_data = np.median( data_slice[:, :, :, :n_volumes_to_discard], axis=3) nb.Nifti1Image(median_image_data, in_nii.affine, in_nii.header).to_filename(out_ref_fname) self._results = dict() self._results["ref_image"] = out_ref_fname self._results["n_volumes_to_discard"] = n_volumes_to_discard return runtime
def volreg(self, in_file, out_file=None, suffix=None, base=None, tshift=False, interpolation="heptic", onedfile=None, onedmat=None): in_file, out_file = self.FuncHandler(in_file, out_file, suffix=suffix) myreg = afni.Volreg(in_file=in_file, out_file=out_file) #https://nipype.readthedocs.io/en/latest/interfaces/generated/interfaces.afni/preprocess.html#volreg if base is not None: base, _ = self.FuncHandler(base, out_file, suffix) myreg.inputs.basefile = base myreg.inputs.verbose = self._is_verbose myreg.inputs.timeshift = tshift myreg.inputs.interp = interpolation if onedfile is True: myreg.inputs.oned_file = out_file.replace(".nii.gz", ".1D") elif onedfile is not None: myreg.inputs.oned_file = onedfile if onedmat is True: myreg.inputs.oned_matrix_save = out_file.replace( "vrA.nii.gz", "vrmat.aff12.1D") elif onedmat is not None: myreg.inputs.oned_matrix_save = onedmat myreg.inputs.num_threads = cpu_count() #should improve speed myreg.run() #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 test_volreg(): input_map = dict( args=dict(argstr='%s', ), basefile=dict(argstr='-base %s', ), copyorigin=dict(argstr='-twodup', ), environ=dict(usedefault=True, ), ignore_exception=dict(usedefault=True, ), in_file=dict( argstr='%s', mandatory=True, ), md1dfile=dict(argstr='-maxdisp1D %s', ), oned_file=dict(argstr='-1Dfile %s', ), out_file=dict(argstr='-prefix %s', ), outputtype=dict(), timeshift=dict(argstr='-tshift 0', ), verbose=dict(argstr='-verbose', ), zpad=dict(argstr='-zpad %d', ), ) instance = afni.Volreg() 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__(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']
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)
# Extract the earliest volume with the # fewest outliers of the first run as the reference extractref = pe.Node(fsl.ExtractROI(t_size=1), name = "extractref") extractref.inputs.in_file = func_files[0] #extractref.inputs.t_min = int(np.ceil(nb.load(study_func_files[0]).shape[3]/2)) #PICKING MIDDLE psb6351_wf.connect(getbestvol, 'best_vol_num', extractref, 't_min') # Below is the command that runs AFNI's 3dvolreg command. # this is the node that performs the motion correction # I'm iterating over the functional files which I am passing # functional data from the slice timing correction node before # I'm using the earliest volume with the least number of outliers # during the first run as the base file to register to. volreg = pe.MapNode(afni.Volreg(), iterfield=['in_file'], name = 'volreg') volreg.inputs.outputtype = 'NIFTI_GZ' volreg.inputs.zpad = 4 volreg.inputs.in_file = func_files psb6351_wf.connect(extractref, 'roi_file', volreg, 'basefile') ''' McFlirt motion correct ''' # Below is the command that runs RAPIDART detection # This is the node that captures outliers in motion and intensity # Using zintensity thresholds of 1, 2, 3, or 4 # And when using norm_threshold of 2, 1, 0.5, or 0.2
def init_bold_hmc_wf(mem_gb, omp_nthreads, name="bold_hmc_wf"): """ Build a workflow to estimate head-motion parameters. This workflow estimates the motion parameters to perform :abbr:`HMC (head motion correction)` over the input :abbr:`BOLD (blood-oxygen-level dependent)` image. Workflow Graph .. workflow:: :graph2use: orig :simple_form: yes from fprodents.workflows.bold.hmc import init_bold_hmc_wf wf = init_bold_hmc_wf( mem_gb=3, omp_nthreads=1) Parameters ---------- mem_gb : :obj:`float` Size of BOLD file in GB omp_nthreads : :obj:`int` Maximum number of threads an individual process may use name : :obj:`str` Name of workflow (default: ``bold_hmc_wf``) Inputs ------ bold_file BOLD series NIfTI file raw_ref_image Reference image to which BOLD series is motion corrected Outputs ------- xforms ITKTransform file aligning each volume to ``ref_image`` movpar_file MCFLIRT motion parameters, normalized to SPM format (X, Y, Z, Rx, Ry, Rz) rms_file Framewise displacement as measured by ``fsl_motion_outliers`` [Jenkinson2002]_. """ from niworkflows.engine.workflows import LiterateWorkflow as Workflow from niworkflows.interfaces.confounds import NormalizeMotionParams workflow = Workflow(name=name) workflow.__desc__ = """\ Head-motion parameters with respect to the BOLD reference (transformation matrices, and six corresponding rotation and translation parameters) are estimated before any spatiotemporal filtering using `3dVolReg` [AFNI {afni_ver}, @afni, RRID:SCR_005927]. """.format(afni_ver=afni.Info().version() or "<ver>") inputnode = pe.Node( niu.IdentityInterface(fields=["bold_file", "raw_ref_image"]), name="inputnode") outputnode = pe.Node( niu.IdentityInterface(fields=["xforms", "movpar_file", "rmsd_file"]), name="outputnode", ) # Head motion correction (hmc) # mcflirt = pe.Node( # fsl.MCFLIRT(save_mats=True, save_plots=True, save_rms=True), # name='mcflirt', mem_gb=mem_gb * 3) # fsl2itk = pe.Node(MCFLIRT2ITK(), name='fsl2itk', # mem_gb=0.05, n_procs=omp_nthreads) mc = pe.Node( afni.Volreg(zpad=4, outputtype="NIFTI_GZ", args="-prefix NULL -twopass"), name="mc", mem_gb=mem_gb * 3, ) mc2itk = pe.Node(Volreg2ITK(), name="mcitk", mem_gb=0.05) normalize_motion = pe.Node( NormalizeMotionParams(format="AFNI"), name="normalize_motion", mem_gb=DEFAULT_MEMORY_MIN_GB, ) # def _pick_rel(rms_files): # return rms_files[-1] # workflow.connect([ # (inputnode, mcflirt, [('raw_ref_image', 'ref_file'), # ('bold_file', 'in_file')]), # (inputnode, fsl2itk, [('raw_ref_image', 'in_source'), # ('raw_ref_image', 'in_reference')]), # (mcflirt, fsl2itk, [('mat_file', 'in_files')]), # (mcflirt, normalize_motion, [('par_file', 'in_file')]), # (mcflirt, outputnode, [(('rms_files', _pick_rel), 'rmsd_file')]), # (fsl2itk, outputnode, [('out_file', 'xforms')]), # (normalize_motion, outputnode, [('out_file', 'movpar_file')]), # ]) # fmt:off workflow.connect([ (inputnode, mc, [ ('raw_ref_image', 'basefile'), ('bold_file', 'in_file'), ]), (mc, mc2itk, [('oned_matrix_save', 'in_file')]), (mc, normalize_motion, [('oned_file', 'in_file')]), (mc2itk, outputnode, [('out_file', 'xforms')]), (normalize_motion, outputnode, [('out_file', 'movpar_file')]), ]) # fmt:on return workflow
def _realign(func_filename, write_dir, caching=False, terminal_output='allatonce', environ=None): if environ is None: environ = {'AFNI_DECONFLICT': 'OVERWRITE'} if caching: memory = Memory(write_dir) clip_level = memory.cache(afni.ClipLevel) threshold = memory.cache(fsl.Threshold) volreg = memory.cache(afni.Volreg) allineate = memory.cache(afni.Allineate) copy = memory.cache(afni.Copy) copy_geom = memory.cache(fsl.CopyGeom) tstat = memory.cache(afni.TStat) for step in [threshold, volreg, allineate, tstat, copy, copy_geom]: step.interface().set_default_terminal_output(terminal_output) else: clip_level = afni.ClipLevel().run threshold = fsl.Threshold(terminal_output=terminal_output).run volreg = afni.Volreg(terminal_output=terminal_output).run allineate = afni.Allineate(terminal_output=terminal_output).run copy = afni.Copy(terminal_output=terminal_output).run copy_geom = fsl.CopyGeom(terminal_output=terminal_output).run tstat = afni.TStat(terminal_output=terminal_output).run out_clip_level = clip_level(in_file=func_filename) out_threshold = threshold(in_file=func_filename, thresh=out_clip_level.outputs.clip_val, out_file=fname_presuffix(func_filename, suffix='_thresholded', newpath=write_dir)) thresholded_filename = out_threshold.outputs.out_file out_volreg = volreg( # XXX dfile not saved in_file=thresholded_filename, out_file=fname_presuffix(thresholded_filename, suffix='_volreg', newpath=write_dir), environ=environ, oned_file=fname_presuffix(thresholded_filename, suffix='_volreg.1Dfile.1D', use_ext=False, newpath=write_dir), oned_matrix_save=fname_presuffix(thresholded_filename, suffix='_volreg.aff12.1D', use_ext=False, newpath=write_dir)) # 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='_volreg', newpath=write_dir), 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 = copy(in_file=out_allineate.outputs.out_file, out_file=fname_presuffix(out_allineate.outputs.out_file, suffix='_oblique', newpath=write_dir), environ=environ) out_copy_geom = copy_geom(dest_file=out_copy.outputs.out_file, in_file=out_volreg.outputs.out_file) oblique_allineated_filename = out_copy_geom.outputs.out_file # Create a (hopefully) nice mean image for use in the registration out_tstat = tstat(in_file=oblique_allineated_filename, args='-mean', out_file=fname_presuffix(oblique_allineated_filename, suffix='_tstat', newpath=write_dir), environ=environ) # Remove intermediate outputs if not caching: for output_file in [ thresholded_filename, out_volreg.outputs.oned_matrix_save, out_volreg.outputs.out_file, out_volreg.outputs.md1d_file, out_allineate.outputs.out_file ]: os.remove(output_file) return (oblique_allineated_filename, out_tstat.outputs.out_file, out_volreg.outputs.oned_file)
def create_preprocessed_nki(wf_name='prepoc_nki'): preproc = pe.Workflow(name=wf_name) inputNode = pe.Node(util.Identity.interface(fields=[ 'dcm_dir', 'anat_file', 'slice_timings_file', 'ref_file', 'TR' ]), name='inputspec') outputNode = pe.Node(util.Identity.interface(fields=[ 'nifti_file', 'anat_skullstripped', 'slice_time_corrected_file', 'temporal_filtering_file', 'motion_correction_file', 'registered_file', 'mat_file_reg', 'log_file_reg', 'out_trans_matrix', 'mean_func' ]), name='outputspec') ############ converting the dicom files into nii files################ dcm_to_nii = pe.Node(interface=dcm2nii.Dcmniix(), name='dcm_to_nii') dcm_to_nii.inputs.bids_format = True preproc.connect(inputNode, 'dcm_dir', dcm_to_nii, 'source_dir') preproc.connect(dcm_to_nii, 'converted_files', outputNode, 'nifti_file') #Let's start with skull stripping the anat files anat_skullstrip = pe.Node(interface=fsl.BET(), name='anat_skullstrip') anat_skullstrip.inputs.output_type = 'NIFTI_GZ' preproc.connect(inputNode, 'anat_file', anat_skullstrip, 'in_file') preproc.connect(anat_skullstrip, 'out_file', outputNode, 'anat_skullstripped') #Now we can get to preprocessing the func files slice_time_corr = pe.Node(interface=afni.SliceTimer(), name='slice_time_corr') slice_time_corr.inputs.interleaved = True preproc.connect(dcm_to_nii, 'converted_files', slice_time_corr, 'in_file') preproc.connect(inputNode, 'slice_timings_file', slice_time_corr, 'slice_timing') preproc.connect(slice_time_corr, 'out_file', outputNode, 'slice_time_corrected_file') #motion correction motion_corr = pe.Node(interface=afni.Volreg(), name='motion_corr') preproc.connect(slice_time_corr, 'out_file', motion_corr, 'in_file') preproc.connect(motion_corr, 'out_file', outputNode, 'motion_corrected_file') #temporal filtering temp_corr = pe.Node(interface=fsl.maths.TemporalFilter(), name='temp_corr') #temp_corr.inputs.lowpass = 0.01 if TR == 1400: temp_corr.inputs.highpass_sigma = 35 elif TR == 645: temp_corr.inputs.highpass_sigma = 78 else: temp_corr.inputs.highpass_sigma = 20 preproc.connect(motion_corr, 'out_file', temp_corr, 'in_file') preproc.connect(temp_corr, 'out_file', outputNode, 'temporal_filtering_file') #co-registration using FLIRT (FSL's Linear Registration tool) flirt_reg = pe.Node(interface=fsl.FLIRT(), name='flirt_reg') flirt_reg.inputs.interp = 'nearestneighbour' flirt_reg.inputs.save_log = True preproc.connect(inputNode, 'ref_file', flirt_reg, 'reference') preproc.connect(temp_corr, 'out_file', flirt_reg, 'in_file') preproc.connect(flirt_reg, 'out_file', outputNode, 'linear_registered_file') preproc.connect(flirt_reg, 'out_matrix_file', outputNode, 'mat_file_reg') preproc.connect(flirt_reg, 'out_log', outputNode, 'log_file_reg') #invert xfm if non linear registration is required inv_flirt = pe.Node(interface=fsl.ConvertXFM(), name='inv_flirt') preproc.connect(flirt_reg, 'out_matrix_file', inv_flirt, 'in_file') inv_flirt.inputs.invert_xfm = True preproc.connect(inv_flirt, 'out_file', outputNode, 'output_trans_matrix') #construct mean functional mean_func = pe.Node(interface=fsl.maths.MeanImage(), name='mean_func') mean_func.inputs.dimension = 'T' preproc.connect(flirt_reg, 'out_file', mean_func, 'in_file') preproc.connect(mean_func, 'out_file', outputNode, 'mean_func') return preproc
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
#Generic datagrabber module that wraps around glob in an NodeHash_1e88370 = pe.Node(io.S3DataGrabber(infields=['sub_id', 'run_id'], outfields=['func']), name='NodeName_1e88370') NodeHash_1e88370.inputs.bucket = 'openneuro' NodeHash_1e88370.inputs.sort_filelist = True NodeHash_1e88370.inputs.template = '%s/func/%s_task-simon_%s_bold.nii.gz' NodeHash_1e88370.inputs.anon = True NodeHash_1e88370.inputs.bucket_path = 'ds000101/ds000101_R2.0.0/uncompressed/' NodeHash_1e88370.inputs.local_directory = '/tmp' NodeHash_1e88370.inputs.template_args = dict( func=[['sub_id', 'sub_id', 'run_id']]) #Wraps command **3dvolreg** NodeHash_19153b0 = pe.MapNode(interface=afni.Volreg(), name='NodeName_19153b0', iterfield=['in_file']) NodeHash_19153b0.inputs.outputtype = 'NIFTI_GZ' #Generic datasink module to store structured outputs NodeHash_2b96290 = pe.Node(interface=io.DataSink(), name='NodeName_2b96290') NodeHash_2b96290.inputs.base_directory = '/tmp' #Create a workflow to connect all those nodes analysisflow = nipype.Workflow('MyWorkflow') analysisflow.connect(NodeHash_24ff4a0, 'sub_id', NodeHash_2b96290, 'container') analysisflow.connect(NodeHash_24ff4a0, 'run_id', NodeHash_1e88370, 'run_id') analysisflow.connect(NodeHash_24ff4a0, 'sub_id', NodeHash_1e88370, 'sub_id') analysisflow.connect(NodeHash_1e88370, 'func', NodeHash_19153b0, 'in_file') analysisflow.connect(NodeHash_19153b0, 'oned_file', NodeHash_2b96290,
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 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 _run_interface(self, runtime): is_sbref = isdefined(self.inputs.sbref_file) ref_input = self.inputs.sbref_file if is_sbref else self.inputs.in_file if self.inputs.multiecho: if len(ref_input) < 2: input_name = "sbref_file" if is_sbref else "in_file" raise ValueError("Argument 'multiecho' is True but " f"'{input_name}' has only one element.") else: # Select only the first echo (see LIMITATION above for SBRefs) ref_input = ref_input[:1] elif not is_sbref and len(ref_input) > 1: raise ValueError( "Input 'in_file' cannot point to more than one file " "for single-echo BOLD datasets.") # Build the nibabel spatial image we will work with ref_im = [] for im_i in ref_input: nib_i = nb.squeeze_image(nb.load(im_i)) if nib_i.dataobj.ndim == 3: ref_im.append(nib_i) elif nib_i.dataobj.ndim == 4: ref_im += nb.four_to_three(nib_i) ref_im = nb.squeeze_image(nb.concat_images(ref_im)) # Volumes to discard only makes sense with BOLD inputs. if not is_sbref: n_volumes_to_discard = _get_vols_to_discard(ref_im) out_ref_fname = os.path.join(runtime.cwd, "ref_bold.nii.gz") else: n_volumes_to_discard = 0 out_ref_fname = os.path.join(runtime.cwd, "ref_sbref.nii.gz") # Set interface outputs self._results["n_volumes_to_discard"] = n_volumes_to_discard self._results["ref_image"] = out_ref_fname # Slicing may induce inconsistencies with shape-dependent values in extensions. # For now, remove all. If this turns out to be a mistake, we can select extensions # that don't break pipeline stages. ref_im.header.extensions.clear() # If reference is only 1 volume, return it directly if ref_im.dataobj.ndim == 3: ref_im.to_filename(out_ref_fname) return runtime if n_volumes_to_discard == 0: if ref_im.shape[-1] > 40: ref_im = nb.Nifti1Image(ref_im.dataobj[:, :, :, 20:40], ref_im.affine, ref_im.header) ref_name = os.path.join(runtime.cwd, "slice.nii.gz") ref_im.to_filename(ref_name) if self.inputs.mc_method == "AFNI": res = afni.Volreg( in_file=ref_name, args="-Fourier -twopass", zpad=4, outputtype="NIFTI_GZ", ).run() elif self.inputs.mc_method == "FSL": res = fsl.MCFLIRT(in_file=ref_name, ref_vol=0, interpolation="sinc").run() mc_slice_nii = nb.load(res.outputs.out_file) median_image_data = np.median(mc_slice_nii.get_fdata(), axis=3) else: median_image_data = np.median( ref_im.dataobj[:, :, :, :n_volumes_to_discard], axis=3) nb.Nifti1Image(median_image_data, ref_im.affine, ref_im.header).to_filename(out_ref_fname) return runtime
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
'motion_parameters') motcor_sltimes_wf.connect(motion_correct, 'out_file', outputspec, 'motion_corrected_files') # Slice timing correction #motion_sltime_correct = pe.MapNode(fsl.SliceTimer(), # name = 'motion_sltime_correct', # iterfield = ['in_file']) #motion_sltime_correct.inputs.time_repetition = 2.0 #motion_sltime_correct.inputs.interleaved = True #motion_sltime_correct.inputs.output_type = 'NIFTI_GZ' #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'
def create_preprocess_mag_wf(): preprocmag = pe.Workflow(name="preprocmag") preprocmag.config['execution']['remove_unnecessary_outputs'] = False # define inputs inputspec = pe.Node(ul.IdentityInterface(fields=['input_mag', # raw phase data 'frac', # BET franction (-f parameter) 'rest', # volumes of rest in block design 'task', # volumes of task in block design ]), name='inputspec') # convert image to float img2float = pe.MapNode(interface=fsl.ImageMaths(out_data_type='float', op_string='', suffix='_dtype'), iterfield=['in_file'], name='img2float') # motion correct each run volreg = pe.MapNode(interface=afni.Volreg(), name='volreg', iterfield='in_file') volreg.inputs.outputtype = 'NIFTI_GZ' # calculate relative motions calcrel = pe.MapNode(ul.Function(['in_file'], ['out_file'], calcrelmotion), name='calcrel', iterfield=['in_file']) #generate motion plots plotmc = pe.MapNode(interface=fsl.PlotMotionParams(), name='plotmc', iterfield='in_file') plotmc.inputs.in_source = 'fsl' plotmc.iterables = ("plot_type", ['rotations', 'translations', 'displacement']) # register each run to first volume of first run # A) extract the first volume of the first run extract_ref = pe.MapNode(interface=fsl.ExtractROI(t_size=1, t_min=0), name='extract_ref', iterfield=['in_file']) # B) registration align2first = pe.MapNode(interface=afni.Allineate(), name='align2first', iterfield=['in_file']) align2first.inputs.num_threads = 2 align2first.inputs.out_matrix = 'align2first' # merge xfm from moco and first run alignment merge_xfm = pe.MapNode(interface=ul.Merge(2), name='merge_xfm', iterfield=['in1', 'in2']) # concatenate moco and alignment to run 1 cat_xfm = pe.MapNode(interface=afni.CatMatvec(oneline=True), name='cat_xfm', iterfield=['in_file']) cat_xfm.inputs.out_file = 'concated_xfm.aff12.1D' # apply first volume registration and motion correction in a single step applyalign = pe.MapNode(interface=afni.Allineate(), name='applyalign', iterfield=['in_file', 'in_matrix']) applyalign.inputs.num_threads = 2 applyalign.inputs.final_interpolation = 'nearestneighbour' applyalign.inputs.outputtype = 'NIFTI_GZ' # afni messes with the header (unobliques the data) this puts it back cpgeommoco = pe.MapNode(interface=fsl.CopyGeom(), name='cpgeommoco', iterfield=['dest_file', 'in_file']) # linear detrending prior to SNR calculation detrend = pe.MapNode(interface=pp.DetrendMag(), name='detrend', iterfield=['mag']) # get the mean functional of run 1 for brain extraction meanfunc = pe.MapNode(interface=fsl.ImageMaths(op_string='-Tmean', suffix='_mean'), name='meanfunc', iterfield=['in_file']) # calculate the phase noise (takes in volume of activation, if none provided them assumes resting state) calcSNR = pe.MapNode(interface=pp.RestAverage(), name='calcSNR', iterfield=['func', 'rest', 'task']) # extract brain with fsl and save the mask extractor = pe.Node(interface=fsl.BET(), name="extractor") extractor.inputs.mask = True # apply the mask to all runs maskfunc = pe.MapNode(interface=fsl.ImageMaths(suffix='_bet', op_string='-mas'), iterfield=['in_file'], name='maskfunc') # outputspec outputspec = pe.Node(ul.IdentityInterface(fields=['proc_mag','motion_par', 'motion_data', 'maxdisp_data' , 'motion_plot', 'run_txfm', 'mask_file','mean_file','snr']), name='outputspec') preprocmag = pe.Workflow(name='preprocmag') preprocmag.connect([(inputspec, img2float, [('input_mag', 'in_file')]), (img2float, volreg, [('out_file', 'in_file')]), (volreg, extract_ref, [('out_file', 'in_file')]), (extract_ref, align2first, [('roi_file', 'in_file')]), (extract_ref, align2first, [(('roi_file', pickfirst), 'reference')]), (extract_ref, applyalign, [(('roi_file', pickfirst), 'reference')]), (volreg, merge_xfm, [('oned_matrix_save', 'in2')]), (align2first, merge_xfm, [('out_matrix', 'in1')]), (merge_xfm, cat_xfm, [(('out', wraptuple), 'in_file')]), (volreg,applyalign, [('out_file', 'in_file')]), (volreg, calcrel, [('md1d_file', 'in_file')]), (volreg, plotmc, [('oned_file', 'in_file')]), (cat_xfm, applyalign, [('out_file', 'in_matrix')]), (img2float, cpgeommoco, [('out_file', 'in_file')]), (applyalign, cpgeommoco, [('out_file', 'dest_file')]), (cpgeommoco, detrend, [('out_file', 'mag')]), (detrend, meanfunc, [('detrended_mag', 'in_file')]), (inputspec, calcSNR, [('rest', 'rest'), ('task', 'task')]), (detrend, calcSNR, [('detrended_mag', 'func')]), (inputspec, extractor, [('frac', 'frac')]), (meanfunc, extractor, [(('out_file', pickfirst), 'in_file')]), (cpgeommoco, maskfunc, [('out_file', 'in_file')]), (extractor, maskfunc, [('mask_file', 'in_file2')]), (maskfunc, outputspec, [('out_file', 'proc_mag')]), (volreg, outputspec, [('oned_matrix_save', 'motion_par')]), (volreg, outputspec, [('oned_file', 'motion_data')]), (volreg, outputspec, [('md1d_file', 'maxdisp_data')]), (plotmc, outputspec, [('out_file', 'motion_plot')]), (cat_xfm, outputspec, [('out_file', 'run_txfm')]), (extractor, outputspec, [('mask_file', 'mask_file')]), (extractor, outputspec, [('out_file', 'mean_file')]), (calcSNR, outputspec, [('tsnr', 'snr')]), ]) return preprocmag
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
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') io_DataSink.inputs.base_directory = '/output' #Create a workflow to connect all those nodes
psb6351_wf.connect(id_outliers, 'out_file', getbestvol, 'outlier_count') # Extract the earliest volume with the # the fewest outliers of the first run as the reference extractref = pe.Node(fsl.ExtractROI(t_size=1), name="extractref") extractref.inputs.in_file = func_files[0] #extractref.inputs.t_min = int(np.ceil(nb.load(study_func_files[0]).shape[3]/2)) #PICKING MIDDLE psb6351_wf.connect(getbestvol, 'best_vol_num', extractref, 't_min') # Below is the command that runs AFNI's 3dvolreg command. # this is the node that performs the motion correction # I'm iterating over the functional files which I am passing # functional data from the slice timing correction node before # I'm using the earliest volume with the least number of outliers # during the first run as the base file to register to. volreg = pe.MapNode(afni.Volreg(), iterfield=['in_file'], name='volreg') volreg.inputs.outputtype = 'NIFTI_GZ' volreg.inputs.zpad = 4 volreg.inputs.in_file = func_files psb6351_wf.connect(extractref, 'roi_file', volreg, 'basefile') ''' # Motion correct functional runs to the reference (1st volume of 1st run) motion_correct = pe.MapNode(fsl.MCFLIRT(save_mats = True, save_plots = True, interpolation = 'sinc'), name = 'motion_correct', iterfield = ['in_file']) motion_correct.inputs.in_file = func_files psb6351_wf.connect(extractref, 'roi_file', motion_correct, 'ref_file') psb6351_wf.connect(motion_correct, 'par_file', outputnode, 'motion_parameters') psb6351_wf.connect(motion_correct, 'out_file', outputnode, 'realigned_files')
""" do not edit below """ # change to lib folder os.chdir(os.path.join(pathLIB, "preprocessing")) path_magn, name_magn, ext_magn = get_filename(input_magn) path_phase, name_phase, ext_phase = get_filename(input_phase) # make subfolders path_moco = os.path.join(path_magn, 'diagnosis') if not os.path.exists(path_moco): os.makedirs(path_moco) """ motion correction of magnitude data """ moco = afni.Volreg() moco.inputs.in_file = os.path.join(path_magn, name_magn + ext_magn) moco.inputs.out_file = os.path.join(path_magn, 'u' + name_magn + ext_magn) moco.inputs.args = '-base 0 -twopass -float -clipit' moco.inputs.zpad = 4 moco.inputs.interp = 'Fourier' moco.inputs.outputtype = 'NIFTI' moco.inputs.md1d_file = os.path.join(path_moco, 'max_disp.1D') moco.inputs.oned_file = os.path.join(path_moco, 'moco_params.1D') moco.inputs.oned_matrix_save = os.path.join(path_moco, 'moco_matrix.1D') moco.run() # plot motion parameters os.system("matlab" + \ " -nodisplay -nodesktop -r " + \ "\"plot_moco(\'{0}\', \'afni\', \'{1}\', \'{2}\'); exit;\"". \