24
24
25
25
import typing as ty
26
26
27
+ import bids
27
28
from nipype import logging
28
29
from nipype .interfaces import (
29
30
freesurfer as fs ,
47
48
from niworkflows .interfaces .freesurfer import (
48
49
StructuralReference ,
49
50
)
51
+ from niworkflows .interfaces .gradunwarp import GradUnwarp
50
52
from niworkflows .interfaces .header import ValidateImage
51
53
from niworkflows .interfaces .images import Conform , TemplateDimensions
52
54
from niworkflows .interfaces .nibabel import ApplyMask , Binarize
53
55
from niworkflows .interfaces .nitransforms import ConcatenateXFMs
54
56
from niworkflows .utils .misc import add_suffix
55
57
from niworkflows .utils .spaces import Reference , SpatialReferences
58
+ from niworkflows .workflows .gradunwarp import init_gradunwarp_wf
56
59
57
60
from ..data import load_resource
58
61
from ..interfaces import DerivativesDataSink
94
97
def init_anat_preproc_wf (
95
98
* ,
96
99
bids_root : str ,
100
+ layout : bids .BIDSLayout ,
97
101
output_dir : str ,
98
102
freesurfer : bool ,
99
103
hires : bool ,
@@ -113,6 +117,7 @@ def init_anat_preproc_wf(
113
117
name : str = 'anat_preproc_wf' ,
114
118
skull_strip_fixed_seed : bool = False ,
115
119
fs_no_resume : bool = False ,
120
+ gradunwarp_file : str | None = None ,
116
121
):
117
122
"""
118
123
Stage the anatomical preprocessing steps of *sMRIPrep*.
@@ -150,6 +155,8 @@ def init_anat_preproc_wf(
150
155
----------
151
156
bids_root : :obj:`str`
152
157
Path of the input BIDS dataset root
158
+ layout : BIDSLayout object
159
+ BIDS dataset layout
153
160
output_dir : :obj:`str`
154
161
Directory in which to save derivatives
155
162
freesurfer : :obj:`bool`
@@ -189,6 +196,8 @@ def init_anat_preproc_wf(
189
196
EXPERT: Import pre-computed FreeSurfer reconstruction without resuming.
190
197
The user is responsible for ensuring that all necessary files are present.
191
198
(default: ``False``).
199
+ gradunwarp_file : :obj:`str`, optional
200
+ Gradient unwarping filename (default: None)
192
201
193
202
Inputs
194
203
------
@@ -265,6 +274,7 @@ def init_anat_preproc_wf(
265
274
266
275
anat_fit_wf = init_anat_fit_wf (
267
276
bids_root = bids_root ,
277
+ layout = layout ,
268
278
output_dir = output_dir ,
269
279
freesurfer = freesurfer ,
270
280
hires = hires ,
@@ -282,6 +292,7 @@ def init_anat_preproc_wf(
282
292
omp_nthreads = omp_nthreads ,
283
293
skull_strip_fixed_seed = skull_strip_fixed_seed ,
284
294
fs_no_resume = fs_no_resume ,
295
+ gradunwarp_file = gradunwarp_file ,
285
296
)
286
297
template_iterator_wf = init_template_iterator_wf (spaces = spaces , sloppy = sloppy )
287
298
ds_std_volumes_wf = init_ds_anat_volumes_wf (
@@ -448,6 +459,7 @@ def init_anat_preproc_wf(
448
459
def init_anat_fit_wf (
449
460
* ,
450
461
bids_root : str ,
462
+ layout : bids .BIDSLayout ,
451
463
output_dir : str ,
452
464
freesurfer : bool ,
453
465
hires : bool ,
@@ -466,6 +478,7 @@ def init_anat_fit_wf(
466
478
name = 'anat_fit_wf' ,
467
479
skull_strip_fixed_seed : bool = False ,
468
480
fs_no_resume : bool = False ,
481
+ gradunwarp_file : str | None = None ,
469
482
):
470
483
"""
471
484
Stage the anatomical preprocessing steps of *sMRIPrep*.
@@ -511,6 +524,8 @@ def init_anat_fit_wf(
511
524
----------
512
525
bids_root : :obj:`str`
513
526
Path of the input BIDS dataset root
527
+ layout : BIDSLayout object
528
+ BIDS dataset layout
514
529
output_dir : :obj:`str`
515
530
Directory in which to save derivatives
516
531
freesurfer : :obj:`bool`
@@ -546,6 +561,12 @@ def init_anat_fit_wf(
546
561
Do not use a random seed for skull-stripping - will ensure
547
562
run-to-run replicability when used with --omp-nthreads 1
548
563
(default: ``False``).
564
+ fs_no_resume : bool
565
+ EXPERT: Import pre-computed FreeSurfer reconstruction without resuming.
566
+ The user is responsible for ensuring that all necessary files are present.
567
+ (default: ``False``).
568
+ gradunwarp_file : :obj:`str`, optional
569
+ Gradient unwarping filename (default: None)
549
570
550
571
Inputs
551
572
------
@@ -760,12 +781,14 @@ def init_anat_fit_wf(
760
781
non-uniformity (INU) with `N4BiasFieldCorrection` [@n4], distributed with ANTs { ants_ver }
761
782
[@ants, RRID:SCR_004757]"""
762
783
desc += '.\n ' if num_t1w > 1 else ', and used as T1w-reference throughout the workflow.\n '
763
-
784
+ t1w_metas = [ layout . get_file ( t ). get_metadata () for t in t1w ]
764
785
anat_template_wf = init_anat_template_wf (
765
786
longitudinal = longitudinal ,
766
787
omp_nthreads = omp_nthreads ,
767
788
num_files = num_t1w ,
768
789
contrast = 'T1w' ,
790
+ gradunwarp_file = gradunwarp_file ,
791
+ metadata = t1w_metas ,
769
792
name = 'anat_template_wf' ,
770
793
)
771
794
ds_template_wf = init_ds_template_wf (output_dir = output_dir , num_t1w = num_t1w )
@@ -1131,11 +1154,14 @@ def init_anat_fit_wf(
1131
1154
1132
1155
if t2w and not have_t2w :
1133
1156
LOGGER .info ('ANAT Stage 7: Creating T2w template' )
1157
+ t2w_metas = [layout .get_file (t ).get_metadata () for t in t1w ]
1134
1158
t2w_template_wf = init_anat_template_wf (
1135
1159
longitudinal = longitudinal ,
1136
1160
omp_nthreads = omp_nthreads ,
1137
1161
num_files = len (t2w ),
1138
1162
contrast = 'T2w' ,
1163
+ metadata = t2w_metas ,
1164
+ gradunwarp_file = gradunwarp_file ,
1139
1165
name = 't2w_template_wf' ,
1140
1166
)
1141
1167
bbreg = pe .Node (
@@ -1376,6 +1402,8 @@ def init_anat_template_wf(
1376
1402
omp_nthreads : int ,
1377
1403
num_files : int ,
1378
1404
contrast : str ,
1405
+ metadata : dict ,
1406
+ gradunwarp_file : str | None = None ,
1379
1407
name : str = 'anat_template_wf' ,
1380
1408
):
1381
1409
"""
@@ -1388,7 +1416,8 @@ def init_anat_template_wf(
1388
1416
1389
1417
from smriprep.workflows.anatomical import init_anat_template_wf
1390
1418
wf = init_anat_template_wf(
1391
- longitudinal=False, omp_nthreads=1, num_files=1, contrast="T1w"
1419
+ longitudinal=False, omp_nthreads=1, num_files=1, contrast="T1w",
1420
+ gradunwarp_file=None,
1392
1421
)
1393
1422
1394
1423
Parameters
@@ -1402,6 +1431,8 @@ def init_anat_template_wf(
1402
1431
Number of images
1403
1432
contrast : :obj:`str`
1404
1433
Name of contrast, for reporting purposes, e.g., T1w, T2w, PDw
1434
+ gradunwarp_file : :obj:`str`, optional
1435
+ Gradient unwarping filename (default: None)
1405
1436
name : :obj:`str`, optional
1406
1437
Workflow name (default: anat_template_wf)
1407
1438
@@ -1449,9 +1480,44 @@ def init_anat_template_wf(
1449
1480
)
1450
1481
anat_conform = pe .MapNode (Conform (), iterfield = 'in_file' , name = 'anat_conform' )
1451
1482
1483
+ # -1 Gradient unwarping (optional)
1484
+ if gradunwarp_file :
1485
+ nds = [
1486
+ (
1487
+ meta .get ('NonlinearGradientCorrection' , None )
1488
+ or 'ND' in meta .get ('ImageType' , [])
1489
+ or False
1490
+ )
1491
+ for meta in metadata
1492
+ ]
1493
+ if any (nds ) and not all (nds ):
1494
+ raise RuntimeError (
1495
+ f'Inconsistent distortion correction metadata across { contrast } images.'
1496
+ )
1497
+ if not any (nds ):
1498
+ gradunwarp_file = None
1499
+ if gradunwarp_file :
1500
+ gradunwarp_ver = GradUnwarp .version ()
1501
+ workflow .__desc__ += f"""\
1502
+ { "Each" if num_files > 1 else "The" } { contrast } image was corrected for gradient
1503
+ non-linearity with `gradunwarp` [@gradunwarp] { gradunwarp_ver } [@gradunwarp]\n """
1504
+ gradunwarp_wf = init_gradunwarp_wf ('gradunward_T1w' )
1505
+ gradunwarp_wf .inputs .inputnode .grad_file = gradunwarp_file
1506
+ # fmt:off
1507
+ workflow .connect ([
1508
+ (inputnode , gradunwarp_wf , [('anat_files' , 'inputnode.input_file' )]),
1509
+ (gradunwarp_wf , anat_ref_dimensions , [('outputnode.corrected_file' , 't1w_list' )]),
1510
+ ])
1511
+ else :
1512
+ workflow .connect (
1513
+ [
1514
+ (inputnode , anat_ref_dimensions , [('anat_files' , 't1w_list' )]),
1515
+ ]
1516
+ )
1517
+ # fmt:on
1518
+
1452
1519
# fmt:off
1453
1520
workflow .connect ([
1454
- (inputnode , anat_ref_dimensions , [('anat_files' , 't1w_list' )]),
1455
1521
(anat_ref_dimensions , denoise , [('t1w_valid_list' , 'input_image' )]),
1456
1522
(anat_ref_dimensions , anat_conform , [
1457
1523
('target_zooms' , 'target_zooms' ),
0 commit comments