Utilities for working with Images and common neuroimaging spaces
Images are very general things, and don’t know anything about the kinds of spaces they refer to, via their coordinate map.
There are a set of common neuroimaging spaces. When we create neuroimaging Images, we want to place them in neuroimaging spaces, and return information about common neuroimaging spaces.
We do this by putting information about neuroimaging spaces in functions and variables in the nipy.core.reference.spaces module, and in this module.
This keeps the specific neuroimaging spaces out of our Image object.
>>> from nipy.core.api import Image, vox2mni, rollimg, xyz_affine, as_xyz_image
Make a standard 4D xyzt image in MNI space.
First the data and affine:
>>> data = np.arange(24).reshape((1,2,3,4))
>>> affine = np.diag([2,3,4,1]).astype(float)
We can add the TR (==2.0) to make the full 5x5 affine we need
>>> img = Image(data, vox2mni(affine, 2.0))
>>> img.affine
array([[ 2., 0., 0., 0., 0.],
[ 0., 3., 0., 0., 0.],
[ 0., 0., 4., 0., 0.],
[ 0., 0., 0., 2., 0.],
[ 0., 0., 0., 0., 1.]])
In this case the neuroimaging ‘xyz_affine’ is just the 4x4 from the 5x5 in the image
>>> xyz_affine(img)
array([[ 2., 0., 0., 0.],
[ 0., 3., 0., 0.],
[ 0., 0., 4., 0.],
[ 0., 0., 0., 1.]])
However, if we roll time first in the image array, we can’t any longer get an xyz_affine that makes sense in relationship to the voxel data:
>>> img_t0 = rollimg(img, 't')
>>> xyz_affine(img_t0)
Traceback (most recent call last):
...
AxesError: First 3 input axes must correspond to X, Y, Z
But we can fix this:
>>> img_t0_affable = as_xyz_image(img_t0)
>>> xyz_affine(img_t0_affable)
array([[ 2., 0., 0., 0.],
[ 0., 3., 0., 0.],
[ 0., 0., 4., 0.],
[ 0., 0., 0., 1.]])
It also works with nibabel images, which can only have xyz_affines:
>>> import nibabel as nib
>>> nimg = nib.Nifti1Image(data, affine)
>>> xyz_affine(nimg)
array([[ 2., 0., 0., 0.],
[ 0., 3., 0., 0.],
[ 0., 0., 4., 0.],
[ 0., 0., 0., 1.]])
Return version of img that has a valid xyz affine, or raise error
Parameters : | img : Image instance or nibabel image
name2xyz : None or mapping
|
---|---|
Returns : | reo_img : Image instance or nibabel image
|
Raises : | SpaceTypeError : if img does not have an affine coordinate map AxesError : if not all of x, y, z recognized in img coordmap range AffineError : if axes dropped from the affine contribute to x, y, z coordinates : |
Return True if the image img has an xyz affine
Parameters : | img : Image or nibabel SpatialImage
name2xyz : None or mapping
|
---|---|
Returns : | tf : bool
|
Examples
>>> from nipy.core.api import vox2mni, Image, rollimg
>>> arr = np.arange(24).reshape((2,3,4,1))
>>> img = Image(arr, vox2mni(np.diag([2,3,4,5,1])))
>>> img.coordmap
AffineTransform(
function_domain=CoordinateSystem(coord_names=('i', 'j', 'k', 'l'), name='voxels', coord_dtype=float64),
function_range=CoordinateSystem(coord_names=('mni-x=L->R', 'mni-y=P->A', 'mni-z=I->S', 't'), name='mni', coord_dtype=float64),
affine=array([[ 2., 0., 0., 0., 0.],
[ 0., 3., 0., 0., 0.],
[ 0., 0., 4., 0., 0.],
[ 0., 0., 0., 5., 0.],
[ 0., 0., 0., 0., 1.]])
)
>>> is_xyz_affable(img)
True
>>> time0_img = rollimg(img, 't')
>>> time0_img.coordmap
AffineTransform(
function_domain=CoordinateSystem(coord_names=('l', 'i', 'j', 'k'), name='voxels', coord_dtype=float64),
function_range=CoordinateSystem(coord_names=('mni-x=L->R', 'mni-y=P->A', 'mni-z=I->S', 't'), name='mni', coord_dtype=float64),
affine=array([[ 0., 2., 0., 0., 0.],
[ 0., 0., 3., 0., 0.],
[ 0., 0., 0., 4., 0.],
[ 5., 0., 0., 0., 0.],
[ 0., 0., 0., 0., 1.]])
)
>>> is_xyz_affable(time0_img)
False
Nibabel images always have xyz affines
>>> import nibabel as nib
>>> nimg = nib.Nifti1Image(arr, np.diag([2,3,4,1]))
>>> is_xyz_affable(nimg)
True
Create 3D+ image embedded in space named in world
Parameters : | data : object
xyz_affine : (4, 4) array-like or tuple
world : str or XYZSpace or CoordSysMaker or CoordinateSystem
metadata : None or mapping, optional
|
---|---|
Returns : | img : Image
|
Examples
>>> data = np.arange(24).reshape((2, 3, 4))
>>> aff = np.diag([4, 5, 6, 1])
>>> img = make_xyz_image(data, aff, 'mni')
>>> img
Image(
data=array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
<BLANKLINE>
[[12, 13, 14, 15],
[16, 17, 18, 19],
[20, 21, 22, 23]]]),
coordmap=AffineTransform(
function_domain=CoordinateSystem(coord_names=('i', 'j', 'k'), name='voxels', coord_dtype=float64),
function_range=CoordinateSystem(coord_names=('mni-x=L->R', 'mni-y=P->A', 'mni-z=I->S'), name='mni', coord_dtype=float64),
affine=array([[ 4., 0., 0., 0.],
[ 0., 5., 0., 0.],
[ 0., 0., 6., 0.],
[ 0., 0., 0., 1.]])
))
Now make data 4D; we just add 1. to the diagonal for the new dimension
>>> data4 = data[..., None]
>>> img = make_xyz_image(data4, aff, 'mni')
>>> img.coordmap
AffineTransform(
function_domain=CoordinateSystem(coord_names=('i', 'j', 'k', 'l'), name='voxels', coord_dtype=float64),
function_range=CoordinateSystem(coord_names=('mni-x=L->R', 'mni-y=P->A', 'mni-z=I->S', 't'), name='mni', coord_dtype=float64),
affine=array([[ 4., 0., 0., 0., 0.],
[ 0., 5., 0., 0., 0.],
[ 0., 0., 6., 0., 0.],
[ 0., 0., 0., 1., 0.],
[ 0., 0., 0., 0., 1.]])
)
We can pass in a scalar or tuple to specify scaling for the extra dimension
>>> img = make_xyz_image(data4, (aff, 2.0), 'mni')
>>> img.coordmap.affine
array([[ 4., 0., 0., 0., 0.],
[ 0., 5., 0., 0., 0.],
[ 0., 0., 6., 0., 0.],
[ 0., 0., 0., 2., 0.],
[ 0., 0., 0., 0., 1.]])
>>> data5 = data4[..., None]
>>> img = make_xyz_image(data5, (aff, (2.0, 3.0)), 'mni')
>>> img.coordmap.affine
array([[ 4., 0., 0., 0., 0., 0.],
[ 0., 5., 0., 0., 0., 0.],
[ 0., 0., 6., 0., 0., 0.],
[ 0., 0., 0., 2., 0., 0.],
[ 0., 0., 0., 0., 3., 0.],
[ 0., 0., 0., 0., 0., 1.]])
Return xyz affine from image img if possible, or raise error
Parameters : | img : Image instance or nibabel image
name2xyz : None or mapping
|
---|---|
Returns : | xyz_aff : (4,4) array
|
Raises : | SpaceTypeError : if img does not have an affine coordinate map AxesError : if not all of x, y, z recognized in img coordmap range AffineError : if axes dropped from the affine contribute to x, y, z coordinates : |
Examples
>>> from nipy.core.api import vox2mni, Image
>>> arr = np.arange(24).reshape((2,3,4,1)).astype(float)
>>> img = Image(arr, vox2mni(np.diag([2,3,4,5,1])))
>>> img.coordmap
AffineTransform(
function_domain=CoordinateSystem(coord_names=('i', 'j', 'k', 'l'), name='voxels', coord_dtype=float64),
function_range=CoordinateSystem(coord_names=('mni-x=L->R', 'mni-y=P->A', 'mni-z=I->S', 't'), name='mni', coord_dtype=float64),
affine=array([[ 2., 0., 0., 0., 0.],
[ 0., 3., 0., 0., 0.],
[ 0., 0., 4., 0., 0.],
[ 0., 0., 0., 5., 0.],
[ 0., 0., 0., 0., 1.]])
)
>>> xyz_affine(img)
array([[ 2., 0., 0., 0.],
[ 0., 3., 0., 0.],
[ 0., 0., 4., 0.],
[ 0., 0., 0., 1.]])
Nibabel images always have xyz affines
>>> import nibabel as nib
>>> nimg = nib.Nifti1Image(arr, np.diag([2,3,4,1]))
>>> xyz_affine(nimg)
array([[ 2., 0., 0., 0.],
[ 0., 3., 0., 0.],
[ 0., 0., 4., 0.],
[ 0., 0., 0., 1.]])