affines

Utility routines for working with points and affine transforms

AffineError

Errors in calculating or using affines

append_diag(aff, steps[, starts])

Add diagonal elements steps and translations starts to affine

apply_affine(aff, pts)

Apply affine matrix aff to points pts

dot_reduce(*args)

Apply numpy dot product function from right to left on arrays

from_matvec(matrix[, vector])

Combine a matrix and vector into an homogeneous affine

to_matvec(transform)

Split a transform into its matrix and vector components.

voxel_sizes(affine)

Return voxel size for each input axis given affine

AffineError

class nibabel.affines.AffineError

Bases: ValueError

Errors in calculating or using affines

__init__($self, /, *args, **kwargs)

Initialize self. See help(type(self)) for accurate signature.

append_diag

nibabel.affines.append_diag(aff, steps, starts=())

Add diagonal elements steps and translations starts to affine

Typical use is in expanding 4x4 affines to larger dimensions. Nipy is the main consumer because it uses NxM affines, whereas we generally only use 4x4 affines; the routine is here for convenience.

Parameters
aff2D array

N by M affine matrix

stepsscalar or sequence

diagonal elements to append.

startsscalar or sequence

elements to append to last column of aff, representing translations corresponding to the steps. If empty, expands to a vector of zeros of the same length as steps

Returns
aff_plus2D array

Now P by Q where L = len(steps) and P == N+L, Q=N+L

Examples

>>> aff = np.eye(4)
>>> aff[:3,:3] = np.arange(9).reshape((3,3))
>>> append_diag(aff, [9, 10], [99,100])
array([[   0.,    1.,    2.,    0.,    0.,    0.],
       [   3.,    4.,    5.,    0.,    0.,    0.],
       [   6.,    7.,    8.,    0.,    0.,    0.],
       [   0.,    0.,    0.,    9.,    0.,   99.],
       [   0.,    0.,    0.,    0.,   10.,  100.],
       [   0.,    0.,    0.,    0.,    0.,    1.]])

apply_affine

nibabel.affines.apply_affine(aff, pts)

Apply affine matrix aff to points pts

Returns result of application of aff to the right of pts. The coordinate dimension of pts should be the last.

For the 3D case, aff will be shape (4,4) and pts will have final axis length 3 - maybe it will just be N by 3. The return value is the transformed points, in this case:

res = np.dot(aff[:3,:3], pts.T) + aff[:3,3:4]
transformed_pts = res.T

This routine is more general than 3D, in that aff can have any shape (N,N), and pts can have any shape, as long as the last dimension is for the coordinates, and is therefore length N-1.

Parameters
aff(N, N) array-like

Homogenous affine, for 3D points, will be 4 by 4. Contrary to first appearance, the affine will be applied on the left of pts.

pts(…, N-1) array-like

Points, where the last dimension contains the coordinates of each point. For 3D, the last dimension will be length 3.

Returns
transformed_pts(…, N-1) array

transformed points

Examples

>>> aff = np.array([[0,2,0,10],[3,0,0,11],[0,0,4,12],[0,0,0,1]])
>>> pts = np.array([[1,2,3],[2,3,4],[4,5,6],[6,7,8]])
>>> apply_affine(aff, pts) #doctest: +ELLIPSIS
array([[14, 14, 24],
       [16, 17, 28],
       [20, 23, 36],
       [24, 29, 44]]...)

Just to show that in the simple 3D case, it is equivalent to:

>>> (np.dot(aff[:3,:3], pts.T) + aff[:3,3:4]).T #doctest: +ELLIPSIS
array([[14, 14, 24],
       [16, 17, 28],
       [20, 23, 36],
       [24, 29, 44]]...)

But pts can be a more complicated shape:

>>> pts = pts.reshape((2,2,3))
>>> apply_affine(aff, pts) #doctest: +ELLIPSIS
array([[[14, 14, 24],
        [16, 17, 28]],
<BLANKLINE>
       [[20, 23, 36],
        [24, 29, 44]]]...)

dot_reduce

nibabel.affines.dot_reduce(*args)

Apply numpy dot product function from right to left on arrays

For passed arrays \(A, B, C, ... Z\) returns \(A \dot B \dot C ... \dot Z\) where “.” is the numpy array dot product.

Parameters
**argsarrays

Arrays that can be passed to numpy dot function

Returns
dot_productarray

If there are N arguments, result of arg[0].dot(arg[1].dot(arg[2].dot ...  arg[N-2].dot(arg[N-1])))...

from_matvec

nibabel.affines.from_matvec(matrix, vector=None)

Combine a matrix and vector into an homogeneous affine

Combine a rotation / scaling / shearing matrix and translation vector into a transform in homogeneous coordinates.

Parameters
matrixarray-like

An NxM array representing the the linear part of the transform. A transform from an M-dimensional space to an N-dimensional space.

vectorNone or array-like, optional

None or an (N,) array representing the translation. None corresponds to an (N,) array of zeros.

Returns
xformarray

An (N+1, M+1) homogenous transform matrix.

See also

to_matvec

Examples

>>> from_matvec(np.diag([2, 3, 4]), [9, 10, 11])
array([[ 2,  0,  0,  9],
       [ 0,  3,  0, 10],
       [ 0,  0,  4, 11],
       [ 0,  0,  0,  1]])

The vector argument is optional:

>>> from_matvec(np.diag([2, 3, 4]))
array([[2, 0, 0, 0],
       [0, 3, 0, 0],
       [0, 0, 4, 0],
       [0, 0, 0, 1]])

to_matvec

nibabel.affines.to_matvec(transform)

Split a transform into its matrix and vector components.

The tranformation must be represented in homogeneous coordinates and is split into its rotation matrix and translation vector components.

Parameters
transformarray-like

NxM transform matrix in homogeneous coordinates representing an affine transformation from an (N-1)-dimensional space to an (M-1)-dimensional space. An example is a 4x4 transform representing rotations and translations in 3 dimensions. A 4x3 matrix can represent a 2-dimensional plane embedded in 3 dimensional space.

Returns
matrix(N-1, M-1) array

Matrix component of transform

vector(M-1,) array

Vector compoent of transform

See also

from_matvec

Examples

>>> aff = np.diag([2, 3, 4, 1])
>>> aff[:3,3] = [9, 10, 11]
>>> to_matvec(aff)
(array([[2, 0, 0],
       [0, 3, 0],
       [0, 0, 4]]), array([ 9, 10, 11]))

voxel_sizes

nibabel.affines.voxel_sizes(affine)

Return voxel size for each input axis given affine

The affine is the mapping between array (voxel) coordinates and mm (world) coordinates.

The voxel size for the first voxel (array) axis is the distance moved in world coordinates when moving one unit along the first voxel (array) axis. This is the distance between the world coordinate of voxel (0, 0, 0) and the world coordinate of voxel (1, 0, 0). The world coordinate vector of voxel coordinate vector (0, 0, 0) is given by v0 = affine.dot((0, 0, 0, 1)[:3]. The world coordinate vector of voxel vector (1, 0, 0) is v1_ax1 = affine.dot((1, 0, 0, 1))[:3]. The final 1 in the voxel vectors and the [:3] at the end are because the affine works on homogenous coodinates. The translations part of the affine is trans = affine[:3, 3], and the rotations, zooms and shearing part of the affine is rzs = affine[:3, :3]. Because of the final 1 in the input voxel vector, v0 == rzs.dot((0, 0, 0)) + trans, and v1_ax1 == rzs.dot((1, 0, 0)) + trans, and the difference vector is rzs.dot((0, 0, 0)) - rzs.dot((1, 0, 0)) == rzs.dot((1, 0, 0)) == rzs[:, 0]. The distance vectors in world coordinates between (0, 0, 0) and (1, 0, 0), (0, 1, 0), (0, 0, 1) are given by rzs.dot(np.eye(3)) = rzs. The voxel sizes are the Euclidean lengths of the distance vectors. So, the voxel sizes are the Euclidean lengths of the columns of the affine (excluding the last row and column of the affine).

Parameters
affine2D array-like

Affine transformation array. Usually shape (4, 4), but can be any 2D array.

Returns
vox_sizes1D array

Voxel sizes for each input axis of affine. Usually 1D array length 3, but in general has length (N-1) where input affine is shape (M, N).