43
43
below). It's not clear what the licenses are for these files.
44
44
"""
45
45
46
+ from __future__ import annotations
47
+
46
48
import warnings
47
49
from numbers import Integral
50
+ from typing import TYPE_CHECKING
48
51
49
52
import numpy as np
50
53
51
54
from .arraywriters import make_array_writer
52
55
from .fileslice import canonical_slicers , predict_shape , slice2outax
53
- from .spatialimages import SpatialHeader , SpatialImage
56
+ from .spatialimages import Affine , AffT , SpatialHeader , SpatialImage
54
57
from .volumeutils import array_from_file , make_dt_codes , native_code , swapped_code
55
58
from .wrapstruct import WrapStruct
56
59
60
+ if TYPE_CHECKING :
61
+ from collections .abc import Mapping
62
+ from typing import Literal as L
63
+
64
+ import numpy .typing as npt
65
+
66
+ from .arrayproxy import ArrayLike
67
+ from .filebasedimages import FileBasedHeader
68
+ from .fileholders import FileMap
69
+
57
70
BLOCK_SIZE = 512
58
71
59
72
main_header_dtd = [
@@ -743,7 +756,7 @@ def __getitem__(self, sliceobj):
743
756
return out_data
744
757
745
758
746
- class EcatImage (SpatialImage ):
759
+ class EcatImage (SpatialImage [ AffT ] ):
747
760
"""Class returns a list of Ecat images, with one image(hdr/data) per frame"""
748
761
749
762
header_class = EcatHeader
@@ -756,7 +769,16 @@ class EcatImage(SpatialImage):
756
769
757
770
ImageArrayProxy = EcatImageArrayProxy
758
771
759
- def __init__ (self , dataobj , affine , header , subheader , mlist , extra = None , file_map = None ):
772
+ def __init__ (
773
+ self ,
774
+ dataobj : ArrayLike ,
775
+ affine : AffT ,
776
+ header : FileBasedHeader | Mapping | None ,
777
+ subheader : EcatSubHeader ,
778
+ mlist : npt .NDArray [np .integer ],
779
+ extra : Mapping | None = None ,
780
+ file_map : FileMap | None = None ,
781
+ ) -> None :
760
782
"""Initialize Image
761
783
762
784
The image is a combination of
@@ -798,40 +820,38 @@ def __init__(self, dataobj, affine, header, subheader, mlist, extra=None, file_m
798
820
>>> data4d.shape == (10, 10, 3, 1)
799
821
True
800
822
"""
823
+ super ().__init__ (
824
+ dataobj = dataobj ,
825
+ affine = affine ,
826
+ header = header ,
827
+ extra = extra ,
828
+ file_map = file_map ,
829
+ )
801
830
self ._subheader = subheader
802
831
self ._mlist = mlist
803
- self ._dataobj = dataobj
804
- if affine is not None :
805
- # Check that affine is array-like 4,4. Maybe this is too strict at
806
- # this abstract level, but so far I think all image formats we know
807
- # do need 4,4.
808
- affine = np .array (affine , dtype = np .float64 , copy = True )
809
- if not affine .shape == (4 , 4 ):
810
- raise ValueError ('Affine should be shape 4,4' )
811
- self ._affine = affine
812
- if extra is None :
813
- extra = {}
814
- self .extra = extra
815
- self ._header = header
816
- if file_map is None :
817
- file_map = self .__class__ .make_file_map ()
818
- self .file_map = file_map
819
- self ._data_cache = None
820
- self ._fdata_cache = None
832
+
833
+ # Override SpatialImage default, which attempts to set the
834
+ # affine in the header.
835
+ def update_header (self ) -> None :
836
+ """Does nothing"""
821
837
822
838
@property
823
- def affine (self ):
839
+ def affine (self ) -> AffT :
824
840
if not self ._subheader ._check_affines ():
825
841
warnings .warn (
826
842
'Affines different across frames, loading affine from FIRST frame' , UserWarning
827
843
)
828
844
return self ._affine
829
845
830
- def get_frame_affine (self , frame ) :
846
+ def get_frame_affine (self , frame : int ) -> Affine :
831
847
"""returns 4X4 affine"""
832
848
return self ._subheader .get_frame_affine (frame = frame )
833
849
834
- def get_frame (self , frame , orientation = None ):
850
+ def get_frame (
851
+ self ,
852
+ frame : int ,
853
+ orientation : L ['neurological' , 'radiological' ] | None = None ,
854
+ ) -> np .ndarray :
835
855
"""
836
856
Get full volume for a time frame
837
857
@@ -847,16 +867,16 @@ def get_data_dtype(self, frame):
847
867
return dt
848
868
849
869
@property
850
- def shape (self ):
870
+ def shape (self ) -> tuple [ int , int , int , int ] :
851
871
x , y , z = self ._subheader .get_shape ()
852
872
nframes = self ._subheader .get_nframes ()
853
873
return (x , y , z , nframes )
854
874
855
- def get_mlist (self ):
875
+ def get_mlist (self ) -> npt . NDArray [ np . integer ] :
856
876
"""get access to the mlist"""
857
877
return self ._mlist
858
878
859
- def get_subheaders (self ):
879
+ def get_subheaders (self ) -> EcatSubHeader :
860
880
"""get access to subheaders"""
861
881
return self ._subheader
862
882
0 commit comments