brainhops.io.transformations.elastix
elastix / transformix transform parameter files.
elastix writes the result of
a registration as a transform parameter file,
TransformParameters.<n>.txt, which transformix (and SimpleElastix,
ITK-Elastix, ...) reads to resample the moving image onto the fixed
grid. It is a plain-text map from parameter names to values.
| Syntax | Class | Extension | Hints | Writes |
|---|---|---|---|---|
| classic text | ElastixParameterTransform |
.txt |
elastix, transformix, elastix.params |
yes |
| TOML (elastix 5.2) | ElastixTomlTransform |
.toml |
elastix, transformix, elastix.toml |
yes |
A rigid transform
(Transform "EulerTransform")
(NumberOfParameters 6)
(TransformParameters 0.1 -0.2 0.3 1.5 -2 3.25)
(InitialTransformParameterFileName "NoInitialTransform")
(HowToCombineTransforms "Compose")
(FixedImageDimension 3)
(MovingImageDimension 3)
(Size 256 256 128)
(Index 0 0 0)
(Spacing 1 1 2)
(Origin -127.5 -127.5 -127)
(Direction 1 0 0 0 1 0 0 0 1)
(UseDirectionCosines "true")
(CenterOfRotationPoint 4.5 -2 7.25)
(ComputeZYX "false")
Syntax
From Common/ParameterFileParser/itkParameterFileParser.cxx:
- text: one
(Name value value ...)per line. A value is a number or a double-quoted string (no escapes);//starts a comment; tabs are blanks; a name may not repeat. elastix writes booleans as quoted words ("true"). - TOML: one
Name = valueorName = [value, ...]per line,#comments. Only the one-line subset that elastix writes is parsed here (Python has no TOML parser before 3.11).
The parsed map is kept, in file order, in
parameter_map.
A file is claimed only if it names a Transform and carries its
parameters: elastix's registration parameter files share the syntax and
are not transforms.
Conventions
- Space. elastix's transforms are ITK transforms acting on ITK's physical space: LPS millimetres.
- Direction. A transform maps fixed-image points to moving-image points -- the pull direction in which transformix resamples. The transformation read here maps the same way: its input is the fixed image's LPS space, its output the moving image's.
- Blocks. Each file's transform is decoded into the ITK block of
[
brainhops.io.transformations.itk][] that carries the same parameters (y = M (x - c) + c + tabout the centerc):
elastix Transform |
Parameters | Block |
|---|---|---|
TranslationTransform |
t (D) |
TranslationTransform |
EulerTransform (2-D) |
angle, t (3) |
Euler2DTransform |
EulerTransform (3-D) |
ax, ay, az, t (6), ComputeZYX |
Euler3DTransform |
SimilarityTransform (2-D) |
scale, angle, t (4) |
Similarity2DTransform |
SimilarityTransform (3-D) |
versor (3), t, scale (7) |
Similarity3DTransform |
AffineTransform |
M row-major, t (D² + D) |
AffineTransform |
AffineLogTransform |
log M row-major, t (D² + D) |
AffineTransform, M = expm(log M) |
AffineDTITransform |
angles, shears, scales, t (7 / 12) |
AffineTransform |
BSplineTransform, RecursiveBSplineTransform |
coefficients (D x grid) | BSplineTransform, of degree BSplineTransformSplineOrder |
The center is CenterOfRotationPoint (world coordinates). Maps that
carry ITK's own ITKTransformParameters / ITKTransformFixedParameters
are read too.
- Fixed image. Size, Index, Spacing, Origin and Direction
describe the grid transformix resamples onto. It is exposed as
fixed_geometry
(a Geometry whose
transformation maps voxels to LPS), since a transformation has no slot
for its output domain.
- Direction matrices are column-major. elastix writes Direction
and GridDirection column by column (Conversion::ToVectorOfStrings
on an itk::Matrix), the transpose of ITK's row-major fixed
parameters.
- B-spline grid. The coefficients are D images of world-space
displacements, back to back, x fastest, over the region that starts at
GridIndex: the first coefficient sits at
GridOrigin + GridDirection @ diag(GridSpacing) @ GridIndex.
Chains
A file may name an initial transform, in
InitialTransformParameterFileName (or the deprecated
InitialTransformParametersFileName), that applies before its own; that
file may name another, and so on. Each is read, and the chain is a
Sequence of their
blocks, initial transforms first (elastix computes T1(T0(x)) --
AdvancedCombinationTransform::TransformPointUseComposition). The
initial transform is also kept, as an ElastixTransform, in initial.
A relative name is looked for as elastix looks for it: from the working
directory, then from the directory of the file that names it. elastix
writes absolute paths, which break when an output folder is moved, so a
name that is found nowhere is then looked for by its base name next to
the file. initial=False reads a file's own transform alone;
initial=<file name> or initial=<transformation> supplies the initial
transform.
Writing
A file read and not modified is written back as read (the files of its
initial transforms are not rewritten). Otherwise the chain must reduce to
one transform: a block that elastix has (translation, Euler, similarity,
affine, B-spline) keeps its class and center; anything else that reduces
to an affine is written as an AffineTransform centered on the origin.
The fixed-image geometry and the other parameters of the map are kept.
Not supported
HowToCombineTransforms "Add": elastix then computesT1(x) + T0(x) - x, a sum that a chain of transformations cannot express. Such a file is refused unless read withinitial=False.- Other transforms:
DeformationFieldTransform(a field stored in a separate image),SplineKernelTransform,WeightedCombinationTransform,MultiBSplineTransformWithNormal,BSplineTransformWithDiffusion, the stack transforms (*StackTransform),ExternalTransform, and cyclic B-splines (UseCyclicTransform "true"). CenterOfRotation, the voxel-index center written by elastix < 3.402, which current elastix no longer reads either.UseDirectionCosines "false": elastix then ignored both images' directions, so the transform maps direction-less spaces that cannot be recovered without the moving image. Such a file is read as if it mapped LPS, with a warning.
B-splines outside their valid region
elastix evaluates a B-spline only where the whole support of the
spline lies inside the control-point grid, and returns the input point
unchanged elsewhere (InsideValidRegion). Here, as for ITK's own
B-splines, coefficients outside the grid are zero, so the two agree
inside the valid region and differ in the outer band of the grid.
Verified and assumed
Verified against transformix (ITK-Elastix 0.25.4): every
transform above in 2-D and 3-D where elastix has it, both Euler angle
orders, B-splines of degrees 1, 2 and 3 with a non-zero GridIndex and an
oblique GridDirection, non-symmetric fixed-image directions, two- and
three-link chains (including the deprecated key), and the TOML syntax --
see tests/data/elastix/generate_elastix_fixtures.py. The source
references are elastix's elxTransformBase.hxx (reading, initial
transforms, combination), itkAdvancedEuler3DTransform.hxx,
itkAdvancedSimilarity{2,3}DTransform.hxx,
itkAdvancedBSplineDeformableTransformBase.hxx,
itkAffineLogTransform.hxx, itkAffineDTI{2,3}DTransform.hxx and
elxAdvancedBSplineTransform.hxx.
Assumed: 4-D (and higher) affine and B-spline maps behave as their 2-D and 3-D counterparts (not tested against transformix).
Classes
ElastixParameterTransform
ElastixParameterTransform(
parameter_map: ParameterMap = Factory(dict, repr=False),
initial: Any | None = None,
)
Bases: ElastixTransform
A transformation stored in a classic elastix transform parameter file
(TransformParameters.0.txt), one (Name value ...) per line.
Attributes
PREFIXES
class-attribute
PREFIXES: tuple[str, ...] = ()
Filename prefixes required by this parser, e.g. ("y_", "iy_").
An empty tuple means "no constraint". A parser that constrains the prefix is more specific than one that does not, and wins ties.
Declaring EXTENSIONS and PREFIXES separately states the
cross-product implicitly, which is how these conventions actually
work: SPM's four names are {y_, iy_} x {.nii, .nii.gz}.
PRIORITY
class-attribute
PRIORITY: int = 0
Explicit tie-breaker, consulted only when specificity cannot decide.
Higher wins. Leave at 0 unless two parsers genuinely collide.
parameter_map
class-attribute
instance-attribute
The parameters of the file, in the order in which they were read.
Each name maps to a tuple of values -- a str for a quoted value, an
int or a float for a number -- except the transform parameters,
which are a float64 array.
initial
class-attribute
instance-attribute
initial: Any | None = None
The initial transform that the file chains to, as an
ElastixTransform, or None when it has none or when it was not
followed (initial=False).
initial_filename
property
initial_filename: str | None
The initial transform that the file names, if any.
fixed_geometry
property
fixed_geometry: Geometry | None
The geometry of the fixed image (Size, Index, Spacing,
Origin, Direction), which is the grid transformix resamples
the moving image onto. Its transformation maps voxels of that
grid to LPS millimetres. None when the file does not say.
Methods:
sniff
classmethod
sniff(
file: FileOrContentLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> type | None
On a dispatcher, identify which registered format would read
file. On a concrete format, score how confident it is that
file, in any supported form, is its own.
sniff_file
classmethod
On a dispatcher, identify which registered format would read the file (path or file-like object). On a concrete format, score how confident it is that the file is its own.
sniff_filename
classmethod
sniff_filename(
filename: FilenameLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> float
Determine if the given filename is of the type that this parser can handle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
FilenameLike
|
The filename to sniff. |
required |
error
|
bool | type[Exception]
|
If not False, raise an error if the filename cannot be sniffed. |
False
|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
float
|
Confidence that the filename is of this type, in |
sniff_fileobj
classmethod
Determine if the given file-like object is of the type that this parser can handle.
A text stream decodes as it is read, so content that is not text -- a binary file that shares an extension with a text format -- fails there. That is a "no", not a failure to sniff.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
IO
|
A file object open for reading. |
required |
error
|
bool | type[Exception]
|
If not False, raise an error if the file cannot be sniffed. |
False
|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
float
|
Confidence that the file is of this type, in |
sniff_content
classmethod
sniff_content(
content: ContentLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> type | None
On a dispatcher, identify which registered format would read the content (text or bytes). On a concrete format, score how confident it is that the content is its own.
sniff_bytes
classmethod
sniff_bytes(
content: BinaryContentLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> float
Determine if the given bytes are of the type that this parser can
handle, by decoding them to text and delegating to sniff_text.
Bytes that do not decode are not text, so they score NO.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
BinaryContentLike
|
The content to sniff. |
required |
error
|
bool | type[Exception]
|
If not False, raise an error if the content cannot be sniffed. |
False
|
**kwargs
|
Parser-specific options, plus |
{}
|
Returns:
| Type | Description |
|---|---|
float
|
Confidence that the content is of this type, in |
sniff_text
classmethod
Score the text of a file (see sniff_lines).
sniff_lines
classmethod
Score how confident the parser is that the lines are an elastix transform parameter file.
The whole map is parsed: it must name a Transform and carry its
parameters. elastix's registration parameter files share the
syntax, and name a Transform too, but carry no parameters, and
are not claimed.
sniff_line
classmethod
On a dispatcher, identify which registered format would read the line. On a concrete format, score how confident it is that the line is its own.
load
classmethod
load(other: FileOrContentLike, **kwargs) -> Self
On a dispatcher, pick the best-matching registered format and
build an instance of it from other. On a concrete format,
build an instance of this class from other, in any supported
form.
from_spec
classmethod
from_spec(spec: SourceSpec, **kwargs) -> Self
Load a structured source specification through this dispatcher.
from_file
classmethod
On a dispatcher, pick the best-matching registered format and build an instance of it from the file (path or file-like object). On a concrete format, build an instance of this class from the file.
from_filename
classmethod
from_filename(filename: FilenameLike, **kwargs) -> Self
Build an object from a filename.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
FilenameLike
|
The filename to parse. |
required |
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
obj
|
The parsed object. |
from_fileobj
classmethod
Build the object from an open file. Its name, when it has
one, is where a relative initial transform is looked for.
from_content
classmethod
from_content(content: ContentLike, **kwargs) -> Self
On a dispatcher, pick the best-matching registered format and build an instance of it from the content (text or bytes). On a concrete format, build an instance of this class from the content.
from_bytes
classmethod
from_bytes(content: BinaryContentLike, **kwargs) -> Self
Build an object from bytes, by decoding them to text and
delegating to from_text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
BinaryContentLike
|
The content to parse. |
required |
**kwargs
|
Parser-specific options, plus |
{}
|
Returns:
| Type | Description |
|---|---|
obj
|
The parsed object. |
from_text
classmethod
Build the object from the text of a file.
from_lines
classmethod
from_lines(
lines: Iterable[str],
initial: bool | FilenameLike | Transformation = True,
origin: FilenameLike | None = None,
**kwargs,
) -> Self
Build the object from the lines of an elastix parameter file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lines
|
Iterable[str]
|
The lines of the file. |
required |
initial
|
bool | FilenameLike | Transformation
|
What to do with the initial transform that the file names in
|
True
|
origin
|
FilenameLike
|
The file the lines were read from, against which a relative
initial transform is resolved. It is set by |
None
|
Raises:
| Type | Description |
|---|---|
ParserNotImplementedError
|
If the file uses a transform that is not supported, or
combines with its initial transform by addition
( |
from_line
classmethod
On a dispatcher, pick the best-matching registered format and build an instance of it from the line. On a concrete format, build an instance of this class from the line.
save
save(file: FileLike, **kwargs) -> None
Write the object to a file (path or file-like object).
This is the generic front door to the to_* family. It is named
save rather than to because to already means something else
on the data models these parsers are mixed into: Transformation.to
converts an object to another type. A writer's to was shadowed
by it on every writable transformation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
FileLike
|
The file to write to. |
required |
**kwargs
|
Parser-specific options. |
{}
|
to_file
to_file(file: FileLike, **kwargs) -> None
Write the object to a file (path or file-like object).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
FileLike
|
The file to write to. |
required |
**kwargs
|
Parser-specific options. |
{}
|
to_filename
to_filename(filename: FilenameLike, **kwargs) -> None
Write the transformation to a file.
The content is built before the file is opened, so a transformation that the format cannot hold is refused without creating or truncating the file.
to_fileobj
to_fileobj(file: IO, **kwargs) -> None
Write the object to a file-like object open for writing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
IO
|
A file object open for writing. |
required |
**kwargs
|
Parser-specific options. |
{}
|
to_bytes
to_bytes(**kwargs) -> bytes
Convert the object to bytes, by converting it to text and encoding the result.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Writer-specific options, plus |
{}
|
Returns:
| Type | Description |
|---|---|
bytes
|
The byte representation of the object. |
to_text
to_text(**kwargs) -> str
Return a text version of the file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
A text version of the file. |
to_line
to_line(**kwargs) -> str
Return a line representing the object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
A line representing the object. |
from_dict
classmethod
Create an instance of the class from a dictionary-like object.
Only keys in the dictionary that match keyword-like fields of
this class, or the keywords its constructor takes without
storing them (its InitVars, such as the matrix= of an
Affine), will be used. Other keys are ignored, but see
from_other,
which refuses them.
Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.
A key naming a field that this class fixes (a field that cannot
be passed to its constructor) is checked instead of used: a
dictionary that sets it to anything other than None or the
value of this class is refused with a ValueError.
from_instance
classmethod
Create an instance from an instance of a similar class.
The data model copies the fields both classes share, by name.
A field that a file format declares for its own use -- such as
the nibabel image and header of the NIfTI and MGH formats
-- is only copied from an object of that same format: from any
other object, a field of the same name holds something else
(a NIfTI image is no MGH image), so this class's default is
kept instead. Saving a NIfTI image to MGH, or the converse,
therefore converts the data model only, and the format-specific
state is rebuilt by the writer.
from_other
classmethod
Create an instance from a file, or from anything the data model reads.
A path (str or os.PathLike), an open file, bytes or a
structured source (SourceSpec)
is read with load: on a dispatcher such as FileBasedImage,
the best-matching registered format reads it, and on a concrete
format, that format does. Any other value is handed to the data
model's own from_other, which reads a mapping field by field,
copies an instance of a similar class, and passes anything else
to the constructor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other
|
Any
|
A file, its content, a mapping, or an instance of a similar class. |
required |
*args
|
Constructor arguments. A file is read with keyword options only. |
()
|
|
**kwargs
|
Format-specific options when reading a file, and field values otherwise. |
{}
|
Returns:
| Type | Description |
|---|---|
obj
|
The object that was built. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If positional arguments come with a file to read. |
compute
compute(
mode: ModeLike = True,
*,
simplify: SimplifyLike = "analytic",
factor: bool = False,
) -> Transformation
Compute the resulting transform of the sequence of transformations.
Assuming that mode=True:
-
If all transformations in the sequence are affine-like transformations,
compute()returns an affine-like transform. -
If the first (= rightmost) transform in the sequence is a coordinate field,
compute()returns a coordinate field. -
If the first (= rightmost) transform in the sequence is an affine-like transform, and the sequence contains at least one non-affine-like transform,
compute()returns a sequence of two transformations: -
the composition of all affine-like transformations that appear before the first non-affine-like transform in the sequence, and
- the composition of all transformations in the sequence, starting from the first non-affine-like transform in the sequence.
Parameters
mode : [list of] name or type, optional
Kinds of transformations to compose.
* If True (default): compose every kind in the sequence.
* If False: compose nothing (simplify-only).
* If a (list of) transformation type(s): compose only pairs
of transformations of these kinds.
simplify : simplify policy, default="analytic"
Whether to simplify sub-transformations prior to composition,
and how hard to try to simplify them.
* "analytic" (the default) looks at the type structure only;
* "numeric" looks at the numeric values of the transformation;
* False/"none"/None disables simplification.
factor : bool, default=False
Whether to rewrite the sequence into its axis-group normal
form [grid?, F_1..F_m, Pi_perm?]: a leading grid (if any),
one axis-preserving subspace factor per group of axes that
transform together, and a trailing reindex permutation. Off
by default, so the result is byte-for-byte the plain
compute() result. Nothing is ever composed across groups;
mode still decides whether the restricted pieces inside a
group compose. A chain that creates or drops axes is left
unfactored. With mode=False nothing is computed, so
factor has nothing to act on and is ignored.
simplify
simplify(
policy: SimplifyLike = "analytic",
*,
compute: ModeLike | bool | None = False,
) -> Self
Simplify this transformation under a per-kind policy.
Convenience sugar for
compute: t.simplify(policy, compute=mode) is
t.compute(mode, simplify=policy).
By default simplify() does no computation at all: compute=False
maps to mode=False, which composes nothing (no matrices multiplied,
no fields sampled, no lazy inverse materialized). It only downcasts
each leaf under policy (analytic by default). Pass an explicit
compute=<mode> to also compose that kind.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
policy
|
simplify policy
|
The simplify policy, in the grammar |
"analytic"
|
compute
|
[list of] name or type
|
The compose mode. The default, |
False
|
square
square(compute: bool = False, **kwargs) -> Transformation
Return the square of this transformation, self @ self.
The square is the sequence [self, self], which composes when it
is computed. It is defined for a transformation that maps a space
to itself.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
compute
|
bool
|
Whether to compute the result now rather than return it lazily. |
False
|
**kwargs
|
Passed to |
{}
|
Raises:
| Type | Description |
|---|---|
DomainError
|
If the transformation does not map a space to itself. |
sqrt
sqrt(compute: bool = False, **kwargs) -> Transformation
Return the principal square root of this chain.
The chain is first simplified, which costs nothing. A chain
[P, *X, P^-1], where P^-1 is the lazy inverse of P, or both
are affines whose product is exactly the identity, is a change of
coordinates around X, and its square root is
[P, sqrt(X), P^-1]: a field stored in voxels between a
world-to-voxel affine and its lazy inverse keeps that form. Any
other chain is composed now, and the square root of the
transformation it composes to is returned.
Raises:
| Type | Description |
|---|---|
DomainError
|
If the chain does not map a space to itself, or if the square root of what it reduces to is not defined. |
NotImplementedError
|
If the chain does not compose to a single transformation. |
to
to(
cls: Type[Transformation] | None = None, **kwargs
) -> Transformation
Convert this chain to a different type or encoding.
See Transformation.to. A chain has no tangent of its own -- the tangent of a
composition is not the sum of the tangents -- so log= re-encodes
the transformation it reduces to, and anything else is refused
before it is computed:
- a chain that simplifies to one transformation is that one;
- a change of coordinates
[P, *X, P^-1](seesqrt) keeps its ends, and re-encodesX: the flow of a velocity commutes with the conjugation, so this is exact. A velocity read between a world-to-voxel affine and its inverse (|svf) is turned into its displacement that way; - a chain of affines is composed, which is cheap and exact.
Any other chain -- one with a field, between ends that do not undo
each other -- raises ConversionError.
transformations
transformations() -> tuple[Transformation, ...]
The chain of transformations, in the order they are applied: the initial transform's (flattened), then the file's own block.
elastix composes a transform with its initial transform as
T(x) = T1(T0(x)) (AdvancedCombinationTransform::
TransformPointUseComposition): the initial transform applies
first. Assigning to it overrides the decoded chain, and is what
the writer then encodes.
to_map
The parameter map that encodes this transformation.
- A transformation read from a file, and not modified, is written as it was read, initial transform file name included. The initial transform itself is not written: it is its own file.
- Otherwise the chain must be a single transformation: an elastix
or ITK block (a translation, an Euler, a similarity, an affine
or a B-spline), or anything that reduces to an affine, which is
written as an
AffineTransformcentered on the origin. The fixed-image geometry and the other non-transform parameters ofparameter_mapare kept. It has no initial transform.
Raises:
| Type | Description |
|---|---|
UnrepresentableTransformationError
|
If the chain cannot be written as a single elastix transform. |
ElastixTomlTransform
ElastixTomlTransform(
parameter_map: ParameterMap = Factory(dict, repr=False),
initial: Any | None = None,
)
Bases: ElastixTransform
A transformation stored in an elastix TOML transform parameter file
(TransformParameters.0.toml), one Name = value per line.
Attributes
PREFIXES
class-attribute
PREFIXES: tuple[str, ...] = ()
Filename prefixes required by this parser, e.g. ("y_", "iy_").
An empty tuple means "no constraint". A parser that constrains the prefix is more specific than one that does not, and wins ties.
Declaring EXTENSIONS and PREFIXES separately states the
cross-product implicitly, which is how these conventions actually
work: SPM's four names are {y_, iy_} x {.nii, .nii.gz}.
PRIORITY
class-attribute
PRIORITY: int = 0
Explicit tie-breaker, consulted only when specificity cannot decide.
Higher wins. Leave at 0 unless two parsers genuinely collide.
parameter_map
class-attribute
instance-attribute
The parameters of the file, in the order in which they were read.
Each name maps to a tuple of values -- a str for a quoted value, an
int or a float for a number -- except the transform parameters,
which are a float64 array.
initial
class-attribute
instance-attribute
initial: Any | None = None
The initial transform that the file chains to, as an
ElastixTransform, or None when it has none or when it was not
followed (initial=False).
initial_filename
property
initial_filename: str | None
The initial transform that the file names, if any.
fixed_geometry
property
fixed_geometry: Geometry | None
The geometry of the fixed image (Size, Index, Spacing,
Origin, Direction), which is the grid transformix resamples
the moving image onto. Its transformation maps voxels of that
grid to LPS millimetres. None when the file does not say.
Methods:
sniff
classmethod
sniff(
file: FileOrContentLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> type | None
On a dispatcher, identify which registered format would read
file. On a concrete format, score how confident it is that
file, in any supported form, is its own.
sniff_file
classmethod
On a dispatcher, identify which registered format would read the file (path or file-like object). On a concrete format, score how confident it is that the file is its own.
sniff_filename
classmethod
sniff_filename(
filename: FilenameLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> float
Determine if the given filename is of the type that this parser can handle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
FilenameLike
|
The filename to sniff. |
required |
error
|
bool | type[Exception]
|
If not False, raise an error if the filename cannot be sniffed. |
False
|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
float
|
Confidence that the filename is of this type, in |
sniff_fileobj
classmethod
Determine if the given file-like object is of the type that this parser can handle.
A text stream decodes as it is read, so content that is not text -- a binary file that shares an extension with a text format -- fails there. That is a "no", not a failure to sniff.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
IO
|
A file object open for reading. |
required |
error
|
bool | type[Exception]
|
If not False, raise an error if the file cannot be sniffed. |
False
|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
float
|
Confidence that the file is of this type, in |
sniff_content
classmethod
sniff_content(
content: ContentLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> type | None
On a dispatcher, identify which registered format would read the content (text or bytes). On a concrete format, score how confident it is that the content is its own.
sniff_bytes
classmethod
sniff_bytes(
content: BinaryContentLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> float
Determine if the given bytes are of the type that this parser can
handle, by decoding them to text and delegating to sniff_text.
Bytes that do not decode are not text, so they score NO.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
BinaryContentLike
|
The content to sniff. |
required |
error
|
bool | type[Exception]
|
If not False, raise an error if the content cannot be sniffed. |
False
|
**kwargs
|
Parser-specific options, plus |
{}
|
Returns:
| Type | Description |
|---|---|
float
|
Confidence that the content is of this type, in |
sniff_text
classmethod
Score the text of a file (see sniff_lines).
sniff_lines
classmethod
Score how confident the parser is that the lines are an elastix transform parameter file.
The whole map is parsed: it must name a Transform and carry its
parameters. elastix's registration parameter files share the
syntax, and name a Transform too, but carry no parameters, and
are not claimed.
sniff_line
classmethod
On a dispatcher, identify which registered format would read the line. On a concrete format, score how confident it is that the line is its own.
load
classmethod
load(other: FileOrContentLike, **kwargs) -> Self
On a dispatcher, pick the best-matching registered format and
build an instance of it from other. On a concrete format,
build an instance of this class from other, in any supported
form.
from_spec
classmethod
from_spec(spec: SourceSpec, **kwargs) -> Self
Load a structured source specification through this dispatcher.
from_file
classmethod
On a dispatcher, pick the best-matching registered format and build an instance of it from the file (path or file-like object). On a concrete format, build an instance of this class from the file.
from_filename
classmethod
from_filename(filename: FilenameLike, **kwargs) -> Self
Build an object from a filename.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
FilenameLike
|
The filename to parse. |
required |
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
obj
|
The parsed object. |
from_fileobj
classmethod
Build the object from an open file. Its name, when it has
one, is where a relative initial transform is looked for.
from_content
classmethod
from_content(content: ContentLike, **kwargs) -> Self
On a dispatcher, pick the best-matching registered format and build an instance of it from the content (text or bytes). On a concrete format, build an instance of this class from the content.
from_bytes
classmethod
from_bytes(content: BinaryContentLike, **kwargs) -> Self
Build an object from bytes, by decoding them to text and
delegating to from_text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
BinaryContentLike
|
The content to parse. |
required |
**kwargs
|
Parser-specific options, plus |
{}
|
Returns:
| Type | Description |
|---|---|
obj
|
The parsed object. |
from_text
classmethod
Build the object from the text of a file.
from_lines
classmethod
from_lines(
lines: Iterable[str],
initial: bool | FilenameLike | Transformation = True,
origin: FilenameLike | None = None,
**kwargs,
) -> Self
Build the object from the lines of an elastix parameter file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lines
|
Iterable[str]
|
The lines of the file. |
required |
initial
|
bool | FilenameLike | Transformation
|
What to do with the initial transform that the file names in
|
True
|
origin
|
FilenameLike
|
The file the lines were read from, against which a relative
initial transform is resolved. It is set by |
None
|
Raises:
| Type | Description |
|---|---|
ParserNotImplementedError
|
If the file uses a transform that is not supported, or
combines with its initial transform by addition
( |
from_line
classmethod
On a dispatcher, pick the best-matching registered format and build an instance of it from the line. On a concrete format, build an instance of this class from the line.
save
save(file: FileLike, **kwargs) -> None
Write the object to a file (path or file-like object).
This is the generic front door to the to_* family. It is named
save rather than to because to already means something else
on the data models these parsers are mixed into: Transformation.to
converts an object to another type. A writer's to was shadowed
by it on every writable transformation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
FileLike
|
The file to write to. |
required |
**kwargs
|
Parser-specific options. |
{}
|
to_file
to_file(file: FileLike, **kwargs) -> None
Write the object to a file (path or file-like object).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
FileLike
|
The file to write to. |
required |
**kwargs
|
Parser-specific options. |
{}
|
to_filename
to_filename(filename: FilenameLike, **kwargs) -> None
Write the transformation to a file.
The content is built before the file is opened, so a transformation that the format cannot hold is refused without creating or truncating the file.
to_fileobj
to_fileobj(file: IO, **kwargs) -> None
Write the object to a file-like object open for writing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
IO
|
A file object open for writing. |
required |
**kwargs
|
Parser-specific options. |
{}
|
to_bytes
to_bytes(**kwargs) -> bytes
Convert the object to bytes, by converting it to text and encoding the result.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Writer-specific options, plus |
{}
|
Returns:
| Type | Description |
|---|---|
bytes
|
The byte representation of the object. |
to_text
to_text(**kwargs) -> str
Return a text version of the file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
A text version of the file. |
to_line
to_line(**kwargs) -> str
Return a line representing the object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
A line representing the object. |
from_dict
classmethod
Create an instance of the class from a dictionary-like object.
Only keys in the dictionary that match keyword-like fields of
this class, or the keywords its constructor takes without
storing them (its InitVars, such as the matrix= of an
Affine), will be used. Other keys are ignored, but see
from_other,
which refuses them.
Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.
A key naming a field that this class fixes (a field that cannot
be passed to its constructor) is checked instead of used: a
dictionary that sets it to anything other than None or the
value of this class is refused with a ValueError.
from_instance
classmethod
Create an instance from an instance of a similar class.
The data model copies the fields both classes share, by name.
A field that a file format declares for its own use -- such as
the nibabel image and header of the NIfTI and MGH formats
-- is only copied from an object of that same format: from any
other object, a field of the same name holds something else
(a NIfTI image is no MGH image), so this class's default is
kept instead. Saving a NIfTI image to MGH, or the converse,
therefore converts the data model only, and the format-specific
state is rebuilt by the writer.
from_other
classmethod
Create an instance from a file, or from anything the data model reads.
A path (str or os.PathLike), an open file, bytes or a
structured source (SourceSpec)
is read with load: on a dispatcher such as FileBasedImage,
the best-matching registered format reads it, and on a concrete
format, that format does. Any other value is handed to the data
model's own from_other, which reads a mapping field by field,
copies an instance of a similar class, and passes anything else
to the constructor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other
|
Any
|
A file, its content, a mapping, or an instance of a similar class. |
required |
*args
|
Constructor arguments. A file is read with keyword options only. |
()
|
|
**kwargs
|
Format-specific options when reading a file, and field values otherwise. |
{}
|
Returns:
| Type | Description |
|---|---|
obj
|
The object that was built. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If positional arguments come with a file to read. |
compute
compute(
mode: ModeLike = True,
*,
simplify: SimplifyLike = "analytic",
factor: bool = False,
) -> Transformation
Compute the resulting transform of the sequence of transformations.
Assuming that mode=True:
-
If all transformations in the sequence are affine-like transformations,
compute()returns an affine-like transform. -
If the first (= rightmost) transform in the sequence is a coordinate field,
compute()returns a coordinate field. -
If the first (= rightmost) transform in the sequence is an affine-like transform, and the sequence contains at least one non-affine-like transform,
compute()returns a sequence of two transformations: -
the composition of all affine-like transformations that appear before the first non-affine-like transform in the sequence, and
- the composition of all transformations in the sequence, starting from the first non-affine-like transform in the sequence.
Parameters
mode : [list of] name or type, optional
Kinds of transformations to compose.
* If True (default): compose every kind in the sequence.
* If False: compose nothing (simplify-only).
* If a (list of) transformation type(s): compose only pairs
of transformations of these kinds.
simplify : simplify policy, default="analytic"
Whether to simplify sub-transformations prior to composition,
and how hard to try to simplify them.
* "analytic" (the default) looks at the type structure only;
* "numeric" looks at the numeric values of the transformation;
* False/"none"/None disables simplification.
factor : bool, default=False
Whether to rewrite the sequence into its axis-group normal
form [grid?, F_1..F_m, Pi_perm?]: a leading grid (if any),
one axis-preserving subspace factor per group of axes that
transform together, and a trailing reindex permutation. Off
by default, so the result is byte-for-byte the plain
compute() result. Nothing is ever composed across groups;
mode still decides whether the restricted pieces inside a
group compose. A chain that creates or drops axes is left
unfactored. With mode=False nothing is computed, so
factor has nothing to act on and is ignored.
simplify
simplify(
policy: SimplifyLike = "analytic",
*,
compute: ModeLike | bool | None = False,
) -> Self
Simplify this transformation under a per-kind policy.
Convenience sugar for
compute: t.simplify(policy, compute=mode) is
t.compute(mode, simplify=policy).
By default simplify() does no computation at all: compute=False
maps to mode=False, which composes nothing (no matrices multiplied,
no fields sampled, no lazy inverse materialized). It only downcasts
each leaf under policy (analytic by default). Pass an explicit
compute=<mode> to also compose that kind.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
policy
|
simplify policy
|
The simplify policy, in the grammar |
"analytic"
|
compute
|
[list of] name or type
|
The compose mode. The default, |
False
|
square
square(compute: bool = False, **kwargs) -> Transformation
Return the square of this transformation, self @ self.
The square is the sequence [self, self], which composes when it
is computed. It is defined for a transformation that maps a space
to itself.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
compute
|
bool
|
Whether to compute the result now rather than return it lazily. |
False
|
**kwargs
|
Passed to |
{}
|
Raises:
| Type | Description |
|---|---|
DomainError
|
If the transformation does not map a space to itself. |
sqrt
sqrt(compute: bool = False, **kwargs) -> Transformation
Return the principal square root of this chain.
The chain is first simplified, which costs nothing. A chain
[P, *X, P^-1], where P^-1 is the lazy inverse of P, or both
are affines whose product is exactly the identity, is a change of
coordinates around X, and its square root is
[P, sqrt(X), P^-1]: a field stored in voxels between a
world-to-voxel affine and its lazy inverse keeps that form. Any
other chain is composed now, and the square root of the
transformation it composes to is returned.
Raises:
| Type | Description |
|---|---|
DomainError
|
If the chain does not map a space to itself, or if the square root of what it reduces to is not defined. |
NotImplementedError
|
If the chain does not compose to a single transformation. |
to
to(
cls: Type[Transformation] | None = None, **kwargs
) -> Transformation
Convert this chain to a different type or encoding.
See Transformation.to. A chain has no tangent of its own -- the tangent of a
composition is not the sum of the tangents -- so log= re-encodes
the transformation it reduces to, and anything else is refused
before it is computed:
- a chain that simplifies to one transformation is that one;
- a change of coordinates
[P, *X, P^-1](seesqrt) keeps its ends, and re-encodesX: the flow of a velocity commutes with the conjugation, so this is exact. A velocity read between a world-to-voxel affine and its inverse (|svf) is turned into its displacement that way; - a chain of affines is composed, which is cheap and exact.
Any other chain -- one with a field, between ends that do not undo
each other -- raises ConversionError.
transformations
transformations() -> tuple[Transformation, ...]
The chain of transformations, in the order they are applied: the initial transform's (flattened), then the file's own block.
elastix composes a transform with its initial transform as
T(x) = T1(T0(x)) (AdvancedCombinationTransform::
TransformPointUseComposition): the initial transform applies
first. Assigning to it overrides the decoded chain, and is what
the writer then encodes.
to_map
The parameter map that encodes this transformation.
- A transformation read from a file, and not modified, is written as it was read, initial transform file name included. The initial transform itself is not written: it is its own file.
- Otherwise the chain must be a single transformation: an elastix
or ITK block (a translation, an Euler, a similarity, an affine
or a B-spline), or anything that reduces to an affine, which is
written as an
AffineTransformcentered on the origin. The fixed-image geometry and the other non-transform parameters ofparameter_mapare kept. It has no initial transform.
Raises:
| Type | Description |
|---|---|
UnrepresentableTransformationError
|
If the chain cannot be written as a single elastix transform. |
ElastixTransform
magic
ElastixTransform(
parameter_map: ParameterMap = Factory(dict, repr=False),
initial: Any | None = None,
)
Bases: TextFileParserWriter, Sequence, WritableFileBasedTransformation
A transformation stored in an elastix transform parameter file.
It is the
Sequence that maps
fixed-image LPS coordinates to moving-image LPS coordinates (the
direction in which transformix pulls the moving image onto the fixed
grid): the blocks of the initial transforms that the file chains to,
first, then the block of the file's own transform. Every block is an
ITK block (see brainhops.io.transformations.elastix).
The raw parameter map is kept in parameter_map, and the initial
transform -- itself an ElastixTransform -- in initial.
Abstract: it is not decorated with @register_format. Its two
syntaxes, ElastixParameterTransform (.txt) and
ElastixTomlTransform (.toml), register themselves.
Attributes
EXTENSIONS
class-attribute
EXTENSIONS: tuple[str, ...] = ()
File extensions handled by this parser, e.g. (".nii", ".nii.gz").
Used as a first, cheap dispatch pass. When several parsers match,
the longest matching extension wins, so a parser declaring
".nii.gz" takes precedence over one declaring ".gz".
PREFIXES
class-attribute
PREFIXES: tuple[str, ...] = ()
Filename prefixes required by this parser, e.g. ("y_", "iy_").
An empty tuple means "no constraint". A parser that constrains the prefix is more specific than one that does not, and wins ties.
Declaring EXTENSIONS and PREFIXES separately states the
cross-product implicitly, which is how these conventions actually
work: SPM's four names are {y_, iy_} x {.nii, .nii.gz}.
PRIORITY
class-attribute
PRIORITY: int = 0
Explicit tie-breaker, consulted only when specificity cannot decide.
Higher wins. Leave at 0 unless two parsers genuinely collide.
parameter_map
class-attribute
instance-attribute
The parameters of the file, in the order in which they were read.
Each name maps to a tuple of values -- a str for a quoted value, an
int or a float for a number -- except the transform parameters,
which are a float64 array.
initial
class-attribute
instance-attribute
initial: Any | None = None
The initial transform that the file chains to, as an
ElastixTransform, or None when it has none or when it was not
followed (initial=False).
initial_filename
property
initial_filename: str | None
The initial transform that the file names, if any.
fixed_geometry
property
fixed_geometry: Geometry | None
The geometry of the fixed image (Size, Index, Spacing,
Origin, Direction), which is the grid transformix resamples
the moving image onto. Its transformation maps voxels of that
grid to LPS millimetres. None when the file does not say.
Methods:
sniff
classmethod
sniff(
file: FileOrContentLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> type | None
On a dispatcher, identify which registered format would read
file. On a concrete format, score how confident it is that
file, in any supported form, is its own.
sniff_file
classmethod
On a dispatcher, identify which registered format would read the file (path or file-like object). On a concrete format, score how confident it is that the file is its own.
sniff_filename
classmethod
sniff_filename(
filename: FilenameLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> float
Determine if the given filename is of the type that this parser can handle.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
FilenameLike
|
The filename to sniff. |
required |
error
|
bool | type[Exception]
|
If not False, raise an error if the filename cannot be sniffed. |
False
|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
float
|
Confidence that the filename is of this type, in |
sniff_fileobj
classmethod
Determine if the given file-like object is of the type that this parser can handle.
A text stream decodes as it is read, so content that is not text -- a binary file that shares an extension with a text format -- fails there. That is a "no", not a failure to sniff.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
IO
|
A file object open for reading. |
required |
error
|
bool | type[Exception]
|
If not False, raise an error if the file cannot be sniffed. |
False
|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
float
|
Confidence that the file is of this type, in |
sniff_content
classmethod
sniff_content(
content: ContentLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> type | None
On a dispatcher, identify which registered format would read the content (text or bytes). On a concrete format, score how confident it is that the content is its own.
sniff_bytes
classmethod
sniff_bytes(
content: BinaryContentLike,
error: bool | Type[Exception] = False,
**kwargs,
) -> float
Determine if the given bytes are of the type that this parser can
handle, by decoding them to text and delegating to sniff_text.
Bytes that do not decode are not text, so they score NO.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
BinaryContentLike
|
The content to sniff. |
required |
error
|
bool | type[Exception]
|
If not False, raise an error if the content cannot be sniffed. |
False
|
**kwargs
|
Parser-specific options, plus |
{}
|
Returns:
| Type | Description |
|---|---|
float
|
Confidence that the content is of this type, in |
sniff_line
classmethod
On a dispatcher, identify which registered format would read the line. On a concrete format, score how confident it is that the line is its own.
load
classmethod
load(other: FileOrContentLike, **kwargs) -> Self
On a dispatcher, pick the best-matching registered format and
build an instance of it from other. On a concrete format,
build an instance of this class from other, in any supported
form.
from_spec
classmethod
from_spec(spec: SourceSpec, **kwargs) -> Self
Load a structured source specification through this dispatcher.
from_file
classmethod
On a dispatcher, pick the best-matching registered format and build an instance of it from the file (path or file-like object). On a concrete format, build an instance of this class from the file.
from_filename
classmethod
from_filename(filename: FilenameLike, **kwargs) -> Self
Build an object from a filename.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
filename
|
FilenameLike
|
The filename to parse. |
required |
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
obj
|
The parsed object. |
from_content
classmethod
from_content(content: ContentLike, **kwargs) -> Self
On a dispatcher, pick the best-matching registered format and build an instance of it from the content (text or bytes). On a concrete format, build an instance of this class from the content.
from_bytes
classmethod
from_bytes(content: BinaryContentLike, **kwargs) -> Self
Build an object from bytes, by decoding them to text and
delegating to from_text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
content
|
BinaryContentLike
|
The content to parse. |
required |
**kwargs
|
Parser-specific options, plus |
{}
|
Returns:
| Type | Description |
|---|---|
obj
|
The parsed object. |
from_line
classmethod
On a dispatcher, pick the best-matching registered format and build an instance of it from the line. On a concrete format, build an instance of this class from the line.
save
save(file: FileLike, **kwargs) -> None
Write the object to a file (path or file-like object).
This is the generic front door to the to_* family. It is named
save rather than to because to already means something else
on the data models these parsers are mixed into: Transformation.to
converts an object to another type. A writer's to was shadowed
by it on every writable transformation.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
FileLike
|
The file to write to. |
required |
**kwargs
|
Parser-specific options. |
{}
|
to_file
to_file(file: FileLike, **kwargs) -> None
Write the object to a file (path or file-like object).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
FileLike
|
The file to write to. |
required |
**kwargs
|
Parser-specific options. |
{}
|
to_fileobj
to_fileobj(file: IO, **kwargs) -> None
Write the object to a file-like object open for writing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
file
|
IO
|
A file object open for writing. |
required |
**kwargs
|
Parser-specific options. |
{}
|
to_bytes
to_bytes(**kwargs) -> bytes
Convert the object to bytes, by converting it to text and encoding the result.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Writer-specific options, plus |
{}
|
Returns:
| Type | Description |
|---|---|
bytes
|
The byte representation of the object. |
to_text
to_text(**kwargs) -> str
Return a text version of the file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
A text version of the file. |
to_line
to_line(**kwargs) -> str
Return a line representing the object.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**kwargs
|
Parser-specific options. |
{}
|
Returns:
| Type | Description |
|---|---|
str
|
A line representing the object. |
from_dict
classmethod
Create an instance of the class from a dictionary-like object.
Only keys in the dictionary that match keyword-like fields of
this class, or the keywords its constructor takes without
storing them (its InitVars, such as the matrix= of an
Affine), will be used. Other keys are ignored, but see
from_other,
which refuses them.
Additional positional and/or keyword arguments can be provided, and will take precedence over the values in the dictionary.
A key naming a field that this class fixes (a field that cannot
be passed to its constructor) is checked instead of used: a
dictionary that sets it to anything other than None or the
value of this class is refused with a ValueError.
from_instance
classmethod
Create an instance from an instance of a similar class.
The data model copies the fields both classes share, by name.
A field that a file format declares for its own use -- such as
the nibabel image and header of the NIfTI and MGH formats
-- is only copied from an object of that same format: from any
other object, a field of the same name holds something else
(a NIfTI image is no MGH image), so this class's default is
kept instead. Saving a NIfTI image to MGH, or the converse,
therefore converts the data model only, and the format-specific
state is rebuilt by the writer.
from_other
classmethod
Create an instance from a file, or from anything the data model reads.
A path (str or os.PathLike), an open file, bytes or a
structured source (SourceSpec)
is read with load: on a dispatcher such as FileBasedImage,
the best-matching registered format reads it, and on a concrete
format, that format does. Any other value is handed to the data
model's own from_other, which reads a mapping field by field,
copies an instance of a similar class, and passes anything else
to the constructor.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
other
|
Any
|
A file, its content, a mapping, or an instance of a similar class. |
required |
*args
|
Constructor arguments. A file is read with keyword options only. |
()
|
|
**kwargs
|
Format-specific options when reading a file, and field values otherwise. |
{}
|
Returns:
| Type | Description |
|---|---|
obj
|
The object that was built. |
Raises:
| Type | Description |
|---|---|
TypeError
|
If positional arguments come with a file to read. |
compute
compute(
mode: ModeLike = True,
*,
simplify: SimplifyLike = "analytic",
factor: bool = False,
) -> Transformation
Compute the resulting transform of the sequence of transformations.
Assuming that mode=True:
-
If all transformations in the sequence are affine-like transformations,
compute()returns an affine-like transform. -
If the first (= rightmost) transform in the sequence is a coordinate field,
compute()returns a coordinate field. -
If the first (= rightmost) transform in the sequence is an affine-like transform, and the sequence contains at least one non-affine-like transform,
compute()returns a sequence of two transformations: -
the composition of all affine-like transformations that appear before the first non-affine-like transform in the sequence, and
- the composition of all transformations in the sequence, starting from the first non-affine-like transform in the sequence.
Parameters
mode : [list of] name or type, optional
Kinds of transformations to compose.
* If True (default): compose every kind in the sequence.
* If False: compose nothing (simplify-only).
* If a (list of) transformation type(s): compose only pairs
of transformations of these kinds.
simplify : simplify policy, default="analytic"
Whether to simplify sub-transformations prior to composition,
and how hard to try to simplify them.
* "analytic" (the default) looks at the type structure only;
* "numeric" looks at the numeric values of the transformation;
* False/"none"/None disables simplification.
factor : bool, default=False
Whether to rewrite the sequence into its axis-group normal
form [grid?, F_1..F_m, Pi_perm?]: a leading grid (if any),
one axis-preserving subspace factor per group of axes that
transform together, and a trailing reindex permutation. Off
by default, so the result is byte-for-byte the plain
compute() result. Nothing is ever composed across groups;
mode still decides whether the restricted pieces inside a
group compose. A chain that creates or drops axes is left
unfactored. With mode=False nothing is computed, so
factor has nothing to act on and is ignored.
simplify
simplify(
policy: SimplifyLike = "analytic",
*,
compute: ModeLike | bool | None = False,
) -> Self
Simplify this transformation under a per-kind policy.
Convenience sugar for
compute: t.simplify(policy, compute=mode) is
t.compute(mode, simplify=policy).
By default simplify() does no computation at all: compute=False
maps to mode=False, which composes nothing (no matrices multiplied,
no fields sampled, no lazy inverse materialized). It only downcasts
each leaf under policy (analytic by default). Pass an explicit
compute=<mode> to also compose that kind.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
policy
|
simplify policy
|
The simplify policy, in the grammar |
"analytic"
|
compute
|
[list of] name or type
|
The compose mode. The default, |
False
|
square
square(compute: bool = False, **kwargs) -> Transformation
Return the square of this transformation, self @ self.
The square is the sequence [self, self], which composes when it
is computed. It is defined for a transformation that maps a space
to itself.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
compute
|
bool
|
Whether to compute the result now rather than return it lazily. |
False
|
**kwargs
|
Passed to |
{}
|
Raises:
| Type | Description |
|---|---|
DomainError
|
If the transformation does not map a space to itself. |
sqrt
sqrt(compute: bool = False, **kwargs) -> Transformation
Return the principal square root of this chain.
The chain is first simplified, which costs nothing. A chain
[P, *X, P^-1], where P^-1 is the lazy inverse of P, or both
are affines whose product is exactly the identity, is a change of
coordinates around X, and its square root is
[P, sqrt(X), P^-1]: a field stored in voxels between a
world-to-voxel affine and its lazy inverse keeps that form. Any
other chain is composed now, and the square root of the
transformation it composes to is returned.
Raises:
| Type | Description |
|---|---|
DomainError
|
If the chain does not map a space to itself, or if the square root of what it reduces to is not defined. |
NotImplementedError
|
If the chain does not compose to a single transformation. |
to
to(
cls: Type[Transformation] | None = None, **kwargs
) -> Transformation
Convert this chain to a different type or encoding.
See Transformation.to. A chain has no tangent of its own -- the tangent of a
composition is not the sum of the tangents -- so log= re-encodes
the transformation it reduces to, and anything else is refused
before it is computed:
- a chain that simplifies to one transformation is that one;
- a change of coordinates
[P, *X, P^-1](seesqrt) keeps its ends, and re-encodesX: the flow of a velocity commutes with the conjugation, so this is exact. A velocity read between a world-to-voxel affine and its inverse (|svf) is turned into its displacement that way; - a chain of affines is composed, which is cheap and exact.
Any other chain -- one with a field, between ends that do not undo
each other -- raises ConversionError.
sniff_lines
classmethod
Score how confident the parser is that the lines are an elastix transform parameter file.
The whole map is parsed: it must name a Transform and carry its
parameters. elastix's registration parameter files share the
syntax, and name a Transform too, but carry no parameters, and
are not claimed.
sniff_text
classmethod
Score the text of a file (see sniff_lines).
from_fileobj
classmethod
Build the object from an open file. Its name, when it has
one, is where a relative initial transform is looked for.
from_text
classmethod
Build the object from the text of a file.
from_lines
classmethod
from_lines(
lines: Iterable[str],
initial: bool | FilenameLike | Transformation = True,
origin: FilenameLike | None = None,
**kwargs,
) -> Self
Build the object from the lines of an elastix parameter file.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
lines
|
Iterable[str]
|
The lines of the file. |
required |
initial
|
bool | FilenameLike | Transformation
|
What to do with the initial transform that the file names in
|
True
|
origin
|
FilenameLike
|
The file the lines were read from, against which a relative
initial transform is resolved. It is set by |
None
|
Raises:
| Type | Description |
|---|---|
ParserNotImplementedError
|
If the file uses a transform that is not supported, or
combines with its initial transform by addition
( |
transformations
transformations() -> tuple[Transformation, ...]
The chain of transformations, in the order they are applied: the initial transform's (flattened), then the file's own block.
elastix composes a transform with its initial transform as
T(x) = T1(T0(x)) (AdvancedCombinationTransform::
TransformPointUseComposition): the initial transform applies
first. Assigning to it overrides the decoded chain, and is what
the writer then encodes.
to_filename
to_filename(filename: FilenameLike, **kwargs) -> None
Write the transformation to a file.
The content is built before the file is opened, so a transformation that the format cannot hold is refused without creating or truncating the file.
to_map
The parameter map that encodes this transformation.
- A transformation read from a file, and not modified, is written as it was read, initial transform file name included. The initial transform itself is not written: it is its own file.
- Otherwise the chain must be a single transformation: an elastix
or ITK block (a translation, an Euler, a similarity, an affine
or a B-spline), or anything that reduces to an affine, which is
written as an
AffineTransformcentered on the origin. The fixed-image geometry and the other non-transform parameters ofparameter_mapare kept. It has no initial transform.
Raises:
| Type | Description |
|---|---|
UnrepresentableTransformationError
|
If the chain cannot be written as a single elastix transform. |