@@ -73,6 +73,7 @@ def _sdc_unwarp(
7373 coordinates : np .ndarray ,
7474 pe_info : Tuple [int , float ],
7575 hmc_xfm : np .ndarray | None ,
76+ jacobian : bool ,
7677 fmap_hz : np .ndarray ,
7778 output_dtype : str | np .dtype | None = None ,
7879 order : int = 3 ,
@@ -95,13 +96,6 @@ def _sdc_unwarp(
9596 vsm = fmap_hz * pe_info [1 ]
9697 coordinates [pe_info [0 ], ...] += vsm
9798
98- # The Jacobian determinant image is the amount of stretching in the PE direction.
99- # Using central differences accounts for the shift in neighboring voxels.
100- # The full Jacobian at each voxel would be a 3x3 matrix, but because there is
101- # only warping in one direction, we end up with a diagonal matrix with two 1s.
102- # The following is the other entry at each voxel, and hence the determinant.
103- jacobian = 1 + np .gradient (vsm , axis = pe_info [0 ])
104-
10599 resampled = ndi .map_coordinates (
106100 data ,
107101 coordinates ,
@@ -110,7 +104,15 @@ def _sdc_unwarp(
110104 mode = mode ,
111105 cval = cval ,
112106 prefilter = prefilter ,
113- ) * jacobian
107+ )
108+
109+ # The Jacobian determinant image is the amount of stretching in the PE direction.
110+ # Using central differences accounts for the shift in neighboring voxels.
111+ # The full Jacobian at each voxel would be a 3x3 matrix, but because there is
112+ # only warping in one direction, we end up with a diagonal matrix with two 1s.
113+ # The following is the other entry at each voxel, and hence the determinant.
114+ if jacobian :
115+ resampled *= 1 + np .gradient (vsm , axis = pe_info [0 ])
114116
115117 return resampled
116118
@@ -138,6 +140,7 @@ async def unwarp_parallel(
138140 fmap_hz : np .ndarray ,
139141 pe_info : Sequence [Tuple [int , float ]],
140142 xfms : Sequence [np .ndarray ],
143+ jacobian : bool ,
141144 order : int = 3 ,
142145 mode : str = "constant" ,
143146 cval : float = 0.0 ,
@@ -162,6 +165,8 @@ async def unwarp_parallel(
162165 pe_info : :obj:`tuple` of (:obj:`int`, :obj:`float`)
163166 A tuple containing the index of the phase-encoding axis in the data array and
164167 the readout time (including sign, if displacements must be reversed)
168+ jacobian : :class:`bool`
169+ If :obj:`True`, apply Jacobian determinant correction after unwarping.
165170 xfms : :obj:`list` of obj:`~numpy.ndarray`
166171 A list of 4×4 matrices, each one formalizing
167172 the estimated head motion alignment to the scan's reference.
@@ -200,6 +205,7 @@ async def unwarp_parallel(
200205
201206 func = partial (
202207 _sdc_unwarp ,
208+ jacobian = jacobian ,
203209 fmap_hz = fmap_hz ,
204210 output_dtype = output_dtype ,
205211 order = order ,
@@ -370,6 +376,7 @@ def apply(
370376 pe_dir : str | Sequence [str ],
371377 ro_time : float | Sequence [float ],
372378 xfms : Sequence [np .ndarray ] | None = None ,
379+ jacobian : bool = True ,
373380 xfm_data2fmap : np .ndarray | None = None ,
374381 approx : bool = True ,
375382 order : int = 3 ,
@@ -394,6 +401,8 @@ def apply(
394401 A valid ``PhaseEncodingDirection`` metadata value.
395402 ro_time : :obj:`float` or :obj:`list` of :obj:`float`
396403 The total readout time in seconds.
404+ jacobian : :class:`bool`
405+ If :obj:`True`, apply Jacobian determinant correction after unwarping.
397406 xfms : :obj:`None` or :obj:`list`
398407 A list of 4×4 matrices, each one formalizing
399408 the estimated head motion alignment to the scan's reference.
@@ -528,6 +537,7 @@ def apply(
528537 self .mapped .get_fdata (dtype = "float32" ), # fieldmap in Hz
529538 pe_info ,
530539 xfms ,
540+ jacobian ,
531541 output_dtype = 'float32' ,
532542 order = order ,
533543 mode = mode ,
0 commit comments