@@ -130,9 +130,17 @@ class AFNILinearTransformArray(BaseLinearTransformList):
130130
131131 def to_ras (self , moving = None , reference = None ):
132132 """Return a nitransforms' internal RAS matrix."""
133- return np .stack (
134- [xfm .to_ras (moving = moving , reference = reference ) for xfm in self .xforms ]
135- )
133+
134+ pre_rotation = post_rotation = np .eye (4 )
135+ if reference is not None and _is_oblique (ref_aff := _ensure_image (reference ).affine ):
136+ pre_rotation = _cardinal_rotation (ref_aff , True )
137+ if moving is not None and _is_oblique (mov_aff := _ensure_image (moving ).affine ):
138+ post_rotation = _cardinal_rotation (mov_aff , False )
139+
140+ return np .stack ([
141+ post_rotation @ (xfm .to_ras () @ pre_rotation )
142+ for xfm in self .xforms
143+ ])
136144
137145 def to_string (self ):
138146 """Convert to a string directly writeable to file."""
@@ -144,14 +152,22 @@ def to_string(self):
144152 if line .strip ()
145153 ]
146154 strings += lines
147- return "\n " .join (strings )
155+ return "\n " .join (strings + [ "" ] )
148156
149157 @classmethod
150158 def from_ras (cls , ras , moving = None , reference = None ):
151159 """Create an ITK affine from a nitransform's RAS+ matrix."""
152160 _self = cls ()
161+
162+ pre_rotation = post_rotation = np .eye (4 )
163+
164+ if reference is not None and _is_oblique (ref_aff := _ensure_image (reference ).affine ):
165+ pre_rotation = _cardinal_rotation (ref_aff , False )
166+ if moving is not None and _is_oblique (mov_aff := _ensure_image (moving ).affine ):
167+ post_rotation = _cardinal_rotation (mov_aff , True )
168+
153169 _self .xforms = [
154- cls ._inner_type .from_ras (ras [i , ...], moving = moving , reference = reference )
170+ cls ._inner_type .from_ras (post_rotation @ ras [i , ...] @ pre_rotation )
155171 for i in range (ras .shape [0 ])
156172 ]
157173 return _self
0 commit comments