parrec
¶
Read images in PAR/REC format.
This is yet another MRI image format generated by Philips scanners. It is an ASCII header (PAR) plus a binary blob (REC).
This implementation aims to read version 4 and 4.2 of this format. Other versions could probably be supported, but we need example images to test against. If you want us to support another version, and have an image we can add to the test suite, let us know. You would make us very happy by submitting a pull request.
PAR file format¶
The PAR format appears to have two sections:
General information¶
This is a set of lines each giving one key : value pair, examples:
. EPI factor <0,1=no EPI> : 39
. Dynamic scan <0=no 1=yes> ? : 1
. Diffusion <0=no 1=yes> ? : 0
(from nibabe/tests/data/phantom_EPI_asc_CLEAR_2_1.PAR)
Image information¶
There is a #
prefixed list of fields under the heading “IMAGE INFORMATION
DEFINITION”. From the same file, here is the start of this list:
# === IMAGE INFORMATION DEFINITION =============================================
# The rest of this file contains ONE line per image, this line contains the following information:
#
# slice number (integer)
# echo number (integer)
# dynamic scan number (integer)
There follows a space separated table with values for these fields, each row containing all the named values. Here’s the first few lines from the example file above:
# === IMAGE INFORMATION ==========================================================
# sl ec dyn ph ty idx pix scan% rec size (re)scale window angulation offcentre thick gap info spacing echo dtime ttime diff avg flip freq RR-int turbo delay b grad cont anis diffusion L.ty
1 1 1 1 0 2 0 16 62 64 64 0.00000 1.29035 4.28404e-003 1070 1860 -13.26 -0.00 -0.00 2.51 -0.81 -8.69 6.000 2.000 0 1 0 2 3.750 3.750 30.00 0.00 0.00 0.00 0 90.00 0 0 0 39 0.0 1 1 8 0 0.000 0.000 0.000 1
2 1 1 1 0 2 1 16 62 64 64 0.00000 1.29035 4.28404e-003 1122 1951 -13.26 -0.00 -0.00 2.51 6.98 -10.53 6.000 2.000 0 1 0 2 3.750 3.750 30.00 0.00 0.00 0.00 0 90.00 0 0 0 39 0.0 1 1 8 0 0.000 0.000 0.000 1
3 1 1 1 0 2 2 16 62 64 64 0.00000 1.29035 4.28404e-003 1137 1977 -13.26 -0.00 -0.00 2.51 14.77 -12.36 6.000 2.000 0 1 0 2 3.750 3.750 30.00 0.00 0.00 0.00 0 90.00 0 0 0 39 0.0 1 1 8 0 0.000 0.000 0.000 1
Orientation¶
PAR files refer to orientations “ap”, “fh” and “rl”.
Nibabel’s required affine output axes are RAS (left to Right, posterior to Anterior, inferior to Superior). The correspondence of the PAR file’s axes to RAS axes is:
- ap = anterior -> posterior = negative A in RAS
- fh = foot -> head = S in RAS
- rl = right -> left = negative R in RAS
The orientation of the PAR file axes corresponds to DICOM’s LPS coordinate system (right to Left, anterior to Posterior, inferior to Superior), but in a different order.
We call the PAR file’s axis system “PSL” (Posterior, Superior, Left)
Data type¶
It seems that everyone agrees that Philips stores REC data in little-endian format - see https://github.com/nipy/nibabel/issues/274
Philips XML header files, and some previous experience, suggest that the REC data is always stored as 8 or 16 bit unsigned integers - see https://github.com/nipy/nibabel/issues/275
PARRECArrayProxy (*args, **kwargs) |
Initialize PARREC array proxy |
PARRECError |
Exception for PAR/REC format related problems. |
PARRECHeader (info, image_defs[, ...]) |
PAR/REC header |
PARRECImage (dataobj, affine[, header, ...]) |
PAR/REC image |
load |
Create PARREC image from filename filename |
one_line (long_str) |
Make maybe mutli-line long_str into one long line |
parse_PAR_header (fobj) |
Parse a PAR header and aggregate all information into useful containers. |
vol_is_full (slice_nos, slice_max[, slice_min]) |
Vector with True for slices in complete volume, False otherwise |
vol_numbers (slice_nos) |
Calculate volume numbers inferred from slice numbers slice_nos |
PARRECArrayProxy
¶
-
class
nibabel.parrec.
PARRECArrayProxy
(*args, **kwargs)¶ Bases:
object
Initialize PARREC array proxy
Parameters: file_like : file-like object
Filename or object implementing
read, seek, tell
header : PARRECHeader instance
Implementing
get_data_shape, get_data_dtype
,get_sorted_slice_indices
,get_data_scaling
,get_rec_shape
.mmap : {True, False, ‘c’, ‘r’}, optional, keyword only
mmap controls the use of numpy memory mapping for reading 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 file_like cannot be memory-mapped, ignore mmap value and read array from file.scaling : {‘fp’, ‘dv’}, optional, keyword only
Type of scaling to use - see header
get_data_scaling
method.-
__init__
(*args, **kwargs)¶ Initialize PARREC array proxy
Parameters: file_like : file-like object
Filename or object implementing
read, seek, tell
header : PARRECHeader instance
Implementing
get_data_shape, get_data_dtype
,get_sorted_slice_indices
,get_data_scaling
,get_rec_shape
.mmap : {True, False, ‘c’, ‘r’}, optional, keyword only
mmap controls the use of numpy memory mapping for reading 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 file_like cannot be memory-mapped, ignore mmap value and read array from file.scaling : {‘fp’, ‘dv’}, optional, keyword only
Type of scaling to use - see header
get_data_scaling
method.
-
dtype
¶
-
get_unscaled
()¶
-
is_proxy
¶
-
shape
¶
-
PARRECHeader
¶
-
class
nibabel.parrec.
PARRECHeader
(info, image_defs, permit_truncated=False)¶ Bases:
nibabel.spatialimages.Header
PAR/REC header
Parameters: info : dict
“General information” from the PAR file (as returned by parse_PAR_header()).
image_defs : array
Structured array with image definitions from the PAR file (as returned by parse_PAR_header()).
permit_truncated : bool, optional
If True, a warning is emitted instead of an error when a truncated recording is detected.
-
__init__
(info, image_defs, permit_truncated=False)¶ Parameters: info : dict
“General information” from the PAR file (as returned by parse_PAR_header()).
image_defs : array
Structured array with image definitions from the PAR file (as returned by parse_PAR_header()).
permit_truncated : bool, optional
If True, a warning is emitted instead of an error when a truncated recording is detected.
-
as_analyze_map
()¶ Convert PAR parameters to NIFTI1 format
-
copy
()¶
-
classmethod
from_fileobj
(klass, fileobj, permit_truncated=False)¶
-
classmethod
from_header
(klass, header=None)¶
-
get_affine
(origin='scanner')¶ Compute affine transformation into scanner space.
The method only considers global rotation and offset settings in the header and ignores potentially deviating information in the image definitions.
Parameters: origin : {‘scanner’, ‘fov’}
Transformation origin. By default the transformation is computed relative to the scanner’s iso center. If ‘fov’ is requested the transformation origin will be the center of the field of view instead.
Returns: aff : (4, 4) array
4x4 array, with output axis order corresponding to RAS or (x,y,z) or (lr, pa, fh).
Notes
Transformations appear to be specified in (ap, fh, rl) axes. The orientation of data is recorded in the “slice orientation” field of the PAR header “General Information”.
We need to:
- translate to coordinates in terms of the center of the FOV
- apply voxel size scaling
- reorder / flip the data to Philips’ PSL axes
- apply the rotations
- apply any isocenter scaling offset if origin == “scanner”
- reorder and flip to RAS axes
-
get_bvals_bvecs
()¶ Get bvals and bvecs from data
Returns: b_vals : None or array
Array of b values, shape (n_directions,), or None if not a diffusion acquisition.
b_vectors : None or array
Array of b vectors, shape (n_directions, 3), or None if not a diffusion acquisition.
-
get_data_offset
()¶ PAR header always has 0 data offset (into REC file)
-
get_data_scaling
(method='dv')¶ Returns scaling slope and intercept.
Parameters: method : {‘fp’, ‘dv’}
Scaling settings to be reported – see notes below.
Returns: slope : array
scaling slope
intercept : array
scaling intercept
Notes
The PAR header contains two different scaling settings: ‘dv’ (value on console) and ‘fp’ (floating point value). Here is how they are defined:
PV: value in REC RS: rescale slope RI: rescale intercept SS: scale slope
DV = PV * RS + RI FP = DV / (RS * SS)
-
get_echo_train_length
()¶ Echo train length of the recording
-
get_q_vectors
()¶ Get Q vectors from the data
Returns: q_vectors : None or array
Array of q vectors (bvals * bvecs), or None if not a diffusion acquisition.
-
get_rec_shape
()¶
-
get_slice_orientation
()¶ Returns the slice orientation label.
Returns: orientation : {‘transverse’, ‘sagittal’, ‘coronal’}
-
get_sorted_slice_indices
()¶ Indices to sort (and maybe discard) slices in REC file
Returns list for indexing into the last (third) dimension of the REC data array, and (equivalently) the only dimension of
self.image_defs
.If the recording is truncated, the returned indices take care of discarding any indices that are not meant to be used.
-
get_voxel_size
()¶ Returns the spatial extent of a voxel.
Does not include the slice gap in the slice extent.
This function is deprecated and we will remove it in future versions of nibabel. Please use
get_zooms
instead. If you need the slice thickness not including the slice gap, useself.image_defs['slice thickness']
.Returns: vox_size: shape (3,) ndarray :
-
get_water_fat_shift
()¶ Water fat shift, in pixels
-
set_data_offset
(offset)¶ PAR header always has 0 data offset (into REC file)
-
PARRECImage
¶
-
class
nibabel.parrec.
PARRECImage
(dataobj, affine, header=None, extra=None, file_map=None)¶ Bases:
nibabel.spatialimages.SpatialImage
PAR/REC image
Initialize image
The image is a combination of (array, affine matrix, header), with optional metadata in extra, and filename / file-like objects contained in the file_map mapping.
Parameters: dataobj : object
Object containg image data. It should be some object that retuns an array from
np.asanyarray
. It should have ashape
attribute or propertyaffine : None or (4,4) array-like
homogenous affine giving relationship between voxel coordinates and world coordinates. Affine can also be None. In this case,
obj.affine
also returns None, and the affine as written to disk will depend on the file format.header : None or mapping or header instance, optional
metadata for this image format
extra : None or mapping, optional
metadata to associate with image that cannot be stored in the metadata of this image type
file_map : mapping, optional
mapping giving file information for this image format
-
__init__
(dataobj, affine, header=None, extra=None, file_map=None)¶ Initialize image
The image is a combination of (array, affine matrix, header), with optional metadata in extra, and filename / file-like objects contained in the file_map mapping.
Parameters: dataobj : object
Object containg image data. It should be some object that retuns an array from
np.asanyarray
. It should have ashape
attribute or propertyaffine : None or (4,4) array-like
homogenous affine giving relationship between voxel coordinates and world coordinates. Affine can also be None. In this case,
obj.affine
also returns None, and the affine as written to disk will depend on the file format.header : None or mapping or header instance, optional
metadata for this image format
extra : None or mapping, optional
metadata to associate with image that cannot be stored in the metadata of this image type
file_map : mapping, optional
mapping giving file information for this image format
-
ImageArrayProxy
¶ alias of
PARRECArrayProxy
-
files_types
= (('image', '.rec'), ('header', '.par'))¶
-
classmethod
from_file_map
(*args, **kwargs)¶ Create PARREC image from file map file_map
Parameters: file_map : dict
dict with keys
image, header
and values being fileholder objects for the respective REC and PAR files.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.permit_truncated : {False, True}, optional, keyword-only
If False, raise an error for an image where the header shows signs that fewer slices / volumes were recorded than were expected.
scaling : {‘dv’, ‘fp’}, optional, keyword-only
Scaling method to apply to data (see
PARRECHeader.get_data_scaling()
).
-
classmethod
from_filename
(*args, **kwargs)¶ Create PARREC image from filename filename
Parameters: filename : str
Filename of “PAR” or “REC” file
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.permit_truncated : {False, True}, optional, keyword-only
If False, raise an error for an image where the header shows signs that fewer slices / volumes were recorded than were expected.
scaling : {‘dv’, ‘fp’}, optional, keyword-only
Scaling method to apply to data (see
PARRECHeader.get_data_scaling()
).
-
header_class
¶ alias of
PARRECHeader
-
classmethod
load
(*args, **kwargs)¶ Create PARREC image from filename filename
Parameters: filename : str
Filename of “PAR” or “REC” file
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.permit_truncated : {False, True}, optional, keyword-only
If False, raise an error for an image where the header shows signs that fewer slices / volumes were recorded than were expected.
scaling : {‘dv’, ‘fp’}, optional, keyword-only
Scaling method to apply to data (see
PARRECHeader.get_data_scaling()
).
-
load¶
-
nibabel.parrec.
load
(*args, **kwargs)¶ Create PARREC image from filename filename
Parameters: filename : str
Filename of “PAR” or “REC” file
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.permit_truncated : {False, True}, optional, keyword-only
If False, raise an error for an image where the header shows signs that fewer slices / volumes were recorded than were expected.
scaling : {‘dv’, ‘fp’}, optional, keyword-only
Scaling method to apply to data (see
PARRECHeader.get_data_scaling()
).
parse_PAR_header¶
-
nibabel.parrec.
parse_PAR_header
(fobj)¶ Parse a PAR header and aggregate all information into useful containers.
Parameters: fobj : file-object
The PAR header file object.
Returns: general_info : dict
Contains all “General Information” from the header file
image_info : ndarray
Structured array with fields giving all “Image information” in the header
vol_is_full¶
-
nibabel.parrec.
vol_is_full
(slice_nos, slice_max, slice_min=1)¶ Vector with True for slices in complete volume, False otherwise
Parameters: slice_nos : sequence
Sequence of slice numbers, e.g.
[1, 2, 3, 4, 1, 2, 3, 4]
.slice_max : int
Highest slice number for a full slice set. Slice set will be
range(slice_min, slice_max+1)
.slice_min : int
Lowest slice number for full slice set.
Returns: is_full : array
Bool vector with True for slices in full volumes, False for slices in partial volumes. A full volume is a volume with all slices in the
slice set
as defined above.Raises: ValueError :
if any slice_nos value is outside slice set.
vol_numbers¶
-
nibabel.parrec.
vol_numbers
(slice_nos)¶ Calculate volume numbers inferred from slice numbers slice_nos
The volume number for each slice is the number of times this slice has occurred previously in the slice_nos sequence
Parameters: slice_nos : sequence
Sequence of slice numbers, e.g.
[1, 2, 3, 4, 1, 2, 3, 4]
.Returns: vol_nos : list
A list, the same length of slice_nos giving the volume number for each corresponding slice number.