@@ -28,7 +28,9 @@ class ResampleSeriesInputSpec(TraitedSpec):
2828 in_file = File (exists = True , mandatory = True , desc = "3D or 4D image file to resample" )
2929 ref_file = File (exists = True , mandatory = True , desc = "File to resample in_file to" )
3030 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)" ,
3234 )
3335 inverse = InputMultiObject (
3436 traits .Bool ,
@@ -48,6 +50,16 @@ class ResampleSeriesInputSpec(TraitedSpec):
4850 desc = "the phase-encoding direction corresponding to in_data" ,
4951 )
5052 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" )
5163
5264
5365class ResampleSeriesOutputSpec (TraitedSpec ):
@@ -87,13 +99,18 @@ def _run_interface(self, runtime):
8799
88100 pe_info = [(pe_axis , - ro_time if (axis_flip ^ pe_flip ) else ro_time )] * nvols
89101
90- resampled = resample_bold (
102+ resampled = resample_image (
91103 source = source ,
92104 target = target ,
93105 transforms = transforms ,
94106 fieldmap = fieldmap ,
95107 pe_info = pe_info ,
96108 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 ,
97114 )
98115 resampled .to_filename (out_path )
99116
@@ -105,10 +122,16 @@ class ReconstructFieldmapInputSpec(TraitedSpec):
105122 in_coeffs = InputMultiObject (
106123 File (exists = True ), mandatory = True , desc = "SDCflows-style spline coefficient files"
107124 )
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+ )
110131 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)" ,
112135 )
113136 inverse = InputMultiObject (
114137 traits .Bool ,
@@ -252,6 +275,9 @@ def resample_vol(
252275 coordinates = nb .affines .apply_affine (
253276 hmc_xfm , coordinates .reshape (coords_shape [0 ], - 1 ).T
254277 ).T .reshape (coords_shape )
278+ else :
279+ # Copy coordinates to avoid interfering with other calls
280+ coordinates = coordinates .copy ()
255281
256282 vsm = fmap_hz * pe_info [1 ]
257283 coordinates [pe_info [0 ], ...] += vsm
@@ -346,15 +372,17 @@ async def resample_series_async(
346372
347373 semaphore = asyncio .Semaphore (max_concurrent )
348374
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' )
350378
351379 tasks = [
352380 asyncio .create_task (
353381 worker (
354382 partial (
355383 resample_vol ,
356384 data = volume ,
357- coordinates = coordinates . copy () ,
385+ coordinates = coordinates ,
358386 pe_info = pe_info [volid ],
359387 hmc_xfm = hmc_xfms [volid ] if hmc_xfms else None ,
360388 fmap_hz = fmap_hz ,
@@ -451,21 +479,26 @@ def resample_series(
451479 )
452480
453481
454- def resample_bold (
482+ def resample_image (
455483 source : nb .Nifti1Image ,
456484 target : nb .Nifti1Image ,
457485 transforms : nt .TransformChain ,
458486 fieldmap : nb .Nifti1Image | None ,
459487 pe_info : list [tuple [int , float ]] | None ,
460488 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 ,
461494) -> 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
463496 and susceptibility-distortion correction simultaneously.
464497
465498 Parameters
466499 ----------
467500 source
468- The 4D bold series to resample.
501+ The 3D bold image or 4D bold series to resample.
469502 target
470503 An image sampled in the target space.
471504 transforms
@@ -480,6 +513,17 @@ def resample_bold(
480513 of the data array in the second dimension.
481514 nthreads
482515 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.
483527
484528 Returns
485529 -------
@@ -527,8 +571,12 @@ def resample_bold(
527571 pe_info = pe_info ,
528572 hmc_xfms = hmc_xfms ,
529573 fmap_hz = fieldmap .get_fdata (dtype = 'f4' ),
530- output_dtype = 'f4' ,
574+ output_dtype = output_dtype ,
531575 nthreads = nthreads ,
576+ order = order ,
577+ mode = mode ,
578+ cval = cval ,
579+ prefilter = prefilter ,
532580 )
533581 resampled_img = nb .Nifti1Image (resampled_data , target .affine , target .header )
534582 resampled_img .set_data_dtype ('f4' )
0 commit comments