@@ -273,6 +273,8 @@ def calc_BV_header_size(hdr_dict_proto, hdr_dict, parent_hdr_dict=None):
273273 # check the length of the array to expect
274274 if def_or_name in hdr_dict :
275275 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)
276278 else :
277279 n_values = parent_hdr_dict [def_or_name ]
278280 for i in range (n_values ):
@@ -306,7 +308,7 @@ def update_BV_header(hdr_dict_proto, hdr_dict_old, hdr_dict_new,
306308 hdr_dict before any changes.
307309 hdr_dict_new: OrderedDict
308310 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
310312 When update_BV_header() is called recursively the not yet updated
311313 (parent) hdr_dict is passed to give access to n_fields_name fields
312314 outside the current scope (see below).
@@ -325,28 +327,27 @@ def update_BV_header(hdr_dict_proto, hdr_dict_old, hdr_dict_new,
325327 # handle only nested loop fields
326328 if not isinstance (pack_format , tuple ):
327329 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 ]
328335 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 )
350351 return hdr_dict_new
351352
352353
@@ -453,7 +454,7 @@ class BvFileHeader(Header):
453454 # format defaults
454455 # BV files are radiological (left-is-right) by default
455456 # (VTC files have a flag for that, however)
456- default_x_flip = True
457+ default_xflip = True
457458 default_endianness = '<' # BV files are always little-endian
458459 allowed_dtypes = [1 , 2 , 3 ]
459460 default_dtype = 2
@@ -470,9 +471,10 @@ def __init__(self,
470471
471472 Parameters
472473 ----------
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
476478 endianness : {None, '<','>', other endian code} string, optional
477479 endianness of the binaryblock. If None, guess endianness
478480 from the data.
@@ -641,11 +643,12 @@ def set_data_dtype(self, datatype):
641643 raise HeaderDataError (
642644 'File format does not support setting of header!' )
643645
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
647649
648- def set_xflip (self , xflip ):
650+ @xflip .setter
651+ def xflip (self , xflip ):
649652 """Set xflip for data."""
650653 if xflip is True :
651654 return
@@ -666,15 +669,15 @@ def get_base_affine(self):
666669 Note that we get the translations from the center of the
667670 (guessed) framing cube of the referenced VMR (anatomical) file.
668671
669- Internal storage of the image is ZYXT, where (in patient coordiante /
672+ Internal storage of the image is ZYXT, where (in patient coordinates /
670673 real world orientations):
671674 Z := axis increasing from right to left (R to L)
672675 Y := axis increasing from superior to inferior (S to I)
673676 X := axis increasing from anterior to posterior (A to P)
674677 T := volumes (if present in file format)
675678 """
676679 zooms = self .get_zooms ()
677- if not self .get_xflip () :
680+ if not self .xflip :
678681 # make the BV internal Z axis neurological (left-is-left);
679682 # not default in BV files!
680683 zooms = (- zooms [0 ], zooms [1 ], zooms [2 ])
@@ -689,7 +692,7 @@ def get_base_affine(self):
689692 rot [:, 2 ] = [0 , - zooms [1 ], 0 ]
690693
691694 # 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
693696 bbc = np .array (self .get_bbox_center ()) # center of bounding box
694697 tra = np .dot ((bbc - fcc ), rot )
695698
@@ -700,11 +703,14 @@ def get_base_affine(self):
700703
701704 return M
702705
703- get_best_affine = get_base_affine
706+ def get_best_affine (self ):
707+ return self .get_base_affine ()
704708
705- get_default_affine = get_base_affine
709+ def get_default_affine (self ):
710+ return self .get_base_affine ()
706711
707- get_affine = get_base_affine
712+ def get_affine (self ):
713+ return self .get_base_affine ()
708714
709715 def _guess_framing_cube (self ):
710716 """Guess the dimensions of the framing cube.
@@ -729,7 +735,8 @@ def _guess_framing_cube(self):
729735 else :
730736 return fc , fc , fc
731737
732- def get_framing_cube (self ):
738+ @property
739+ def framing_cube (self ):
733740 """Get the dimensions of the framing cube.
734741
735742 Get the dimensions of the framing cube that constitutes the
@@ -739,7 +746,8 @@ def get_framing_cube(self):
739746 """
740747 return self ._framing_cube
741748
742- def set_framing_cube (self , fc ):
749+ @framing_cube .setter
750+ def framing_cube (self , fc ):
743751 """Set the dimensions of the framing cube.
744752
745753 Set the dimensions of the framing cube that constitutes the
@@ -771,10 +779,24 @@ def get_zooms(self):
771779 for d in shape [0 :3 ])
772780
773781 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+ """
774796 if type (zooms ) == int :
775797 self ._hdr_dict ['resolution' ] = zooms
776798 else :
777- if any ([ zooms [ i ] != zooms [ i + 1 ] for i in range ( len ( zooms ) - 1 )] ):
799+ if np . any (np . diff ( zooms )):
778800 raise BvError ('Zooms for all dimensions must be equal!' )
779801 else :
780802 self ._hdr_dict ['resolution' ] = int (zooms [0 ])
0 commit comments