2
2
from math import pi
3
3
import numpy as np
4
4
from nibabel .affines import (
5
- from_matvec ,
5
+ apply_affine ,
6
6
obliquity ,
7
7
voxel_sizes ,
8
8
)
@@ -39,25 +39,8 @@ def to_string(self, banner=True):
39
39
@classmethod
40
40
def from_ras (cls , ras , moving = None , reference = None ):
41
41
"""Create an AFNI affine from a nitransform's RAS+ matrix."""
42
- pre = LPS
43
- post = LPS
44
-
45
- if reference is not None :
46
- reference = _ensure_image (reference )
47
-
48
- if reference is not None and _is_oblique (reference .affine ):
49
- print ("Reference affine axes are oblique." )
50
- ras = ras @ _afni_warpdrive (reference .affine , ras = True , forward = False )
51
-
52
- if moving is not None :
53
- moving = _ensure_image (moving )
54
-
55
- if moving is not None and _is_oblique (moving .affine ):
56
- print ("Moving affine axes are oblique." )
57
- ras = _afni_warpdrive (reference .affine , ras = True ) @ ras
58
-
59
42
# swapaxes is necessary, as axis 0 encodes series of transforms
60
- parameters = np .swapaxes (post @ ras @ pre , 0 , 1 )
43
+ parameters = np .swapaxes (LPS @ ras @ LPS , 0 , 1 )
61
44
62
45
tf = cls ()
63
46
tf .structarr ["parameters" ] = parameters .T
@@ -89,23 +72,8 @@ def from_string(cls, string):
89
72
90
73
def to_ras (self , moving = None , reference = None ):
91
74
"""Return a nitransforms internal RAS+ matrix."""
92
- pre = LPS
93
- post = LPS
94
-
95
- if reference is not None :
96
- reference = _ensure_image (reference )
97
-
98
- if reference is not None and _is_oblique (reference .affine ):
99
- raise NotImplementedError
100
-
101
- if moving is not None :
102
- moving = _ensure_image (moving )
103
-
104
- if moving is not None and _is_oblique (moving .affine ):
105
- raise NotImplementedError
106
-
107
75
# swapaxes is necessary, as axis 0 encodes series of transforms
108
- return post @ np .swapaxes (self .structarr ["parameters" ].T , 0 , 1 ) @ pre
76
+ return LPS @ np .swapaxes (self .structarr ["parameters" ].T , 0 , 1 ) @ LPS
109
77
110
78
111
79
class AFNILinearTransformArray (BaseLinearTransformList ):
@@ -183,7 +151,7 @@ def _is_oblique(affine, thres=OBLIQUITY_THRESHOLD_DEG):
183
151
return (obliquity (affine ).min () * 180 / pi ) > thres
184
152
185
153
186
- def _afni_warpdrive (nii , forward = True , ras = False ):
154
+ def _afni_warpdrive (oblique , shape , forward = True , ras = False ):
187
155
"""
188
156
Calculate AFNI's ``WARPDRIVE_MATVEC_FOR_000000`` (de)obliquing affine.
189
157
@@ -204,15 +172,18 @@ def _afni_warpdrive(nii, forward=True, ras=False):
204
172
to be oblique.
205
173
206
174
"""
207
- oblique = nii .affine
208
- plumb = oblique [:3 , :3 ] / np .abs (oblique [:3 , :3 ]).max (0 )
209
- plumb [np .abs (plumb ) < 1.0 ] = 0
210
- plumb *= voxel_sizes (oblique )
211
-
212
- R = from_matvec (plumb @ np .linalg .inv (oblique [:3 , :3 ]), (0 , 0 , 0 ))
213
- plumb_orig = np .linalg .inv (R [:3 , :3 ]) @ oblique [:3 , 3 ]
214
- print (plumb_orig )
215
- R [:3 , 3 ] = R [:3 , :3 ] @ (plumb_orig - oblique [:3 , 3 ])
175
+ shape = np .array (shape [:3 ])
176
+ plumb_r = oblique [:3 , :3 ] / np .abs (oblique [:3 , :3 ]).max (0 )
177
+ plumb_r [np .abs (plumb_r ) < 1.0 ] = 0
178
+ plumb_r *= voxel_sizes (oblique )
179
+ plumb = np .eye (4 )
180
+ plumb [:3 , :3 ] = plumb_r
181
+ obliq_o = apply_affine (oblique , 0.5 * (shape - 1 ))
182
+ plumb_c = apply_affine (plumb , 0.5 * (shape - 1 ))
183
+ plumb [:3 , 3 ] = - plumb_c + obliq_o
184
+ print (obliq_o , apply_affine (plumb , 0.5 * (shape - 1 )))
185
+
186
+ R = plumb @ np .linalg .inv (oblique )
216
187
if not ras :
217
188
# Change sign to match AFNI's warpdrive_matvec signs
218
189
B = np .ones ((2 , 2 ))
@@ -228,5 +199,8 @@ def _afni_header(nii, field="WARPDRIVE_MATVEC_FOR_000000"):
228
199
root .find (f".//*[@atr_name='{ field } ']" ).text ,
229
200
sep = "\n " ,
230
201
dtype = "float32"
231
- ).reshape ((3 , 4 ))
232
- return np .vstack ((retval , (0 , 0 , 0 , 1 )))
202
+ )
203
+ if retval .size == 12 :
204
+ return np .vstack ((retval .reshape ((3 , 4 )), (0 , 0 , 0 , 1 )))
205
+
206
+ return retval
0 commit comments