6
6
import nibabel as nb
7
7
from nibabel .affines import apply_affine
8
8
9
+ from nipype import logging
9
10
from nipype .utils .filemanip import fname_presuffix
10
11
from nipype .interfaces .base import (
11
12
BaseInterfaceInputSpec ,
22
23
DEFAULT_ZOOMS_MM = (40.0 , 40.0 , 20.0 ) # For human adults (mid-frequency), in mm
23
24
DEFAULT_LF_ZOOMS_MM = (100.0 , 100.0 , 40.0 ) # For human adults (low-frequency), in mm
24
25
DEFAULT_HF_ZOOMS_MM = (16.0 , 16.0 , 10.0 ) # For human adults (high-frequency), in mm
25
- BSPLINE_SUPPORT = 2 - 1.82e-2 # Disallows weights < 1e-6
26
+ BSPLINE_SUPPORT = 2 - 1.82e-3 # Disallows weights < 1e-9
27
+ LOGGER = logging .getLogger ("nipype.interface" )
26
28
27
29
28
30
class _BSplineApproxInputSpec (BaseInterfaceInputSpec ):
@@ -97,6 +99,7 @@ class BSplineApprox(SimpleInterface):
97
99
98
100
def _run_interface (self , runtime ):
99
101
from sklearn import linear_model as lm
102
+ from scipy .sparse import vstack as sparse_vstack
100
103
101
104
# Load in the fieldmap
102
105
fmapnii = nb .load (self .inputs .in_data )
@@ -130,7 +133,7 @@ def _run_interface(self, runtime):
130
133
if regressors is None :
131
134
regressors = bspline_weights (fmap_points , level )
132
135
else :
133
- regressors = np . vstack (
136
+ regressors = sparse_vstack (
134
137
(regressors , bspline_weights (fmap_points , level ))
135
138
)
136
139
@@ -179,7 +182,7 @@ def _run_interface(self, runtime):
179
182
return runtime
180
183
181
184
bg_points = apply_affine (fmapnii .affine .astype ("float32" ), bg_indices )
182
- extrapolators = np . vstack (
185
+ extrapolators = sparse_vstack (
183
186
[bspline_weights (bg_points , level ) for level in bs_levels ]
184
187
)
185
188
interp_data [~ mask ] = np .array (model .coef_ ) @ extrapolators # Extrapolation
@@ -234,6 +237,8 @@ class Coefficients2Warp(SimpleInterface):
234
237
output_spec = _Coefficients2WarpOutputSpec
235
238
236
239
def _run_interface (self , runtime ):
240
+ from scipy .sparse import vstack as sparse_vstack
241
+
237
242
# Calculate the physical coordinates of target grid
238
243
targetnii = nb .load (self .inputs .in_target )
239
244
targetaff = targetnii .affine
@@ -247,15 +252,13 @@ def _run_interface(self, runtime):
247
252
for cname in self .inputs .in_coeff :
248
253
coeff_nii = nb .load (cname )
249
254
wmat = bspline_weights (
250
- points ,
251
- coeff_nii ,
252
- blocksize = LOW_MEM_BLOCK_SIZE if self .inputs .low_mem else None ,
255
+ points , coeff_nii , mem_percent = 0.1 if self .inputs .low_mem else None ,
253
256
)
254
257
weights .append (wmat )
255
258
coeffs .append (coeff_nii .get_fdata (dtype = "float32" ).reshape (- 1 ))
256
259
257
260
data = np .zeros (targetnii .shape , dtype = "float32" )
258
- data [allmask == 1 ] = np .squeeze (np .vstack (coeffs ).T ) @ np . vstack (weights )
261
+ data [allmask == 1 ] = np .squeeze (np .vstack (coeffs ).T ) @ sparse_vstack (weights )
259
262
260
263
hdr = targetnii .header .copy ()
261
264
hdr .set_data_dtype ("float32" )
@@ -398,7 +401,7 @@ def bspline_grid(img, control_zooms_mm=DEFAULT_ZOOMS_MM):
398
401
return img .__class__ (np .zeros (bs_shape , dtype = "float32" ), bs_affine )
399
402
400
403
401
- def bspline_weights (points , ctrl_nii , blocksize = None ):
404
+ def bspline_weights (points , ctrl_nii , blocksize = None , mem_percent = None ):
402
405
r"""
403
406
Calculate the tensor-product cubic B-Spline kernel weights for a list of 3D points.
404
407
@@ -443,6 +446,7 @@ def bspline_weights(points, ctrl_nii, blocksize=None):
443
446
step of approximation/extrapolation.
444
447
445
448
"""
449
+ from scipy .sparse import csc_matrix , hstack
446
450
from ..utils .misc import get_free_mem
447
451
448
452
if isinstance (ctrl_nii , (str , bytes , Path )):
@@ -457,11 +461,17 @@ def bspline_weights(points, ctrl_nii, blocksize=None):
457
461
# Try to probe the free memory
458
462
_free_mem = get_free_mem ()
459
463
suggested_blocksize = (
460
- int (np .round ((_free_mem * 0.80 ) / (3 * 32 * ncoeff )))
464
+ int (np .round ((_free_mem * ( mem_percent or 0.9 )) / (3 * 4 * ncoeff )))
461
465
if _free_mem
462
466
else blocksize
463
467
)
464
468
blocksize = min (blocksize , suggested_blocksize )
469
+ LOGGER .info (
470
+ f"Determined a block size of { blocksize } , for interpolating "
471
+ f"an image of { len (points )} voxels with a grid of { ncoeff } "
472
+ f"coefficients ({ _free_mem / 1024 ** 3 :.2f} GiB free memory)."
473
+ )
474
+
465
475
idx = 0
466
476
wmatrix = None
467
477
while True :
@@ -497,13 +507,13 @@ def bspline_weights(points, ctrl_nii, blocksize=None):
497
507
498
508
weights [weights < 1e-6 ] = 0.0
499
509
500
- if idx == 0 :
501
- wmatrix = weights
510
+ if wmatrix is None :
511
+ wmatrix = csc_matrix ( weights )
502
512
else :
503
- wmatrix = np . hstack ((wmatrix , weights ))
513
+ wmatrix = hstack ((wmatrix , csc_matrix ( weights ) ))
504
514
idx = end
505
515
506
- return wmatrix
516
+ return wmatrix . tocsr ()
507
517
508
518
509
519
def _move_coeff (in_coeff , fmap_ref , transform ):
0 commit comments