@@ -140,6 +140,14 @@ def from_filename(cls, filename: Path | str) -> DWI:
140
140
141
141
return cls (** data )
142
142
143
+ @property
144
+ def bvals (self ):
145
+ return self .gradients [- 1 , ...]
146
+
147
+ @property
148
+ def bvecs (self ):
149
+ return self .gradients [:- 1 , ...]
150
+
143
151
def set_transform (self , index : int , affine : np .ndarray , order : int = 3 ) -> None :
144
152
"""
145
153
Set an affine transform for a particular index and update the data object.
@@ -164,14 +172,14 @@ def set_transform(self, index: int, affine: np.ndarray, order: int = 3) -> None:
164
172
reference = ImageGrid (shape = self .dataobj .shape [:3 ], affine = self .affine )
165
173
166
174
xform = Affine (matrix = affine , reference = reference )
167
- bvec = self .gradients [: 3 , index ]
175
+ bvec = self .bvecs [: , index ]
168
176
169
177
# invert transform transform b-vector and origin
170
178
r_bvec = (~ xform ).map ([bvec , (0.0 , 0.0 , 0.0 )])
171
179
# Reset b-vector's origin
172
180
new_bvec = r_bvec [1 ] - r_bvec [0 ]
173
181
# Normalize and update
174
- self .gradients [: 3 , index ] = new_bvec / np .linalg .norm (new_bvec )
182
+ self .bvecs [: , index ] = new_bvec / np .linalg .norm (new_bvec )
175
183
176
184
super ().set_transform (index , affine , order )
177
185
@@ -201,16 +209,26 @@ def to_filename(
201
209
with h5py .File (filename , "r+" ) as out_file :
202
210
out_file .attrs ["Type" ] = "dmri"
203
211
204
- def to_nifti (self , filename : Path | str , insert_b0 : bool = False ) -> None :
212
+ def to_nifti (
213
+ self ,
214
+ filename : Path | str ,
215
+ insert_b0 : bool = False ,
216
+ bvals_dec_places : int = 2 ,
217
+ bvecs_dec_places : int = 6 ,
218
+ ) -> None :
205
219
"""
206
220
Write a NIfTI file to disk.
207
221
208
222
Parameters
209
223
----------
210
224
filename : :obj:`os.pathlike`
211
225
The output NIfTI file path.
212
- insert_b0 : :obj:`bool`
226
+ insert_b0 : :obj:`bool`, optional
213
227
Insert a :math:`b=0` at the front of the output NIfTI.
228
+ bvals_dec_places : :obj:`int`, optional
229
+ Decimal places to use when serializing b-values.
230
+ bvecs_dec_places : :obj:`int`, optional
231
+ Decimal places to use when serializing b-vectors.
214
232
215
233
"""
216
234
if not insert_b0 :
@@ -226,21 +244,17 @@ def to_nifti(self, filename: Path | str, insert_b0: bool = False) -> None:
226
244
# Convert filename to a Path object.
227
245
out_root = Path (filename ).absolute ()
228
246
229
- # Remove .gz if present, then remove .nii if present.
230
- # This yields the base stem for writing .bvec / .bval.
231
- if out_root .suffix == ".gz" :
232
- out_root = out_root .with_suffix ("" ) # remove '.gz'
233
- if out_root .suffix == ".nii" :
234
- out_root = out_root .with_suffix ("" ) # remove '.nii'
247
+ # Get the base stem for writing .bvec / .bval.
248
+ out_root = out_root .parent / out_root .name .replace ("" .join (out_root .suffixes ), "" )
235
249
236
250
# Construct sidecar file paths.
237
251
bvecs_file = out_root .with_suffix (".bvec" )
238
252
bvals_file = out_root .with_suffix (".bval" )
239
253
240
254
# Save bvecs and bvals to text files
241
255
# Each row of bvecs is one direction (3 rows, N columns).
242
- np .savetxt (bvecs_file , self .gradients [: 3 , ...]. T , fmt = "%.6f " )
243
- np .savetxt (bvals_file , self .gradients [: 3 , ... ], fmt = "%.6f " )
256
+ np .savetxt (bvecs_file , self .bvecs , fmt = f "%.{ bvecs_dec_places } f " )
257
+ np .savetxt (bvals_file , self .bvals [ np . newaxis , : ], fmt = f "%.{ bvals_dec_places } f " )
244
258
245
259
246
260
def load (
0 commit comments