compose¶
Combine a chain of spatial transformations (affine matrices, displacement fields, velocity fields, and their inverses) into a single transformation. Use it to invert a transformation, to merge an affine and a non-linear registration into one file, or to prepare a transformation that you will apply to many images.
Description¶
compose uses the same description of a transformation chain as reslice, and instead of resampling an image, it writes the resulting transformation. There are no input images: the command line is a list of transformations, optionally followed by a target and an output name.
The result is one of two things:
- If all transformations are linear and you give no target, the result is a single linear transformation, written as an
.ltafile: the product of the matrices, after any inversion. - Otherwise the result is a dense displacement field, defined on the voxel grid of a target image, and written as a volume with three components in its last dimension.
How the chain is read¶
As in reslice, each transformation maps coordinates of the output space to coordinates of the input space, and if you list \(T_1, T_2, \dots, T_n\) in this order, the composed transformation is
so that the last transformation on the command line is applied first to a point, and the first one last. List the transformations in order from the "input" side towards the "output" side, exactly as you would for reslice. The detailed rules, the transformation types and the direction conventions are explained in reslice; they apply here without change.
Velocity fields are handled as in reslice. A velocity file can be followed by a JSON file of shooting parameters. If there is one, or if a file with the same name as the velocity field and the extension .json exists (as written by register), its model entry tells whether the field is an initial velocity integrated by geodesic shooting (shoot, the default) or a stationary velocity field (svf), and its inversion entry selects the inversion method of register --inversion. Without a JSON file, the field is a stationary velocity field, exponentiated by scaling and squaring with 8 steps. Its fast entry selects the shooting scheme, as in reslice (a JSON file without it uses the fast scheme). As in reslice, -id uses regularised Gauss-Newton steps when the sidecar of a smalldef displacement says so. Two optional numbers after the file (and after the JSON file, if any) are time bounds: -v FILE T0 T1 is the part of the path of the velocity from time T0 to time T1, with 0 and 1 by default. The square forms -v2 and -iv2 are shorthands for bounds of 0 to 0.5 and 0.5 to 0, and -iv swaps the bounds. The details are explained in reslice.
Consecutive linear transformations are multiplied together first, in the order you wrote them.
To invert a composition, reverse the order and toggle -i on every transformation. For instance, the inverse of -il affine.lta -v velocity.nii.gz is -iv velocity.nii.gz -l affine.lta. A single transformation is inverted by writing it with its -i tag: compose -il affine.lta writes the inverse matrix.
The target grid¶
A dense field needs a grid on which it is defined. It is the grid of -t FILE if you give one. Otherwise, it is the grid (shape and orientation matrix) of the file of the last non-linear transformation on the command line, that is, the one that is applied first. If all transformations are linear, there is no grid, and a matrix is written, unless you give -t, in which case a displacement field on the target grid is written.
At every voxel \(x\) of the target grid, with \(M\) the orientation matrix of the target, the position \(y = T(Mx)\) is computed. The displacement written at \(x\) is then \(y - Mx\) in millimetres (-ou mm), or \(M^{-1}y - x\) in voxels of the target grid (-ou vox, the default). The output file carries the orientation matrix of the target. In voxel units, it is a displacement field that can be given straight back to reslice or compose as a -d field, together with the same target, and it then reproduces the chain: see the last example.
A displacement written in millimetres is a correct world-space displacement. To reuse it in reslice or compose, give it with -d FILE -u mm.
Output files¶
The default output name is composed{ext}: composed.lta for a matrix, composed.nii.gz for a field, in the current directory. If you give -o, the name is used as it is. Its extension must suit the content: .lta for a matrix, a volume extension such as .nii.gz for a field. A name with the field {ext} in it is filled with .lta or .nii.gz as appropriate.
Fields are written in floating point (32 bits). Matrices are written as FreeSurfer linear transform arrays.
Arguments¶
compose takes no positional arguments. The first argument on the command line must be a transformation tag; a value that does not belong to a tag is an error.
A bare -- completes the option just before it, so that the last value can start with a dash: nitorch compose -l a.lta -o -- -out.nii. Only the last option can take dash-prefixed values this way; write the others as ./-name.
Options¶
Transformations¶
| Option | Value | Description | Default |
|---|---|---|---|
-l, --linear |
FILE |
Linear transformation (an .lta or .dat matrix file). |
|
-d, --displacement |
FILE |
Dense displacement field. | |
-v, --velocity |
FILE [JSON] [T0 T1] |
Velocity field. With a JSON file of shooting parameters (given, or found next to the field), it is integrated by geodesic shooting; otherwise it is exponentiated by scaling and squaring. T0 T1 are optional time bounds (default 0 and 1): the transformation is the part of the path from T0 to T1. |
|
-il, -id, -iv |
FILE |
The inverse of a linear transformation, of a displacement field, of a velocity field (-iv also takes an optional JSON and time bounds). |
|
-l2, -v2 |
FILE |
The file holds the square of the transformation: its square root is used. -v2 also takes an optional JSON and time bounds. |
|
-il2, -iv2 |
FILE |
The inverse of the square root. | |
-u, --unit |
{vox,mm} |
After -d/-id only: unit of the displacements. Voxels of the field's own grid, or millimetres. |
vox |
-n, --order |
ORDER |
After -d/-id only: order of the splines that encode the field (0 to 7; 1 is linear). |
1 |
At least one transformation is required. The inverse forms also have long names: --linear-inverse, --displacement-inverse and --velocity-inverse; the square forms have --linear-square and --velocity-square.
Output¶
| Option | Value | Description | Default |
|---|---|---|---|
-t, --target |
FILE |
Image that defines the grid on which a displacement field is written. Only its shape and orientation matrix are used. | grid of the last non-linear transformation; none if all are linear |
-o, --output |
FILE |
Output file. | composed{ext} |
-ou, --output-unit |
{vox,mm} |
Unit of the output displacement field: voxels of the target grid (any value starting with v) or millimetres (any other value). Ignored for a matrix. |
vox |
-cpu, --cpu |
Use the CPU. | CPU | |
-gpu, --gpu |
[ID] |
Use a GPU, optionally the one with this index (see hardware). | off |
Examples¶
Combine two rigid registrations into one matrix. The matrix in b.lta is applied to a point first, then the one in a.lta:
Invert an affine matrix:
Compute the inverse of a diffeomorphism from its velocity field. The field is defined on the grid of the velocity file, and written in voxel units:
If velocity.nii.gz was written by register with its velocity.json next to it, the commands above integrate the velocity by geodesic shooting. To use other shooting parameters, give a JSON file right after the velocity file. To compute the displacement to the midpoint of the geodesic instead of the full transformation, use -v2, or equivalently the time bounds 0 and 0.5:
nitorch compose -v2 velocity.nii.gz params.json -o half_disp.nii.gz
nitorch compose -v velocity.nii.gz params.json 0 0.5 -o half_disp.nii.gz
Merge an affine and a non-linear registration into a single displacement field on the fixed grid, expressed in millimetres. The velocity field is applied to points of the grid first, then the inverse affine:
Write the same transformation in voxel units, and use it to resample the moving image. Resampling with the single field is equivalent to resampling through the chain, and is faster when many images share the transformation:
nitorch compose -il affine.lta -v velocity.nii.gz -t fix.nii.gz -o mov_to_fix.nii.gz
nitorch reslice mov.nii.gz -d mov_to_fix.nii.gz -t fix.nii.gz -o mov_in_fix.nii.gz
Express a matrix as a displacement field on the grid of an image, for use in a tool that only accepts fields:
See also¶
resliceapplies a chain of transformations to images and explains the conventions in full.vexpexponentiates a velocity field on its own.- Spatial transformations in the CLI conventions.