@@ -28,7 +28,9 @@ class ResampleSeriesInputSpec(TraitedSpec):
28
28
in_file = File (exists = True , mandatory = True , desc = "3D or 4D image file to resample" )
29
29
ref_file = File (exists = True , mandatory = True , desc = "File to resample in_file to" )
30
30
transforms = InputMultiObject (
31
- File (exists = True ), mandatory = True , desc = "Transform files, from in_file to ref_file (image mode)"
31
+ File (exists = True ),
32
+ mandatory = True ,
33
+ desc = "Transform files, from in_file to ref_file (image mode)" ,
32
34
)
33
35
inverse = InputMultiObject (
34
36
traits .Bool ,
@@ -48,6 +50,16 @@ class ResampleSeriesInputSpec(TraitedSpec):
48
50
desc = "the phase-encoding direction corresponding to in_data" ,
49
51
)
50
52
num_threads = traits .Int (1 , usedefault = True , desc = "Number of threads to use for resampling" )
53
+ output_data_type = traits .Str ("float32" , usedefault = True , desc = "Data type of output image" )
54
+ order = traits .Int (3 , usedefault = True , desc = "Order of interpolation (0=nearest, 3=cubic)" )
55
+ mode = traits .Str (
56
+ 'constant' ,
57
+ usedefault = True ,
58
+ desc = "How data is extended beyond its boundaries. "
59
+ "See scipy.ndimage.map_coordinates for more details." ,
60
+ )
61
+ cval = traits .Float (0.0 , usedefault = True , desc = "Value to fill past edges of data" )
62
+ prefilter = traits .Bool (True , usedefault = True , desc = "Spline-prefilter data if order > 1" )
51
63
52
64
53
65
class ResampleSeriesOutputSpec (TraitedSpec ):
@@ -87,13 +99,18 @@ def _run_interface(self, runtime):
87
99
88
100
pe_info = [(pe_axis , - ro_time if (axis_flip ^ pe_flip ) else ro_time )] * nvols
89
101
90
- resampled = resample_bold (
102
+ resampled = resample_image (
91
103
source = source ,
92
104
target = target ,
93
105
transforms = transforms ,
94
106
fieldmap = fieldmap ,
95
107
pe_info = pe_info ,
96
108
nthreads = self .inputs .num_threads ,
109
+ output_dtype = self .inputs .output_data_type ,
110
+ order = self .inputs .order ,
111
+ mode = self .inputs .mode ,
112
+ cval = self .inputs .cval ,
113
+ prefilter = self .inputs .prefilter ,
97
114
)
98
115
resampled .to_filename (out_path )
99
116
@@ -105,10 +122,16 @@ class ReconstructFieldmapInputSpec(TraitedSpec):
105
122
in_coeffs = InputMultiObject (
106
123
File (exists = True ), mandatory = True , desc = "SDCflows-style spline coefficient files"
107
124
)
108
- target_ref_file = File (exists = True , mandatory = True , desc = "Image to reconstruct the field in alignment with" )
109
- fmap_ref_file = File (exists = True , mandatory = True , desc = "Reference file aligned with coefficients" )
125
+ target_ref_file = File (
126
+ exists = True , mandatory = True , desc = "Image to reconstruct the field in alignment with"
127
+ )
128
+ fmap_ref_file = File (
129
+ exists = True , mandatory = True , desc = "Reference file aligned with coefficients"
130
+ )
110
131
transforms = InputMultiObject (
111
- File (exists = True ), mandatory = True , desc = "Transform files, from in_file to ref_file (image mode)"
132
+ File (exists = True ),
133
+ mandatory = True ,
134
+ desc = "Transform files, from in_file to ref_file (image mode)" ,
112
135
)
113
136
inverse = InputMultiObject (
114
137
traits .Bool ,
@@ -252,6 +275,9 @@ def resample_vol(
252
275
coordinates = nb .affines .apply_affine (
253
276
hmc_xfm , coordinates .reshape (coords_shape [0 ], - 1 ).T
254
277
).T .reshape (coords_shape )
278
+ else :
279
+ # Copy coordinates to avoid interfering with other calls
280
+ coordinates = coordinates .copy ()
255
281
256
282
vsm = fmap_hz * pe_info [1 ]
257
283
coordinates [pe_info [0 ], ...] += vsm
@@ -346,15 +372,17 @@ async def resample_series_async(
346
372
347
373
semaphore = asyncio .Semaphore (max_concurrent )
348
374
349
- out_array = np .zeros (coordinates .shape [1 :] + data .shape [- 1 :], dtype = output_dtype )
375
+ # Order F ensures individual volumes are contiguous in memory
376
+ # Also matches NIfTI, making final save more efficient
377
+ out_array = np .zeros (coordinates .shape [1 :] + data .shape [- 1 :], dtype = output_dtype , order = 'F' )
350
378
351
379
tasks = [
352
380
asyncio .create_task (
353
381
worker (
354
382
partial (
355
383
resample_vol ,
356
384
data = volume ,
357
- coordinates = coordinates . copy () ,
385
+ coordinates = coordinates ,
358
386
pe_info = pe_info [volid ],
359
387
hmc_xfm = hmc_xfms [volid ] if hmc_xfms else None ,
360
388
fmap_hz = fmap_hz ,
@@ -451,21 +479,26 @@ def resample_series(
451
479
)
452
480
453
481
454
- def resample_bold (
482
+ def resample_image (
455
483
source : nb .Nifti1Image ,
456
484
target : nb .Nifti1Image ,
457
485
transforms : nt .TransformChain ,
458
486
fieldmap : nb .Nifti1Image | None ,
459
487
pe_info : list [tuple [int , float ]] | None ,
460
488
nthreads : int = 1 ,
489
+ output_dtype : np .dtype | str | None = 'f4' ,
490
+ order : int = 3 ,
491
+ mode : str = 'constant' ,
492
+ cval : float = 0.0 ,
493
+ prefilter : bool = True ,
461
494
) -> nb .Nifti1Image :
462
- """Resample a 4D bold series into a target space, applying head-motion
495
+ """Resample a 3- or 4D image into a target space, applying head-motion
463
496
and susceptibility-distortion correction simultaneously.
464
497
465
498
Parameters
466
499
----------
467
500
source
468
- The 4D bold series to resample.
501
+ The 3D bold image or 4D bold series to resample.
469
502
target
470
503
An image sampled in the target space.
471
504
transforms
@@ -480,6 +513,17 @@ def resample_bold(
480
513
of the data array in the second dimension.
481
514
nthreads
482
515
Number of threads to use for parallel resampling
516
+ output_dtype
517
+ The dtype of the output array.
518
+ order
519
+ Order of interpolation (default: 3 = cubic)
520
+ mode
521
+ How ``data`` is extended beyond its boundaries. See
522
+ :func:`scipy.ndimage.map_coordinates` for more details.
523
+ cval
524
+ Value to fill past edges of ``data`` if ``mode`` is ``'constant'``.
525
+ prefilter
526
+ Determines if ``data`` is pre-filtered before interpolation.
483
527
484
528
Returns
485
529
-------
@@ -527,8 +571,12 @@ def resample_bold(
527
571
pe_info = pe_info ,
528
572
hmc_xfms = hmc_xfms ,
529
573
fmap_hz = fieldmap .get_fdata (dtype = 'f4' ),
530
- output_dtype = 'f4' ,
574
+ output_dtype = output_dtype ,
531
575
nthreads = nthreads ,
576
+ order = order ,
577
+ mode = mode ,
578
+ cval = cval ,
579
+ prefilter = prefilter ,
532
580
)
533
581
resampled_img = nb .Nifti1Image (resampled_data , target .affine , target .header )
534
582
resampled_img .set_data_dtype ('f4' )
0 commit comments