fsl.data.imagewrapper

This module provides the ImageWrapper class, which can be used to manage data access to nibabel NIFTI images.

Terminology

There are some confusing terms used in this module, so it may be useful to get their definitions straight:

  • Coverage: The portion of an image that has been covered in the data

    range calculation. The ImageWrapper keeps track of the coverage for individual volumes within a 4D image (or slices in a 3D image).

  • Slice: Portion of the image data which is being accessed. A slice

    comprises either a tuple of slice objects (or integers), or a sequence of (low, high) tuples, specifying the index range into each image dimension that is covered by the slice.

  • Expansion: A sequence of (low, high) tuples, specifying an

    index range into each image dimension, that is used to expand the coverage of an image, based on a given set of slices.

  • Fancy slice: Any object which is used to slice an array, and is not

    an int, slice, or Ellipsis, or sequence of these.

class fsl.data.imagewrapper.ImageWrapper(image, name=None, loadData=False, dataRange=None, threaded=False)

Bases: fsl.utils.notifier.Notifier

The ImageWrapper class is a convenience class which manages data access to nibabel NIFTI images. The ImageWrapper class can be used to:

  • Control whether the image is loaded into memory, or kept on disk

  • Incrementally update the known image data range, as more image data is read in.

In memory or on disk?

The image data will be kept on disk, and accessed through the nibabel.Nifti1Image.dataobj (or nibabel.Nifti2Image.dataobj) array proxy, if:

  • The loadData parameter to __init__() is False.

  • The loadData() method never gets called.

  • The image data is not modified (via __setitem__().

If any of these conditions do not hold, the image data will be loaded into memory and accessed directly, via the nibabel.Nifti1Image.get_data method.

Image dimensionality

The ImageWrapper abstracts away trailing image dimensions of length 1. This means that if the header for a NIFTI image specifies that the image has four dimensions, but the fourth dimension is of length 1, you do not need to worry about indexing that fourth dimension. However, all NIFTI images will be presented as having at least three dimensions, so if your image header specifies a third dimension of length 1, you will still need provide an index of 0 for that dimensions, for all data accesses.

Data access

The ImageWrapper can be indexed in one of two ways:

  • With basic numpy-like multi-dimensional array slicing (with step sizes of 1)

  • With boolean array indexing, where the boolean/mask array has the same shape as the image data.

See https://docs.scipy.org/doc/numpy/reference/arrays.indexing.html for more details on numpy indexing.

Data range

In order to avoid the computational overhead of calculating the image data range (its minimum/maximum values) when an image is first loaded in, an ImageWrapper incrementally updates the known image data range as data is accessed. The ImageWrapper keeps track of the image data coverage, the portion of the image which has already been considered in the data range calculation. When data from a region of the image not in the coverage is accessed, the coverage is expanded to include this region. The coverage is always expanded in a rectilinear manner, i.e. the coverage is always rectangular for a 2D image, or cuboid for a 3D image.

For a 4D image, the ImageWrapper internally maintains a separate coverage and known data range for each 3D volume within the image. For a 3D image, separate coverages and data ranges are stored for each 2D slice.

The ImageWrapper implements the Notifier interface. Listeners can register to be notified whenever the known image data range is updated. The data range can be accessed via the dataRange property.

The ImageWrapper class uses the following functions (also defined in this module) to keep track of the portion of the image that has currently been included in the data range calculation:

isValidFancySliceObj

Returns True if the given sliceobj is a valid and fancy slice object.

canonicalSliceObj

Returns a canonical version of the given sliceobj.

sliceObjToSliceTuple

Turns an array slice object into a tuple of (low, high) index pairs, one pair for each dimension in the given shape

sliceTupleToSliceObj

Turns a sequence of (low, high) index pairs into a tuple of array slice objects.

sliceCovered

Returns True if the portion of the image data calculated by the given slices` has already been calculated, ``False otherwise.

calcExpansion

Calculates a series of expansion slices, which can be used to expand the given coverage so that it includes the given slices.

adjustCoverage

Adjusts/expands the given oldCoverage so that it covers the given set of slices.

getTaskThread()

If this ImageWrapper was created with threaded=True, this method returns the TaskThread that is used for running data range calculation tasks. Otherwise, this method returns False.

reset(dataRange=None)

Reset the internal state and known data range of this ImageWrapper.

Parameters

dataRange – A tuple containing the initial (min, max) data range to use.

Note

The dataRange parameter is intended for situations where the image data range is known in advance (e.g. it was calculated earlier, and the image is being re-loaded). If a dataRange is passed in, it will not be overwritten by any range calculated from the data, unless the calculated data range is wider than the provided dataRange.

property dataRange

Returns the currently known data range as a tuple of (min, max) values.

property covered

Returns True if this ImageWrapper has read the entire image data, False otherwise.

property shape

Returns the shape that the image data is presented as. This is the same as the underlying image shape, but with trailing dimensions of length 1 removed, and at least three dimensions.

coverage(vol)

Returns the current image data coverage for the specified volume (for a 4D image, slice for a 3D image, or vector for a 2D images).

Parameters

vol – Index of the volume/slice/vector to return the coverage for.

Returns

The coverage for the specified volume, as a numpy array of shape (nd, 2), where nd is the number of dimensions in the volume.

Note

If the specified volume is not covered, the returned array will contain np.nan values.

loadData()

Forces all of the image data to be loaded into memory.

Note

This method will be called by __init__() if its loadData parameter is True.

fsl.data.imagewrapper.isValidFancySliceObj(sliceobj, shape)

Returns True if the given sliceobj is a valid and fancy slice object.

nibabel refers to slice objects as “fancy” if they comprise anything but tuples of integers and simple slice objects. The ImageWrapper class supports one type of “fancy” slicing, where the sliceobj is a boolean numpy array of the same shape as the image.

This function returns True if the given sliceobj adheres to these requirements, False otherwise.

fsl.data.imagewrapper.canonicalSliceObj(sliceobj, shape)

Returns a canonical version of the given sliceobj. See the nibabel.fileslice.canonical_slicers function.

fsl.data.imagewrapper.expectedShape(sliceobj, shape)

Given a slice object, and the shape of an array to which that slice object is going to be applied, returns the expected shape of the result.

Note

It is assumed that the sliceobj has been passed through the canonicalSliceObj() function.

Parameters
  • sliceobj – Something which can be used to slice an array of shape shape.

  • shape – Shape of the array being sliced.

Returns

A tuple containing:

  • Expected number of dimensions of the result

  • Expected shape of the result (or None if sliceobj is fancy).

fsl.data.imagewrapper.sliceObjToSliceTuple(sliceobj, shape)

Turns an array slice object into a tuple of (low, high) index pairs, one pair for each dimension in the given shape

Parameters
  • sliceobj – Something which can be used to slice an array of shape shape.

  • shape – Shape of the array being sliced.

fsl.data.imagewrapper.sliceTupleToSliceObj(slices)

Turns a sequence of (low, high) index pairs into a tuple of array slice objects.

Parameters

slices – A sequence of (low, high) index pairs.

fsl.data.imagewrapper.adjustCoverage(oldCoverage, slices)

Adjusts/expands the given oldCoverage so that it covers the given set of slices.

Parameters
  • oldCoverage – A numpy array of shape (2, n) containing the (low, high) index pairs for n dimensions of a single slice/volume in the image.

  • slices – A sequence of (low, high) index pairs. If slices contains more dimensions than are specified in oldCoverage, the trailing dimensions are ignored.

Returns

A numpy array containing the adjusted/expanded coverage.

fsl.data.imagewrapper.OVERLAP_ALL = 0

Indicates that the slice is wholly contained within the coverage. This is a return code for the sliceOverlap() function.

fsl.data.imagewrapper.OVERLAP_SOME = 1

Indicates that the slice partially overlaps with the coverage. This is a return code for the sliceOverlap() function.

fsl.data.imagewrapper.OVERLAP_NONE = 2

Indicates that the slice does not overlap with the coverage. This is a return code for the sliceOverlap() function.

fsl.data.imagewrapper.sliceOverlap(slices, coverage)

Determines whether the given slices overlap with the given coverage.

Parameters
  • slices – A sequence of (low, high) index pairs, assumed to cover all image dimensions.

  • coverage – A numpy array of shape (2, nd, nv) (where nd is the number of dimensions being covered, and nv is the number of volumes (or vectors/slices) in the image, which contains the (low, high) index pairs describing the current image coverage.

Returns

One of the following codes:

OVERLAP_ALL OVERLAP_SOME OVERLAP_NONE

fsl.data.imagewrapper.sliceCovered(slices, coverage)

Returns True if the portion of the image data calculated by the given slices` has already been calculated, ``False otherwise.

Parameters
  • slices – A sequence of (low, high) index pairs, assumed to cover all image dimensions.

  • coverage – A numpy array of shape (2, nd, nv) (where nd is the number of dimensions being covered, and nv is the number of volumes (or vectors/slices) in the image, which contains the (low, high) index pairs describing the current image coverage.

fsl.data.imagewrapper.calcExpansion(slices, coverage)

Calculates a series of expansion slices, which can be used to expand the given coverage so that it includes the given slices.

Parameters
  • slices – Slices that the coverage needs to be expanded to cover.

  • coverage – Current image coverage.

Returns

A list of volume indices, and a corresponding list of expansions.

fsl.data.imagewrapper.collapseExpansions(expansions, numDims)

Scans through the given list of expansions (each assumed to pertain to a single 3D image), and combines any which cover the same image area, and cover adjacent volumes.

Args expansions

A list of expansion slices - see calcExpansions().

Args numDims

Number of dimensions covered by each expansion, not including the volume dimension (i.e. 3 for a 4D image).

Returns

A list of expansions, with equivalent expansions that cover adjacent images collapsed down.

Note

For one expansion exp in the expansions list, this function assumes that the range at exp[numDims] contains the image to which exp pertains (i.e. exp[numDims] == (vol, vol + 1)).