NiBabel

Access a cacophony of neuro-imaging file formats

Table Of Contents

Previous topic

ecat

Next topic

trackvis

Reggie -- the one

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 with mode=mmap. A mmap value of True gives the same behavior as mmap='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 with mode=mmap. A mmap value of True gives the same behavior as mmap='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

PARRECError

class nibabel.parrec.PARRECError

Bases: exceptions.Exception

Exception for PAR/REC format related problems.

To be raised whenever PAR/REC is not happy, or we are not happy with PAR/REC.

__init__()

x.__init__(...) initializes x; see help(type(x)) for signature

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, use self.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 a shape attribute or property

affine : 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 a shape attribute or property

affine : 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 with mode=mmap. A mmap value of True gives the same behavior as mmap='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 with mode=mmap. A mmap value of True gives the same behavior as mmap='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 with mode=mmap. A mmap value of True gives the same behavior as mmap='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 with mode=mmap. A mmap value of True gives the same behavior as mmap='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()).

one_line

nibabel.parrec.one_line(long_str)

Make maybe mutli-line long_str into one long line

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.