Skip to content

Commit 20eeb8c

Browse files
authored
ENH: Add option to use recon-all instead of infant_recon_all (#214)
* ENH: Add option to force traditional reconall * ENH: Add anatomical pathway for `recon-all` RF: `infant_surface_recon_wf` inputs were renamed to synchronize with existing workflow. * FIX: Forgotten renamed field * FIX: Missing output files * RF: IRCA/RCA input/output field convergence * ENH: Update FS build to include RCA * FIX: Missing aseg connection to outputnode
1 parent cdd600a commit 20eeb8c

File tree

7 files changed

+78
-58
lines changed

7 files changed

+78
-58
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ ENV FSLDIR="/opt/fsl" \
208208
LD_LIBRARY_PATH="/opt/fsl/lib:$LD_LIBRARY_PATH"
209209

210210
# Install FreeSurfer
211-
COPY --from=nipreps/freesurfer@sha256:2ddc13f0a07b09e282a85d0a1aa715967841b1f4b734371dde98da1d1e87bed8 /opt/freesurfer /opt/freesurfer
211+
COPY --from=nipreps/freesurfer@sha256:7a750b97e276008030bfc68ffad3266a8838c4767398d82b25b539d389c8688e /opt/freesurfer /opt/freesurfer
212212
ENV FREESURFER_HOME="/opt/freesurfer"
213213
ENV SUBJECTS_DIR="$FREESURFER_HOME/subjects" \
214214
FUNCTIONALS_DIR="$FREESURFER_HOME/sessions" \

nibabies/cli/parser.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,12 @@ def _slice_time_ref(value, parser):
655655
metavar="FILE",
656656
help="A JSON file for customizing the derivatives queries.",
657657
)
658+
g_baby.add_argument(
659+
"--force-reconall",
660+
default=False,
661+
action="store_true",
662+
help="Force traditional FreeSurfer surface reconstruction.",
663+
)
658664
return parser
659665

660666

nibabies/config.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -543,6 +543,8 @@ class workflow(_Config):
543543
"""Remove the mean from fieldmaps."""
544544
force_syn = None
545545
"""Run *fieldmap-less* susceptibility-derived distortions estimation."""
546+
force_reconall = False
547+
"""Force traditional FreeSurfer surface reconstruction instead of infant version."""
546548
hires = None
547549
"""Run FreeSurfer ``recon-all`` with the ``-hires`` flag."""
548550
ignore = None

nibabies/workflows/anatomical/base.py

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ def init_infant_anat_wf(
1515
bids_root,
1616
existing_derivatives,
1717
freesurfer,
18+
hires,
1819
longitudinal,
1920
omp_nthreads,
2021
output_dir,
@@ -65,10 +66,10 @@ def init_infant_anat_wf(
6566
Inverse transform of the above.
6667
subject_id
6768
FreeSurfer subject ID
68-
anat2fsnative_xfm
69+
t1w2fsnative_xfm
6970
LTA-style affine matrix translating from T1w to
7071
FreeSurfer-conformed subject space
71-
fsnative2anat_xfm
72+
fsnative2t1w_xfm
7273
LTA-style affine matrix translating from FreeSurfer-conformed
7374
subject space to T1w
7475
surfaces
@@ -91,7 +92,6 @@ def init_infant_anat_wf(
9192
from .preproc import init_anat_average_wf
9293
from .registration import init_coregistration_wf
9394
from .segmentation import init_anat_segmentations_wf
94-
from .surfaces import init_infant_surface_recon_wf
9595

9696
# for now, T1w only
9797
num_t1w = len(t1w) if t1w else 0
@@ -138,8 +138,8 @@ def init_infant_anat_wf(
138138
"subject_id",
139139
"anat2std_xfm",
140140
"std2anat_xfm",
141-
"anat2fsnative_xfm",
142-
"fsnative2anat_xfm",
141+
"t1w2fsnative_xfm",
142+
"fsnative2t1w_xfm",
143143
"surfaces",
144144
"anat_aseg",
145145
"anat_aparc",
@@ -364,49 +364,55 @@ def init_infant_anat_wf(
364364
if not freesurfer:
365365
return wf
366366

367-
# if running with precomputed aseg, or JLF, pass the aseg along to FreeSurfer
368-
use_aseg = bool(precomp_aseg) or bool(segmentation_atlases)
369-
# FreeSurfer surfaces
370-
surface_recon_wf = init_infant_surface_recon_wf(
371-
age_months=age_months,
372-
use_aseg=use_aseg,
373-
)
367+
if config.workflow.force_reconall:
368+
from smriprep.workflows.surfaces import init_surface_recon_wf
369+
370+
surface_recon_wf = init_surface_recon_wf(omp_nthreads=omp_nthreads, hires=hires)
371+
else:
372+
from .surfaces import init_infant_surface_recon_wf
373+
374+
# if running with precomputed aseg, or JLF, pass the aseg along to FreeSurfer
375+
use_aseg = bool(precomp_aseg or segmentation_atlases)
376+
surface_recon_wf = init_infant_surface_recon_wf(
377+
age_months=age_months,
378+
use_aseg=use_aseg,
379+
)
374380

375381
# fmt:off
376382
wf.connect([
377-
(anat_seg_wf, surface_recon_wf, [
378-
("outputnode.anat_aseg", "inputnode.anat_aseg"),
379-
]),
380383
(inputnode, surface_recon_wf, [
381384
("subject_id", "inputnode.subject_id"),
382385
("subjects_dir", "inputnode.subjects_dir"),
383386
("t2w", "inputnode.t2w"),
384387
]),
388+
(anat_seg_wf, surface_recon_wf, [
389+
("outputnode.anat_aseg", "inputnode.ants_segs"),
390+
]),
385391
(t1w_template_wf, surface_recon_wf, [
386-
("outputnode.out_file", "inputnode.anat_orig"),
392+
("outputnode.out_file", "inputnode.t1w"),
387393
]),
388394
(t1w_preproc_wf, surface_recon_wf, [
389-
("outputnode.t1w_brain", "inputnode.anat_skullstripped"),
390-
("outputnode.t1w_preproc", "inputnode.anat_preproc"),
395+
("outputnode.t1w_brain", "inputnode.skullstripped_t1"),
396+
("outputnode.t1w_preproc", "inputnode.corrected_t1"),
391397
]),
392398
(surface_recon_wf, outputnode, [
393399
("outputnode.subjects_dir", "subjects_dir"),
394400
("outputnode.subject_id", "subject_id"),
395-
("outputnode.anat2fsnative_xfm", "anat2fsnative_xfm"),
396-
("outputnode.fsnative2anat_xfm", "fsnative2anat_xfm"),
401+
("outputnode.t1w2fsnative_xfm", "t1w2fsnative_xfm"),
402+
("outputnode.fsnative2t1w_xfm", "fsnative2t1w_xfm"),
397403
("outputnode.surfaces", "surfaces"),
398-
("outputnode.anat_aparc", "anat_aparc"),
399-
("outputnode.anat_aseg", "anat_aseg"),
404+
("outputnode.out_aparc", "anat_aparc"),
405+
("outputnode.out_aseg", "anat_aseg"),
400406
]),
401407
(surface_recon_wf, anat_reports_wf, [
402408
("outputnode.subject_id", "inputnode.subject_id"),
403409
("outputnode.subjects_dir", "inputnode.subjects_dir"),
404410
]),
405411
(surface_recon_wf, anat_derivatives_wf, [
406-
("outputnode.anat_aseg", "inputnode.t1w_fs_aseg"),
407-
("outputnode.anat_aparc", "inputnode.t1w_fs_aparc"),
408-
("outputnode.anat2fsnative_xfm", "inputnode.t1w2fsnative_xfm"),
409-
("outputnode.fsnative2anat_xfm", "inputnode.fsnative2t1w_xfm"),
412+
("outputnode.out_aseg", "inputnode.t1w_fs_aseg"),
413+
("outputnode.out_aparc", "inputnode.t1w_fs_aparc"),
414+
("outputnode.t1w2fsnative_xfm", "inputnode.t1w2fsnative_xfm"),
415+
("outputnode.fsnative2t1w_xfm", "inputnode.fsnative2t1w_xfm"),
410416
("outputnode.surfaces", "inputnode.surfaces"),
411417
]),
412418
])

nibabies/workflows/anatomical/surfaces.py

Lines changed: 28 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -15,17 +15,19 @@ def init_infant_surface_recon_wf(*, age_months, use_aseg=False, name="infant_sur
1515

1616
from nibabies.interfaces.freesurfer import InfantReconAll
1717

18+
# Synchronized inputs to smriprep.workflows.surfaces.init_surface_recon_wf
1819
wf = LiterateWorkflow(name=name)
1920
inputnode = pe.Node(
2021
niu.IdentityInterface(
2122
fields=[
2223
"subjects_dir",
2324
"subject_id",
24-
"anat_orig",
25-
"anat_skullstripped",
26-
"anat_preproc",
27-
"anat_aseg",
25+
"t1w",
2826
"t2w",
27+
"flair",
28+
"skullstripped_t1",
29+
"corrected_t1",
30+
"ants_segs",
2931
],
3032
),
3133
name="inputnode",
@@ -35,11 +37,11 @@ def init_infant_surface_recon_wf(*, age_months, use_aseg=False, name="infant_sur
3537
fields=[
3638
"subjects_dir",
3739
"subject_id",
38-
"anat2fsnative_xfm",
39-
"fsnative2anat_xfm",
40+
"t1w2fsnative_xfm",
41+
"fsnative2t1w_xfm",
4042
"surfaces",
41-
"anat_aseg",
42-
"anat_aparc",
43+
"out_aseg",
44+
"out_aparc",
4345
]
4446
),
4547
name="outputnode",
@@ -57,14 +59,14 @@ def init_infant_surface_recon_wf(*, age_months, use_aseg=False, name="infant_sur
5759
recon = pe.Node(InfantReconAll(age=age_months), name="reconall")
5860
fssource = pe.Node(nio.FreeSurferSource(), name='fssource', run_without_submitting=True)
5961

60-
fsnative2anat_xfm = pe.Node(
62+
fsnative2t1w_xfm = pe.Node(
6163
RobustRegister(auto_sens=True, est_int_scale=True),
62-
name='fsnative2anat_xfm',
64+
name='fsnative2t1w_xfm',
6365
)
6466

65-
anat2fsnative_xfm = pe.Node(
67+
t1w2fsnative_xfm = pe.Node(
6668
LTAConvert(out_lta=True, invert=True),
67-
name="anat2fsnative_xfm",
69+
name="t1w2fsnative_xfm",
6870
)
6971

7072
# convert generated surfaces to GIFTIs
@@ -73,7 +75,7 @@ def init_infant_surface_recon_wf(*, age_months, use_aseg=False, name="infant_sur
7375
aparc2nii = pe.Node(fs.MRIConvert(out_type="niigz"), name="aparc2nii")
7476

7577
if use_aseg:
76-
wf.connect(inputnode, "anat_aseg", recon, "aseg_file")
78+
wf.connect(inputnode, "ants_segs", recon, "aseg_file")
7779

7880
# fmt: off
7981
wf.connect([
@@ -82,7 +84,7 @@ def init_infant_surface_recon_wf(*, age_months, use_aseg=False, name="infant_sur
8284
('subject_id', 'subject_id'),
8385
]),
8486
(inputnode, recon, [
85-
('anat_skullstripped', 'mask_file'),
87+
('skullstripped_t1', 'mask_file'),
8688
('subject_id', 'subject_id'),
8789
]),
8890
(gen_recon_outdir, recon, [
@@ -103,24 +105,27 @@ def init_infant_surface_recon_wf(*, age_months, use_aseg=False, name="infant_sur
103105
(fssource, outputnode, [
104106
(('aseg', _replace_mgz), 'anat_aseg'),
105107
]),
106-
(inputnode, fsnative2anat_xfm, [('anat_skullstripped', 'target_file')]),
107-
(fssource, fsnative2anat_xfm, [
108+
(inputnode, fsnative2t1w_xfm, [('skullstripped_t1', 'target_file')]),
109+
(fssource, fsnative2t1w_xfm, [
108110
(('norm', _replace_mgz), 'source_file'),
109111
]),
110-
(fsnative2anat_xfm, anat2fsnative_xfm, [('out_reg_file', 'in_lta')]),
112+
(fsnative2t1w_xfm, t1w2fsnative_xfm, [('out_reg_file', 'in_lta')]),
111113
(fssource, aparc2nii, [
112114
('aparc_aseg', 'in_file'),
113115
]),
114116
(aparc2nii, outputnode, [
115-
('out_file', 'anat_aparc'),
117+
('out_file', 'out_aparc'),
116118
]),
117-
(fsnative2anat_xfm, outputnode, [
118-
('out_reg_file', 'fsnative2anat_xfm'),
119+
(fssource, outputnode, [
120+
(('aseg', _replace_mgz), 'out_aseg'),
121+
]),
122+
(fsnative2t1w_xfm, outputnode, [
123+
('out_reg_file', 'fsnative2t1w_xfm'),
119124
]),
120-
(anat2fsnative_xfm, outputnode, [
121-
('out_lta', 'anat2fsnative_xfm'),
125+
(t1w2fsnative_xfm, outputnode, [
126+
('out_lta', 't1w2fsnative_xfm'),
122127
]),
123-
(fsnative2anat_xfm, gifti_surface_wf, [
128+
(fsnative2t1w_xfm, gifti_surface_wf, [
124129
('out_reg_file', 'inputnode.fsnative2t1w_xfm')]),
125130
(gifti_surface_wf, outputnode, [
126131
('outputnode.surfaces', 'surfaces'),

nibabies/workflows/base.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,7 @@ def init_single_subject_wf(subject_id, session_id=None):
323323
bids_root=config.execution.bids_dir,
324324
existing_derivatives=derivatives,
325325
freesurfer=config.workflow.run_reconall,
326+
hires=config.workflow.hires,
326327
longitudinal=config.workflow.longitudinal,
327328
omp_nthreads=config.nipype.omp_nthreads,
328329
output_dir=nibabies_dir,
@@ -475,8 +476,8 @@ def init_single_subject_wf(subject_id, session_id=None):
475476
# Undefined if --fs-no-reconall, but this is safe
476477
('outputnode.subjects_dir', 'inputnode.subjects_dir'),
477478
('outputnode.subject_id', 'inputnode.subject_id'),
478-
('outputnode.anat2fsnative_xfm', 'inputnode.anat2fsnative_xfm'),
479-
('outputnode.fsnative2anat_xfm', 'inputnode.fsnative2anat_xfm'),
479+
('outputnode.t1w2fsnative_xfm', 'inputnode.t1w2fsnative_xfm'),
480+
('outputnode.fsnative2t1w_xfm', 'inputnode.fsnative2t1w_xfm'),
480481
]),
481482
])
482483
# fmt: on

nibabies/workflows/bold/base.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,9 @@ def init_func_preproc_wf(bold_file, has_fieldmap=False, existing_derivatives=Non
123123
FreeSurfer SUBJECTS_DIR
124124
subject_id
125125
FreeSurfer subject ID
126-
anat2fsnative_xfm
126+
t1w2fsnative_xfm
127127
LTA-style affine matrix translating from T1w to FreeSurfer-conformed subject space
128-
fsnative2anat_xfm
128+
fsnative2t1w_xfm
129129
LTA-style affine matrix translating from FreeSurfer-conformed subject space to T1w
130130
bold_ref
131131
BOLD reference file
@@ -333,8 +333,8 @@ def init_func_preproc_wf(bold_file, has_fieldmap=False, existing_derivatives=Non
333333
"fmap_id",
334334
"sdc_method",
335335
# if reconstructing with FreeSurfer (optional)
336-
"anat2fsnative_xfm",
337-
"fsnative2anat_xfm",
336+
"t1w2fsnative_xfm",
337+
"fsnative2t1w_xfm",
338338
"subject_id",
339339
"subjects_dir",
340340
]
@@ -596,7 +596,7 @@ def init_func_preproc_wf(bold_file, has_fieldmap=False, existing_derivatives=Non
596596
# Undefined if --fs-no-reconall, but this is safe
597597
('subjects_dir', 'inputnode.subjects_dir'),
598598
('subject_id', 'inputnode.subject_id'),
599-
('fsnative2anat_xfm', 'inputnode.fsnative2t1w_xfm'),
599+
('fsnative2t1w_xfm', 'inputnode.fsnative2t1w_xfm'),
600600
]),
601601
(bold_final, bold_reg_wf, [
602602
("boldref", "inputnode.ref_bold_brain")]),
@@ -858,7 +858,7 @@ def init_func_preproc_wf(bold_file, has_fieldmap=False, existing_derivatives=Non
858858
(inputnode, bold_surf_wf, [
859859
('subjects_dir', 'inputnode.subjects_dir'),
860860
('subject_id', 'inputnode.subject_id'),
861-
('anat2fsnative_xfm', 'inputnode.t1w2fsnative_xfm')]),
861+
('t1w2fsnative_xfm', 'inputnode.t1w2fsnative_xfm')]),
862862
(bold_t1_trans_wf, bold_surf_wf, [('outputnode.bold_t1', 'inputnode.source_file')]),
863863
(bold_surf_wf, outputnode, [('outputnode.surfaces', 'surfaces')]),
864864
(bold_surf_wf, func_derivatives_wf, [

0 commit comments

Comments
 (0)