Conventions
Spatial transformations
Section titled “Spatial transformations”Format
Section titled “Format”The common file format for anything that implies transformations is the ITK format :
| Transformation type | format |
|---|---|
| linear transformations (e.g. rigid and affine) | .mat |
| non-linear warps and deformation fields | .nii.gz |
Order of operations
Section titled “Order of operations”To guarantee perfect interaction between all components of its library, nf-neuro imposes linear algebra order of operations (from right to left) when applying transformations.
Subworkflows and pipelines
Section titled “Subworkflows and pipelines”To define a sequence of transformations, use either a list or a glob pattern to a list of transformation files
Consider the following sequence of transformations :
and 3 channels, one for each transformation. Use the following to output a channel in the right order :
// All channels are joined on meta, the basic required// metadata defining a subject, minimally [id: id]ch_transformations = ch_T1 .join(ch_T2) .join(ch_T3) .map{ meta, t1, t2, t3 -> [ meta, [ t3, t2, t1 ] ] }Consider the following sequence of transformations :
corresponding to the following example files :
Directorysub-007
Directorytransforms
- transformX.mat
- transformY.nii.gz
- transformZ.mat
Using the Channel.fromFilePairs filesystem parser, which implements alphabetical ordering
by default, you obtain the correct oredering using :
ch_transforms = Channel .fromFilePairs("**/transforms/transform*.{mat,nii.gz}", size: -1) { file -> file.parent.parent.name } // This defines the ID for the file, here subject sub-007 .map{ id, t1, t2, t3 -> [ [id: id], [ t3, t2, t1 ] ] } // [id: id] is the basic required metadata defining a subjectModules that perform registration
Section titled “Modules that perform registration”Registration modules must output their transforms in lists following linear algebra ordering. Additionally, for compatibility with legacy modules, they also must provide individual outputs for an affine and a deformation field (and their inverses).
The following output channels are required :
| Channel name | Transformation |
|---|---|
| image_transform | Transformation from moving space to fixed space |
| inverse_image_transform | Transformation from fixed space to moving space |
| tractogram_transform | Reversed and inversed transformation from moving space to fixed space (usually the same as the inverse_image_transform) |
| inverse_tractogram_transform | Reversed and inversed transformation from fixed space to moving space (usually the same as the image_transform) |
Transformation files must be collected in one single path variable with a glob pattern, using the arity parameter to cast it as a list of files (see example below).
output: tuple val(meta), path("*__transform*.{mat,nii.gz}", arity: '1..*') , emit: image_transform tuple val(meta), path("*__inverse_transform*.{mat,nii.gz}", arity: '1..*'), emit: inverse_image_transform tuple val(meta), path("*__inverse_transform*.{mat,nii.gz}", arity: '1..*'), emit: tractogram_transform tuple val(meta), path("*__transform*.{mat,nii.gz}", arity: '1..*') , emit: inverse_tractogram_transformscript: def prefix = meta.id """ # Moving space touch ${prefix}__transformZ.mat touch ${prefix}__transformY.mat touch ${prefix}__transformX.nii.gz # Fixed space touch ${prefix}__inverse_transformZ.nii.gz touch ${prefix}__inverse_transformY.mat touch ${prefix}__inverse_transformX.mat # Moving space """| Channel name | Transformation |
|---|---|
| affine | Linear transformation from moving space to fixed space |
| warp | Non-linear deformation from moving space to fixed space |
| inverse_affine | Linear transformation from fixed space to moving space |
| inverse_warp | Non-linear deformation from fixed space to moving space |
For compatibility with modules that don’t support parsing the transformation sequences, you must provide single file transformations between fixed and moving spaces. There are many options here, rely on your judgment and knowledge of the module you are implementing. Here are some examples :
Modules that apply transformations
Section titled “Modules that apply transformations”All modules that use transformations and need them provided in input should expect a chain of transformations
in the form of a list and ordered as stated above. If they only use parts of it, they should parse through it to select
the transformations to apply. Define the input variable using a path and the arity parameter in order to ensure
it is interpreted as a list in the script section of the module :
input: tuple val(meta), ..., path(transformations, arity: '1..*')...script:"""for transform in $transformationsdo echo "I'm doing good work using transformation : \$transform"done"""Filenames convention
Section titled “Filenames convention”nf-neuro provides its own custom convention for transformations, based on two required labels that must appear in any transformation filenames :
Format: *_<backward|forward><index>_*.<mat|nii.gz>
- The direction of the transformation is defined by either the
forwardorbackwardlabel. - The label is suffixed with the transformation index in the chain of transformations between spaces. To
follow linear algebra order of transformation, indexes are given in inorder, from
N - 1(first) to0(last), givenNtransformation steps.
Format: *_<affine|warp>.<mat|nii.gz>
The type of the transformation is either affine (also encompasses simple translation and rigid transformations) or warp. The type label must
be located at the end of the transformation name, before the extension.