@@ -273,6 +273,8 @@ def calc_BV_header_size(hdr_dict_proto, hdr_dict, parent_hdr_dict=None):
273
273
# check the length of the array to expect
274
274
if def_or_name in hdr_dict :
275
275
n_values = hdr_dict [def_or_name ]
276
+ # handle cases when n_values is resides outside of the
277
+ # current scope (e.g. nr_of_timepoints in VMP_HDR_DICT_PROTO)
276
278
else :
277
279
n_values = parent_hdr_dict [def_or_name ]
278
280
for i in range (n_values ):
@@ -306,7 +308,7 @@ def update_BV_header(hdr_dict_proto, hdr_dict_old, hdr_dict_new,
306
308
hdr_dict before any changes.
307
309
hdr_dict_new: OrderedDict
308
310
hdr_dict with changed fields in n_fields_name or c_fields_name fields.
309
- parent_old: OrderedDict
311
+ parent_old: None or OrderedDict, optional
310
312
When update_BV_header() is called recursively the not yet updated
311
313
(parent) hdr_dict is passed to give access to n_fields_name fields
312
314
outside the current scope (see below).
@@ -325,28 +327,27 @@ def update_BV_header(hdr_dict_proto, hdr_dict_old, hdr_dict_new,
325
327
# handle only nested loop fields
326
328
if not isinstance (pack_format , tuple ):
327
329
continue
330
+ # calculate the change of array length and the new array length
331
+ if def_or_name in hdr_dict_old :
332
+ delta_values = (hdr_dict_new [def_or_name ] -
333
+ hdr_dict_old [def_or_name ])
334
+ n_values = hdr_dict_new [def_or_name ]
328
335
else :
329
- # calculate the change of array length and the new array length
330
- if def_or_name in hdr_dict_old :
331
- delta_values = (hdr_dict_new [def_or_name ] -
332
- hdr_dict_old [def_or_name ])
333
- n_values = hdr_dict_new [def_or_name ]
334
- else :
335
- delta_values = (parent_new [def_or_name ] -
336
- parent_old [def_or_name ])
337
- n_values = parent_new [def_or_name ]
338
- if delta_values > 0 : # add nested loops
339
- for i in range (delta_values ):
340
- hdr_dict_new [name ].append (_proto2default (pack_format ,
341
- hdr_dict_new ))
342
- elif delta_values < 0 : # remove nested loops
343
- for i in range (abs (delta_values )):
344
- hdr_dict_new [name ].pop ()
345
- # loop over nested fields
346
- for i in range (n_values ):
347
- update_BV_header (pack_format , hdr_dict_old [name ][i ],
348
- hdr_dict_new [name ][i ], hdr_dict_old ,
349
- hdr_dict_new )
336
+ delta_values = (parent_new [def_or_name ] -
337
+ parent_old [def_or_name ])
338
+ n_values = parent_new [def_or_name ]
339
+ if delta_values > 0 : # add nested loops
340
+ for i in range (delta_values ):
341
+ hdr_dict_new [name ].append (_proto2default (pack_format ,
342
+ hdr_dict_new ))
343
+ elif delta_values < 0 : # remove nested loops
344
+ for i in range (abs (delta_values )):
345
+ hdr_dict_new [name ].pop ()
346
+ # loop over nested fields
347
+ for i in range (n_values ):
348
+ update_BV_header (pack_format , hdr_dict_old [name ][i ],
349
+ hdr_dict_new [name ][i ], hdr_dict_old ,
350
+ hdr_dict_new )
350
351
return hdr_dict_new
351
352
352
353
@@ -453,7 +454,7 @@ class BvFileHeader(Header):
453
454
# format defaults
454
455
# BV files are radiological (left-is-right) by default
455
456
# (VTC files have a flag for that, however)
456
- default_x_flip = True
457
+ default_xflip = True
457
458
default_endianness = '<' # BV files are always little-endian
458
459
allowed_dtypes = [1 , 2 , 3 ]
459
460
default_dtype = 2
@@ -470,9 +471,10 @@ def __init__(self,
470
471
471
472
Parameters
472
473
----------
473
- binaryblock : {None, string} optional
474
- binary block to set into header. By default, None, in
475
- which case we insert the default empty header block
474
+ hdr_dict : None or OrderedDict, optional
475
+ An OrderedDict containing all header fields parsed from the file.
476
+ By default, None, in which case we create a default hdr_dict from
477
+ the corresponding _HDR_DICT_PROTO
476
478
endianness : {None, '<','>', other endian code} string, optional
477
479
endianness of the binaryblock. If None, guess endianness
478
480
from the data.
@@ -641,11 +643,12 @@ def set_data_dtype(self, datatype):
641
643
raise HeaderDataError (
642
644
'File format does not support setting of header!' )
643
645
644
- def get_xflip ( self ):
645
- """Get xflip for data."""
646
- return self .default_x_flip
646
+ @ property
647
+ def xflip ( self ):
648
+ return self .default_xflip
647
649
648
- def set_xflip (self , xflip ):
650
+ @xflip .setter
651
+ def xflip (self , xflip ):
649
652
"""Set xflip for data."""
650
653
if xflip is True :
651
654
return
@@ -666,15 +669,15 @@ def get_base_affine(self):
666
669
Note that we get the translations from the center of the
667
670
(guessed) framing cube of the referenced VMR (anatomical) file.
668
671
669
- Internal storage of the image is ZYXT, where (in patient coordiante /
672
+ Internal storage of the image is ZYXT, where (in patient coordinates /
670
673
real world orientations):
671
674
Z := axis increasing from right to left (R to L)
672
675
Y := axis increasing from superior to inferior (S to I)
673
676
X := axis increasing from anterior to posterior (A to P)
674
677
T := volumes (if present in file format)
675
678
"""
676
679
zooms = self .get_zooms ()
677
- if not self .get_xflip () :
680
+ if not self .xflip :
678
681
# make the BV internal Z axis neurological (left-is-left);
679
682
# not default in BV files!
680
683
zooms = (- zooms [0 ], zooms [1 ], zooms [2 ])
@@ -689,7 +692,7 @@ def get_base_affine(self):
689
692
rot [:, 2 ] = [0 , - zooms [1 ], 0 ]
690
693
691
694
# compute the translation
692
- fcc = np .array (self .get_framing_cube () ) / 2 # center of framing cube
695
+ fcc = np .array (self .framing_cube ) / 2 # center of framing cube
693
696
bbc = np .array (self .get_bbox_center ()) # center of bounding box
694
697
tra = np .dot ((bbc - fcc ), rot )
695
698
@@ -700,11 +703,14 @@ def get_base_affine(self):
700
703
701
704
return M
702
705
703
- get_best_affine = get_base_affine
706
+ def get_best_affine (self ):
707
+ return self .get_base_affine ()
704
708
705
- get_default_affine = get_base_affine
709
+ def get_default_affine (self ):
710
+ return self .get_base_affine ()
706
711
707
- get_affine = get_base_affine
712
+ def get_affine (self ):
713
+ return self .get_base_affine ()
708
714
709
715
def _guess_framing_cube (self ):
710
716
"""Guess the dimensions of the framing cube.
@@ -729,7 +735,8 @@ def _guess_framing_cube(self):
729
735
else :
730
736
return fc , fc , fc
731
737
732
- def get_framing_cube (self ):
738
+ @property
739
+ def framing_cube (self ):
733
740
"""Get the dimensions of the framing cube.
734
741
735
742
Get the dimensions of the framing cube that constitutes the
@@ -739,7 +746,8 @@ def get_framing_cube(self):
739
746
"""
740
747
return self ._framing_cube
741
748
742
- def set_framing_cube (self , fc ):
749
+ @framing_cube .setter
750
+ def framing_cube (self , fc ):
743
751
"""Set the dimensions of the framing cube.
744
752
745
753
Set the dimensions of the framing cube that constitutes the
@@ -771,10 +779,24 @@ def get_zooms(self):
771
779
for d in shape [0 :3 ])
772
780
773
781
def set_zooms (self , zooms ):
782
+ """Set the zooms for the image.
783
+
784
+ Voxel dimensions of functional data in BV file formats are
785
+ always in relationship to the voxel dimensions in a VMR file and
786
+ therefore need to be equal for all three spatial dimensions.
787
+
788
+ Parameters
789
+ ----------
790
+ zooms : int or sequence
791
+ An integer or a sequence of integers specifying the relationship
792
+ between voxel dimensions and real-world dimensions. If a single
793
+ integer is used it is applied to all spatial dimensions. If a
794
+ sequence of integers is used all dimensions have to be equal.
795
+ """
774
796
if type (zooms ) == int :
775
797
self ._hdr_dict ['resolution' ] = zooms
776
798
else :
777
- if any ([ zooms [ i ] != zooms [ i + 1 ] for i in range ( len ( zooms ) - 1 )] ):
799
+ if np . any (np . diff ( zooms )):
778
800
raise BvError ('Zooms for all dimensions must be equal!' )
779
801
else :
780
802
self ._hdr_dict ['resolution' ] = int (zooms [0 ])
0 commit comments