ecat
¶
Read ECAT format images
An ECAT format image consists of:
a main header;
at least one matrix list (mlist);
ECAT thinks of memory locations in terms of blocks. One block is 512 bytes. Thus block 1 starts at 0 bytes, block 2 at 512 bytes, and so on.
The matrix list is an array with one row per frame in the data.
Columns in the matrix list are:
0: Matrix identifier (frame number)
1: matrix data start block number (subheader followed by image data)
2: Last block number of matrix (image) data
3: Matrix status
1: hxists - rw
2: exists - ro
3: matrix deleted
There is one sub-header for each image frame (or matrix in the terminology above). A sub-header can also be called an image header. The sub-header is one block (512 bytes), and the frame (image) data follows.
There is very little documentation of the ECAT format, and many of the comments in this code come from a combination of trial and error and wild speculation.
XMedcon can read and write ECAT 6 format, and read ECAT 7 format: see
http://xmedcon.sourceforge.net and the ECAT files in the source of XMedCon,
currently libs/tpc/*ecat*
and source/m-ecat*
. Unfortunately XMedCon is
GPL and some of the header files are adapted from CTI files (called CTI code
below). It’s not clear what the licenses are for these files.
|
Class for basic Ecat PET header |
|
Class returns a list of Ecat images, with one image(hdr/data) per frame |
|
Ecat implementation of array proxy protocol |
|
parses the subheaders in the ecat (.v) file there is one subheader for each frame in the ecat file |
|
Returns the order of the frames stored in the file Sometimes Frames are not stored in the file in chronological order, this can be used to extract frames in correct order |
|
Returns framenumber of data as it was collected, as part of a series; not just the order of how it was stored in this or across other files |
|
read (nframes, 4) matrix list array from fileobj |
|
Retrieve all subheaders and return list of subheader recarrays |
EcatHeader
¶
- class nibabel.ecat.EcatHeader(binaryblock=None, endianness=None, check=True)¶
Bases:
WrapStruct
,SpatialHeader
Class for basic Ecat PET header
Sub-parts of standard Ecat File
main header
matrix list which lists the information for each frame collected (can have 1 to many frames)
subheaders specific to each frame with possibly-variable sized data blocks
This just reads the main Ecat Header, it does not load the data or read the mlist or any sub headers
Initialize Ecat header from bytes object
- Parameters:
- binaryblock{None, bytes} optional
binary block to set into header, By default, None in which case we insert default empty header block
- endianness{None, ‘<’, ‘>’, other endian code}, optional
endian code of binary block, If None, guess endianness from the data
- check{True, False}, optional
Whether to check and fix header for errors. No checks currently implemented, so value has no effect.
- __init__(binaryblock=None, endianness=None, check=True)¶
Initialize Ecat header from bytes object
- Parameters:
- binaryblock{None, bytes} optional
binary block to set into header, By default, None in which case we insert default empty header block
- endianness{None, ‘<’, ‘>’, other endian code}, optional
endian code of binary block, If None, guess endianness from the data
- check{True, False}, optional
Whether to check and fix header for errors. No checks currently implemented, so value has no effect.
- classmethod default_structarr(endianness=None)¶
Return header data for empty header with given endianness
- get_data_dtype()¶
Get numpy dtype for data from header
- get_filetype()¶
Type of ECAT Matrix File from code stored in header
- get_patient_orient()¶
gets orientation of patient based on code stored in header, not always reliable
- classmethod guessed_endian(hdr)¶
Guess endian from MAGIC NUMBER value of header data
- template_dtype = dtype([('magic_number', 'S14'), ('original_filename', 'S32'), ('sw_version', '<u2'), ('system_type', '<u2'), ('file_type', '<u2'), ('serial_number', 'S10'), ('scan_start_time', '<u4'), ('isotope_name', 'S8'), ('isotope_halflife', '<f4'), ('radiopharmaceutical', 'S32'), ('gantry_tilt', '<f4'), ('gantry_rotation', '<f4'), ('bed_elevation', '<f4'), ('intrinsic_tilt', '<f4'), ('wobble_speed', '<u2'), ('transm_source_type', '<u2'), ('distance_scanned', '<f4'), ('transaxial_fov', '<f4'), ('angular_compression', '<u2'), ('coin_samp_mode', '<u2'), ('axial_samp_mode', '<u2'), ('ecat_calibration_factor', '<f4'), ('calibration_unitS', '<u2'), ('calibration_units_type', '<u2'), ('compression_code', '<u2'), ('study_type', 'S12'), ('patient_id', 'S16'), ('patient_name', 'S32'), ('patient_sex', 'S1'), ('patient_dexterity', 'S1'), ('patient_age', '<f4'), ('patient_height', '<f4'), ('patient_weight', '<f4'), ('patient_birth_date', '<u4'), ('physician_name', 'S32'), ('operator_name', 'S32'), ('study_description', 'S32'), ('acquisition_type', '<u2'), ('patient_orientation', '<u2'), ('facility_name', 'S20'), ('num_planes', '<u2'), ('num_frames', '<u2'), ('num_gates', '<u2'), ('num_bed_pos', '<u2'), ('init_bed_position', '<f4'), ('bed_position', '<f4', (15,)), ('plane_separation', '<f4'), ('lwr_sctr_thres', '<u2'), ('lwr_true_thres', '<u2'), ('upr_true_thres', '<u2'), ('user_process_code', 'S10'), ('acquisition_mode', '<u2'), ('bin_size', '<f4'), ('branching_fraction', '<f4'), ('dose_start_time', '<u4'), ('dosage', '<f4'), ('well_counter_corr_factor', '<f4'), ('data_units', 'S32'), ('septa_state', '<u2'), ('fill', 'S12')])¶
EcatImage
¶
- class nibabel.ecat.EcatImage(dataobj, affine, header, subheader, mlist, extra=None, file_map=None)¶
Bases:
SpatialImage
Class returns a list of Ecat images, with one image(hdr/data) per frame
Initialize Image
The image is a combination of (array, affine matrix, header, subheader, mlist) with optional meta data in extra, and filename / file-like objects contained in the file_map.
- Parameters:
- dataobjarray-like
image data
- affineNone or (4,4) array-like
homogeneous affine giving relationship between voxel coords and world coords.
- headerNone or header instance
meta data for this image format
- subheaderNone or subheader instance
meta data for each sub-image for frame in the image
- mlistNone or array
Matrix list array giving offset and order of data in file
- extraNone or mapping, optional
metadata associated with this image that cannot be stored in header or subheader
- file_mapmapping, optional
mapping giving file information for this image format
Examples
>>> import os >>> import nibabel as nib >>> nibabel_dir = os.path.dirname(nib.__file__) >>> from nibabel import ecat >>> ecat_file = os.path.join(nibabel_dir,'tests','data','tinypet.v') >>> img = ecat.load(ecat_file) >>> frame0 = img.get_frame(0) >>> frame0.shape == (10, 10, 3) True >>> data4d = img.get_fdata() >>> data4d.shape == (10, 10, 3, 1) True
- __init__(dataobj, affine, header, subheader, mlist, extra=None, file_map=None)¶
Initialize Image
The image is a combination of (array, affine matrix, header, subheader, mlist) with optional meta data in extra, and filename / file-like objects contained in the file_map.
- Parameters:
- dataobjarray-like
image data
- affineNone or (4,4) array-like
homogeneous affine giving relationship between voxel coords and world coords.
- headerNone or header instance
meta data for this image format
- subheaderNone or subheader instance
meta data for each sub-image for frame in the image
- mlistNone or array
Matrix list array giving offset and order of data in file
- extraNone or mapping, optional
metadata associated with this image that cannot be stored in header or subheader
- file_mapmapping, optional
mapping giving file information for this image format
Examples
>>> import os >>> import nibabel as nib >>> nibabel_dir = os.path.dirname(nib.__file__) >>> from nibabel import ecat >>> ecat_file = os.path.join(nibabel_dir,'tests','data','tinypet.v') >>> img = ecat.load(ecat_file) >>> frame0 = img.get_frame(0) >>> frame0.shape == (10, 10, 3) True >>> data4d = img.get_fdata() >>> data4d.shape == (10, 10, 3, 1) True
- ImageArrayProxy¶
alias of
EcatImageArrayProxy
- property affine¶
- classmethod from_file_map(file_map, *, mmap=True, keep_file_open=None)¶
class method to create image from mapping specified in file_map
- classmethod from_image(img)¶
Class method to create new instance of own class from img
- Parameters:
- img
spatialimage
instance In fact, an object with the API of
spatialimage
- specificallydataobj
,affine
,header
andextra
.
- img
- Returns:
- cimg
spatialimage
instance Image, of our own class
- cimg
- get_data_dtype(frame)¶
- get_frame(frame, orientation=None)¶
Get full volume for a time frame
- Parameters:
frame – Time frame index from where to fetch data
orientation – None (default), ‘neurological’ or ‘radiological’
- Return type:
Numpy array containing (possibly oriented) raw data
- get_frame_affine(frame)¶
returns 4X4 affine
- get_mlist()¶
get access to the mlist
- get_subheaders()¶
get access to subheaders
- header_class¶
alias of
EcatHeader
- classmethod load(filespec)¶
Class method to create image from filename filename
- Parameters:
- filenamestr
Filename of image to load
- mmap{True, False, ‘c’, ‘r’}, optional, keyword only
mmap controls the use of numpy memory mapping for reading image array data. If False, do not try numpy
memmap
for data array. If one of {‘c’, ‘r’}, try numpy memmap withmode=mmap
. A mmap value of True gives the same behavior asmmap='c'
. If image data file cannot be memory-mapped, ignore mmap value and read array from file.- keep_file_open{ None, True, False }, optional, keyword only
keep_file_open controls whether a new file handle is created every time the image is accessed, or a single file handle is created and used for the lifetime of this
ArrayProxy
. IfTrue
, a single file handle is created and used. IfFalse
, a new file handle is created every time the image is accessed. The default value (None
) will result in the value ofnibabel.arrayproxy.KEEP_FILE_OPEN_DEFAULT
being used.
- Returns:
- imgDataobjImage instance
- property shape¶
- to_file_map(file_map=None)¶
Write ECAT7 image to file_map or contained
self.file_map
The format consist of:
- A main header (512L) with dictionary entries in the form
[numAvail, nextDir, previousDir, numUsed]
For every frame (3D volume in 4D data) - A subheader (size = frame_offset) - Frame data (3D volume)
EcatImageArrayProxy
¶
EcatSubHeader
¶
- class nibabel.ecat.EcatSubHeader(hdr, mlist, fileobj)¶
Bases:
object
parses the subheaders in the ecat (.v) file there is one subheader for each frame in the ecat file
- Parameters:
- hdrEcatHeader
ECAT main header
- mlistarray shape (N, 4)
Matrix list
- fileobjECAT file <filename>.v fileholder or file object
with read, seek methods
- __init__(hdr, mlist, fileobj)¶
parses the subheaders in the ecat (.v) file there is one subheader for each frame in the ecat file
- Parameters:
- hdrEcatHeader
ECAT main header
- mlistarray shape (N, 4)
Matrix list
- fileobjECAT file <filename>.v fileholder or file object
with read, seek methods
- data_from_fileobj(frame=0, orientation=None)¶
Read scaled data from file for a given frame
- Parameters:
frame – Time frame index from where to fetch data
orientation – None (default), ‘neurological’ or ‘radiological’
- Return type:
Numpy array containing (possibly oriented) raw data
See also
raw_data_from_fileobj
- get_frame_affine(frame=0)¶
returns best affine for given frame of data
- get_nframes()¶
returns number of frames
- get_shape(frame=0)¶
returns shape of given frame
- get_zooms(frame=0)¶
returns zooms …pixdims
- raw_data_from_fileobj(frame=0, orientation=None)¶
Get raw data from file object.
- Parameters:
frame – Time frame index from where to fetch data
orientation – None (default), ‘neurological’ or ‘radiological’
- Return type:
Numpy array containing (possibly oriented) raw data
See also
data_from_fileobj
get_frame_order¶
- nibabel.ecat.get_frame_order(mlist)¶
Returns the order of the frames stored in the file Sometimes Frames are not stored in the file in chronological order, this can be used to extract frames in correct order
- Returns:
- id_dict: dict mapping frame number -> [mlist_row, mlist_id]
- (where mlist id is value in the first column of the mlist matrix )
Examples
>>> import os >>> import nibabel as nib >>> nibabel_dir = os.path.dirname(nib.__file__) >>> from nibabel import ecat >>> ecat_file = os.path.join(nibabel_dir,'tests','data','tinypet.v') >>> img = ecat.load(ecat_file) >>> mlist = img.get_mlist() >>> get_frame_order(mlist) {0: [0, 16842758]}
read_mlist¶
- nibabel.ecat.read_mlist(fileobj, endianness)¶
read (nframes, 4) matrix list array from fileobj
- Parameters:
- fileobjfile-like
an open file-like object implementing
seek
andread
- Returns:
- mlist(nframes, 4) ndarray
matrix list is an array with
nframes
rows and columns:0: Matrix identifier (frame number)
1: matrix data start block number (subheader followed by image data)
2: Last block number of matrix (image) data
3: Matrix status
1: hxists - rw
2: exists - ro
3: matrix deleted
Notes
A block is 512 bytes.
block_no
in the code below is 1-based. block 1 is the main header, and the mlist blocks start at block number 2.The 512 bytes in an mlist block contain 32 rows of the int32 (nframes, 4) mlist matrix.
The first row of these 32 looks like a special row. The 4 values appear to be (respectively):
not sure - maybe negative number of mlist rows (out of 31) that are blank and not used in this block. Called nfree but unused in CTI code;
block_no - of next set of mlist entries or 2 if no more entries. We also allow 1 or 0 to signal no more entries;
<no idea>. Called prvblk in CTI code, so maybe previous block no;
n_rows - number of mlist rows in this block (between ?0 and 31) (called nused in CTI code).
read_subheaders¶
- nibabel.ecat.read_subheaders(fileobj, mlist, endianness)¶
Retrieve all subheaders and return list of subheader recarrays
- Parameters:
- fileobjfile-like
implementing
read
andseek
- mlist(nframes, 4) ndarray
Columns are: * 0 - Matrix identifier. * 1 - subheader block number * 2 - Last block number of matrix data block. * 3 - Matrix status
- endianness{‘<’, ‘>’}
little / big endian code
- Returns:
- subheaderslist
List of subheader structured arrays