@@ -140,6 +140,14 @@ def from_filename(cls, filename: Path | str) -> DWI:
140140
141141 return cls (** data )
142142
143+ @property
144+ def bvals (self ):
145+ return self .gradients [- 1 , ...]
146+
147+ @property
148+ def bvecs (self ):
149+ return self .gradients [:- 1 , ...]
150+
143151 def set_transform (self , index : int , affine : np .ndarray , order : int = 3 ) -> None :
144152 """
145153 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:
164172 reference = ImageGrid (shape = self .dataobj .shape [:3 ], affine = self .affine )
165173
166174 xform = Affine (matrix = affine , reference = reference )
167- bvec = self .gradients [: 3 , index ]
175+ bvec = self .bvecs [: , index ]
168176
169177 # invert transform transform b-vector and origin
170178 r_bvec = (~ xform ).map ([bvec , (0.0 , 0.0 , 0.0 )])
171179 # Reset b-vector's origin
172180 new_bvec = r_bvec [1 ] - r_bvec [0 ]
173181 # 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 )
175183
176184 super ().set_transform (index , affine , order )
177185
@@ -201,16 +209,26 @@ def to_filename(
201209 with h5py .File (filename , "r+" ) as out_file :
202210 out_file .attrs ["Type" ] = "dmri"
203211
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 :
205219 """
206220 Write a NIfTI file to disk.
207221
208222 Parameters
209223 ----------
210224 filename : :obj:`os.pathlike`
211225 The output NIfTI file path.
212- insert_b0 : :obj:`bool`
226+ insert_b0 : :obj:`bool`, optional
213227 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.
214232
215233 """
216234 if not insert_b0 :
@@ -226,21 +244,17 @@ def to_nifti(self, filename: Path | str, insert_b0: bool = False) -> None:
226244 # Convert filename to a Path object.
227245 out_root = Path (filename ).absolute ()
228246
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 ), "" )
235249
236250 # Construct sidecar file paths.
237251 bvecs_file = out_root .with_suffix (".bvec" )
238252 bvals_file = out_root .with_suffix (".bval" )
239253
240254 # Save bvecs and bvals to text files
241255 # 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 " )
244258
245259
246260def load (
0 commit comments