88### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ### ##
99"""Common interface for transforms."""
1010from collections .abc import Iterable
11+ import numpy as np
1112
1213from .base import (
1314 TransformBase ,
@@ -74,8 +75,8 @@ def transforms(self):
7475 @transforms .setter
7576 def transforms (self , value ):
7677 self ._transforms = _as_chain (value )
77- if self .transforms [- 1 ].reference :
78- self .reference = self .transforms [- 1 ].reference
78+ if self .transforms [0 ].reference :
79+ self .reference = self .transforms [0 ].reference
7980
8081 def append (self , x ):
8182 """
@@ -131,19 +132,56 @@ def map(self, x, inverse=False):
131132 raise TransformError ("Cannot apply an empty transforms chain." )
132133
133134 transforms = self .transforms
134- if not inverse :
135- transforms = self .transforms [:: - 1 ]
135+ if inverse :
136+ transforms = list ( reversed ( self .transforms ))
136137
137138 for xfm in transforms :
138- x = xfm (x , inverse = inverse )
139+ x = xfm . map (x , inverse = inverse )
139140
140141 return x
141142
142- def asaffine (self ):
143- """Combine a succession of linear transforms into one."""
144- retval = self .transforms [- 1 ]
145- for xfm in self .transforms [:- 1 ][::- 1 ]:
146- retval @= xfm
143+ def asaffine (self , indices = None ):
144+ """
145+ Combine a succession of linear transforms into one.
146+
147+ Example
148+ ------
149+ >>> chain = TransformChain(transforms=[
150+ ... Affine.from_matvec(vec=(2, -10, 3)),
151+ ... Affine.from_matvec(vec=(-2, 10, -3)),
152+ ... ])
153+ >>> chain.asaffine()
154+ array([[1., 0., 0., 0.],
155+ [0., 1., 0., 0.],
156+ [0., 0., 1., 0.],
157+ [0., 0., 0., 1.]])
158+
159+ >>> chain = TransformChain(transforms=[
160+ ... Affine.from_matvec(vec=(1, 2, 3)),
161+ ... Affine.from_matvec(mat=[[0, 1, 0], [0, 0, 1], [1, 0, 0]]),
162+ ... ])
163+ >>> chain.asaffine()
164+ array([[0., 1., 0., 2.],
165+ [0., 0., 1., 3.],
166+ [1., 0., 0., 1.],
167+ [0., 0., 0., 1.]])
168+
169+ >>> np.allclose(
170+ ... chain.map((4, -2, 1)),
171+ ... chain.asaffine().map((4, -2, 1)),
172+ ... )
173+ True
174+
175+ Parameters
176+ ----------
177+ indices : :obj:`numpy.array_like`
178+ The indices of the values to extract.
179+
180+ """
181+ affines = self .transforms if indices is None else np .take (self .transforms , indices )
182+ retval = affines [0 ]
183+ for xfm in affines [1 :]:
184+ retval = xfm @ retval
147185 return retval
148186
149187 @classmethod
@@ -157,9 +195,9 @@ def from_filename(cls, filename, fmt="X5", reference=None, moving=None):
157195 xforms = itk .ITKCompositeH5 .from_filename (filename )
158196 for xfmobj in xforms :
159197 if isinstance (xfmobj , itk .ITKLinearTransform ):
160- retval .append ( Affine (xfmobj .to_ras (), reference = reference ))
198+ retval .insert ( 0 , Affine (xfmobj .to_ras (), reference = reference ))
161199 else :
162- retval .append ( DisplacementsFieldTransform (xfmobj ))
200+ retval .insert ( 0 , DisplacementsFieldTransform (xfmobj ))
163201
164202 return TransformChain (retval )
165203
0 commit comments