Skip to content

Commit

Permalink
rf: Reconstruct motion confounds from minimal derivatives
Browse files Browse the repository at this point in the history
  • Loading branch information
effigies committed Jan 29, 2025
1 parent 607c8e9 commit 85f725c
Show file tree
Hide file tree
Showing 4 changed files with 18 additions and 36 deletions.
2 changes: 1 addition & 1 deletion fmriprep/workflows/bold/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -673,7 +673,7 @@ def init_bold_wf(
]),
(bold_fit_wf, bold_confounds_wf, [
('outputnode.bold_mask', 'inputnode.bold_mask'),
('outputnode.movpar_file', 'inputnode.movpar_file'),
('outputnode.motion_xfm', 'inputnode.motion_xfm'),
('outputnode.rmsd_file', 'inputnode.rmsd_file'),
('outputnode.boldref2anat_xfm', 'inputnode.boldref2anat_xfm'),
('outputnode.dummy_scans', 'inputnode.skip_vols'),
Expand Down
30 changes: 14 additions & 16 deletions fmriprep/workflows/bold/confounds.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
from ...interfaces.confounds import (
FilterDropped,
FMRISummary,
FramewiseDisplacement,
FSLMotionParams,
GatherConfounds,
RenameACompCor,
)
Expand Down Expand Up @@ -120,8 +122,8 @@ def init_bold_confs_wf(
when available.
bold_mask
BOLD series mask
movpar_file
SPM-formatted motion parameters file
motion_xfm
ITK-formatted head motion transforms
rmsd_file
Root mean squared deviation as measured by ``fsl_motion_outliers`` [Jenkinson2002]_.
skip_vols
Expand Down Expand Up @@ -221,7 +223,7 @@ def init_bold_confs_wf(
fields=[
'bold',
'bold_mask',
'movpar_file',
'motion_xfm',
'rmsd_file',
'skip_vols',
't1w_mask',
Expand Down Expand Up @@ -262,8 +264,11 @@ def init_bold_confs_wf(
mem_gb=mem_gb,
)

# Motion parameters
motion_params = pe.Node(FSLMotionParams(), name='motion_params')

# Frame displacement
fdisp = pe.Node(nac.FramewiseDisplacement(parameter_source='SPM'), name='fdisp', mem_gb=mem_gb)
fdisp = pe.Node(FramewiseDisplacement(), name='fdisp', mem_gb=mem_gb)

# Generate aCompCor probseg maps
acc_masks = pe.Node(aCompCorMasks(is_aseg=freesurfer), name='acc_masks')
Expand Down Expand Up @@ -367,12 +372,6 @@ def init_bold_confs_wf(
mem_gb=0.01,
run_without_submitting=True,
)
add_motion_headers = pe.Node(
AddTSVHeader(columns=['trans_x', 'trans_y', 'trans_z', 'rot_x', 'rot_y', 'rot_z']),
name='add_motion_headers',
mem_gb=0.01,
run_without_submitting=True,
)
add_rmsd_header = pe.Node(
AddTSVHeader(columns=['rmsd']),
name='add_rmsd_header',
Expand Down Expand Up @@ -518,12 +517,13 @@ def _select_cols(table):
if not col.startswith(('a_comp_cor_', 't_comp_cor_', 'std_dvars'))
]

# fmt:off
workflow.connect([
# connect inputnode to each non-anatomical confound node
(inputnode, dvars, [('bold', 'in_file'),
('bold_mask', 'in_mask')]),
(inputnode, fdisp, [('movpar_file', 'in_file')]),
(inputnode, motion_params, [('motion_xfm', 'xfm_file'),
('bold_mask', 'boldref_file')]),
(motion_params, fdisp, [('out_file', 'in_file')]),
# Brain mask
(inputnode, t1w_mask_tfm, [('t1w_mask', 'input_image'),
('bold_mask', 'reference_image'),
Expand Down Expand Up @@ -566,7 +566,6 @@ def _select_cols(table):
(merge_rois, signals, [('out', 'label_files')]),

# Collate computed confounds together
(inputnode, add_motion_headers, [('movpar_file', 'in_file')]),
(inputnode, add_rmsd_header, [('rmsd_file', 'in_file')]),
(dvars, add_dvars_header, [('out_nstd', 'in_file')]),
(dvars, add_std_dvars_header, [('out_std', 'in_file')]),
Expand All @@ -576,7 +575,7 @@ def _select_cols(table):
('pre_filter_file', 'cos_basis')]),
(rename_acompcor, concat, [('components_file', 'acompcor')]),
(crowncompcor, concat, [('components_file', 'crowncompcor')]),
(add_motion_headers, concat, [('out_file', 'motion')]),
(motion_params, concat, [('out_file', 'motion')]),
(add_rmsd_header, concat, [('out_file', 'rmsd')]),
(add_dvars_header, concat, [('out_file', 'dvars')]),
(add_std_dvars_header, concat, [('out_file', 'std_dvars')]),
Expand Down Expand Up @@ -617,8 +616,7 @@ def _select_cols(table):
(concat, conf_corr_plot, [('confounds_file', 'confounds_file'),
(('confounds_file', _select_cols), 'columns')]),
(conf_corr_plot, ds_report_conf_corr, [('out_file', 'in_file')]),
])
# fmt: on
]) # fmt: skip

return workflow

Expand Down
7 changes: 1 addition & 6 deletions fmriprep/workflows/bold/fit.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,8 +178,6 @@ def init_bold_fit_wf(
boldref2fmap_xfm
Affine transform mapping from BOLD reference space to the fieldmap
space, if applicable.
movpar_file
MCFLIRT motion parameters, normalized to SPM format (X, Y, Z, Rx, Ry, Rz)
rmsd_file
Root mean squared deviation as measured by ``fsl_motion_outliers`` [Jenkinson2002]_.
dummy_scans
Expand Down Expand Up @@ -287,7 +285,6 @@ def init_bold_fit_wf(
'motion_xfm',
'boldref2anat_xfm',
'boldref2fmap_xfm',
'movpar_file',
'rmsd_file',
],
),
Expand All @@ -303,7 +300,7 @@ def init_bold_fit_wf(
)
fmapref_buffer = pe.Node(niu.Function(function=_select_ref), name='fmapref_buffer')
hmc_buffer = pe.Node(
niu.IdentityInterface(fields=['hmc_xforms', 'movpar_file', 'rmsd_file']), name='hmc_buffer'
niu.IdentityInterface(fields=['hmc_xforms', 'rmsd_file']), name='hmc_buffer'
)
fmapreg_buffer = pe.Node(
niu.IdentityInterface(fields=['boldref2fmap_xfm']), name='fmapreg_buffer'
Expand Down Expand Up @@ -357,7 +354,6 @@ def init_bold_fit_wf(
(fmapreg_buffer, outputnode, [('boldref2fmap_xfm', 'boldref2fmap_xfm')]),
(hmc_buffer, outputnode, [
('hmc_xforms', 'motion_xfm'),
('movpar_file', 'movpar_file'),
('rmsd_file', 'rmsd_file'),
]),
(inputnode, func_fit_reports_wf, [
Expand Down Expand Up @@ -449,7 +445,6 @@ def init_bold_fit_wf(
]),
(bold_hmc_wf, ds_hmc_wf, [('outputnode.xforms', 'inputnode.xforms')]),
(bold_hmc_wf, hmc_buffer, [
('outputnode.movpar_file', 'movpar_file'),
('outputnode.rmsd_file', 'rmsd_file'),
]),
(ds_hmc_wf, hmc_buffer, [('outputnode.xforms', 'hmc_xforms')]),
Expand Down
15 changes: 2 additions & 13 deletions fmriprep/workflows/bold/hmc.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,14 +73,11 @@ def init_bold_hmc_wf(mem_gb: float, omp_nthreads: int, name: str = 'bold_hmc_wf'
-------
xforms
ITKTransform file aligning each volume to ``ref_image``
movpar_file
MCFLIRT motion parameters, normalized to SPM format (X, Y, Z, Rx, Ry, Rz)
rmsd_file
Root mean squared deviation as measured by ``fsl_motion_outliers`` [Jenkinson2002]_.
"""
from niworkflows.engine.workflows import LiterateWorkflow as Workflow
from niworkflows.interfaces.confounds import NormalizeMotionParams
from niworkflows.interfaces.itk import MCFLIRT2ITK

workflow = Workflow(name=name)
Expand All @@ -95,7 +92,7 @@ def init_bold_hmc_wf(mem_gb: float, omp_nthreads: int, name: str = 'bold_hmc_wf'
niu.IdentityInterface(fields=['bold_file', 'raw_ref_image']), name='inputnode'
)
outputnode = pe.Node(
niu.IdentityInterface(fields=['xforms', 'movpar_file', 'rmsd_file']), name='outputnode'
niu.IdentityInterface(fields=['xforms', 'rmsd_file']), name='outputnode'
)

# Head motion correction (hmc)
Expand All @@ -107,25 +104,17 @@ def init_bold_hmc_wf(mem_gb: float, omp_nthreads: int, name: str = 'bold_hmc_wf'

fsl2itk = pe.Node(MCFLIRT2ITK(), name='fsl2itk', mem_gb=0.05, n_procs=omp_nthreads)

normalize_motion = pe.Node(
NormalizeMotionParams(format='FSL'), name='normalize_motion', mem_gb=DEFAULT_MEMORY_MIN_GB
)

def _pick_rel(rms_files):
return rms_files[-1]

# fmt:off
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:on
]) # fmt:skip

return workflow

0 comments on commit 85f725c

Please sign in to comment.