Skip to content

Commit 21ac1b8

Browse files
authored
Merge pull request #1270 from effigies/enh/sbref
ENH: Use single-band reference images when available
2 parents f592879 + a66b2b1 commit 21ac1b8

File tree

4 files changed

+43
-8
lines changed

4 files changed

+43
-8
lines changed

docs/workflows.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,6 +294,9 @@ BOLD reference image estimation
294294

295295
This workflow estimates a reference image for a
296296
:abbr:`BOLD (blood-oxygen level-dependent)` series.
297+
If a single-band reference ("sbref") image associated with the BOLD series is
298+
available, then it is used directly.
299+
If not, a reference image is estimated from the BOLD series as follows:
297300
When T1-saturation effects ("dummy scans" or non-steady state volumes) are
298301
detected, they are averaged and used as reference due to their
299302
superior tissue contrast.

fmriprep/cli/run.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ def get_parser():
107107
g_conf = parser.add_argument_group('Workflow configuration')
108108
g_conf.add_argument(
109109
'--ignore', required=False, action='store', nargs="+", default=[],
110-
choices=['fieldmaps', 'slicetiming'],
110+
choices=['fieldmaps', 'slicetiming', 'sbref'],
111111
help='ignore selected aspects of the input dataset to disable corresponding '
112112
'parts of the workflow (a space delimited list)')
113113
g_conf.add_argument(

fmriprep/workflows/bold/base.py

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,6 +242,7 @@ def init_func_preproc_wf(bold_file, ignore, freesurfer,
242242
'Memory resampled/largemem=%.2f/%.2f GB.'),
243243
ref_file, mem_gb['filesize'], bold_tlen, mem_gb['resampled'], mem_gb['largemem'])
244244

245+
sbref_file = None
245246
# For doc building purposes
246247
if layout is None or bold_file == 'bold_preprocesing':
247248
LOGGER.log(25, 'No valid layout: building empty workflow.')
@@ -259,6 +260,28 @@ def init_func_preproc_wf(bold_file, ignore, freesurfer,
259260
run_stc = True
260261
multiecho = False
261262
else:
263+
# Find associated sbref, if possible
264+
entities = layout.parse_file_entities(ref_file)
265+
entities['type'] = 'sbref'
266+
files = layout.get(**entities)
267+
refbase = os.path.basename(ref_file)
268+
if 'sbref' in ignore:
269+
LOGGER.info("Single-band reference files ignored.")
270+
elif files and multiecho:
271+
LOGGER.warning("Single-band reference found, but not supported in "
272+
"multi-echo workflows at this time. Ignoring.")
273+
elif files:
274+
sbref_file = files[0].filename
275+
sbbase = os.path.basename(sbref_file)
276+
if len(files) > 1:
277+
LOGGER.warning(
278+
"Multiple single-band reference files found for {}; using "
279+
"{}".format(refbase, sbbase))
280+
else:
281+
LOGGER.log(25, "Using single-band reference file {}".format(sbbase))
282+
else:
283+
LOGGER.log(25, "No single-band-reference found for {}".format(refbase))
284+
262285
metadata = layout.get_metadata(ref_file)
263286

264287
# Find fieldmaps. Options: (phase1|phase2|phasediff|epi|fieldmap|syn)
@@ -312,13 +335,15 @@ def init_func_preproc_wf(bold_file, ignore, freesurfer,
312335
"""
313336

314337
inputnode = pe.Node(niu.IdentityInterface(
315-
fields=['bold_file', 'subjects_dir', 'subject_id',
338+
fields=['bold_file', 'sbref_file', 'subjects_dir', 'subject_id',
316339
't1_preproc', 't1_brain', 't1_mask', 't1_seg', 't1_tpms',
317340
't1_aseg', 't1_aparc',
318341
't1_2_mni_forward_transform', 't1_2_mni_reverse_transform',
319342
't1_2_fsnative_forward_transform', 't1_2_fsnative_reverse_transform']),
320343
name='inputnode')
321344
inputnode.inputs.bold_file = bold_file
345+
if sbref_file is not None:
346+
inputnode.inputs.sbref_file = sbref_file
322347

323348
outputnode = pe.Node(niu.IdentityInterface(
324349
fields=['bold_t1', 'bold_mask_t1', 'bold_aseg_t1', 'bold_aparc_t1', 'cifti_variant',
@@ -441,7 +466,8 @@ def init_func_preproc_wf(bold_file, ignore, freesurfer,
441466
# MAIN WORKFLOW STRUCTURE #######################################################
442467
workflow.connect([
443468
# Generate early reference
444-
(inputnode, bold_reference_wf, [('bold_file', 'inputnode.bold_file')]),
469+
(inputnode, bold_reference_wf, [('bold_file', 'inputnode.bold_file'),
470+
('sbref_file', 'inputnode.sbref_file')]),
445471
# BOLD buffer has slice-time corrected if it was run, original otherwise
446472
(boldbuffer, bold_split, [('bold_file', 'in_file')]),
447473
# HMC
@@ -549,7 +575,8 @@ def init_func_preproc_wf(bold_file, ignore, freesurfer,
549575
# Replace reference with the echo selected with FirstEcho
550576
workflow.disconnect([
551577
(inputnode, bold_reference_wf, [
552-
('bold_file', 'inputnode.bold_file')]),
578+
('bold_file', 'inputnode.bold_file'),
579+
('sbref_file', 'inputnode.sbref_file')]),
553580
(bold_reference_wf, boldbuffer, [
554581
('outputnode.bold_file', 'bold_file')]),
555582
])

fmriprep/workflows/bold/util.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,8 @@ def init_bold_reference_wf(omp_nthreads, bold_file=None, name='bold_reference_wf
8787
First, a reference volume and its skull-stripped version were generated
8888
using a custom methodology of *fMRIPrep*.
8989
"""
90-
inputnode = pe.Node(niu.IdentityInterface(fields=['bold_file']), name='inputnode')
90+
inputnode = pe.Node(niu.IdentityInterface(fields=['bold_file', 'sbref_file']),
91+
name='inputnode')
9192
outputnode = pe.Node(
9293
niu.IdentityInterface(fields=['bold_file', 'raw_ref_image', 'skip_vols', 'ref_image',
9394
'ref_image_brain', 'bold_mask', 'validation_report',
@@ -102,16 +103,20 @@ def init_bold_reference_wf(omp_nthreads, bold_file=None, name='bold_reference_wf
102103

103104
gen_ref = pe.Node(EstimateReferenceImage(), name="gen_ref",
104105
mem_gb=1) # OE: 128x128x128x50 * 64 / 8 ~ 900MB.
106+
# Re-run validation; no effect if no sbref; otherwise apply same validation to sbref as bold
107+
validate_ref = pe.Node(ValidateImage(), name='validate_ref', mem_gb=DEFAULT_MEMORY_MIN_GB)
105108
enhance_and_skullstrip_bold_wf = init_enhance_and_skullstrip_bold_wf(omp_nthreads=omp_nthreads)
106109

107110
workflow.connect([
108111
(inputnode, validate, [('bold_file', 'in_file')]),
112+
(inputnode, gen_ref, [('sbref_file', 'sbref_file')]),
109113
(validate, gen_ref, [('out_file', 'in_file')]),
110-
(gen_ref, enhance_and_skullstrip_bold_wf, [('ref_image', 'inputnode.in_file')]),
114+
(gen_ref, validate_ref, [('ref_image', 'in_file')]),
115+
(validate_ref, enhance_and_skullstrip_bold_wf, [('out_file', 'inputnode.in_file')]),
111116
(validate, outputnode, [('out_file', 'bold_file'),
112117
('out_report', 'validation_report')]),
113-
(gen_ref, outputnode, [('ref_image', 'raw_ref_image'),
114-
('n_volumes_to_discard', 'skip_vols')]),
118+
(gen_ref, outputnode, [('n_volumes_to_discard', 'skip_vols')]),
119+
(validate_ref, outputnode, [('out_file', 'raw_ref_image')]),
115120
(enhance_and_skullstrip_bold_wf, outputnode, [
116121
('outputnode.bias_corrected_file', 'ref_image'),
117122
('outputnode.mask_file', 'bold_mask'),

0 commit comments

Comments
 (0)