Skip to content

Commit b3b188e

Browse files
authored
Merge pull request #143 from poldracklab/fix/afni-load-array-xfail
FIX: Load arrays of linear transforms from AFNI files
2 parents 0b9371c + 09166ef commit b3b188e

File tree

4 files changed

+42
-17
lines changed

4 files changed

+42
-17
lines changed

nitransforms/cli.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,11 @@ def cli_apply(pargs):
2929
"Cannot determine transformation format, manually set format with the `--fmt` flag"
3030
)
3131

32-
if pargs.nonlinear:
33-
xfm = nlinload(pargs.transform, fmt=fmt)
34-
else:
35-
xfm = linload(pargs.transform, fmt=fmt)
32+
xfm = (
33+
nlinload(pargs.transform, fmt=fmt)
34+
if pargs.nonlinear else
35+
linload(pargs.transform, fmt=fmt)
36+
)
3637

3738
# ensure a reference is set
3839
xfm.reference = pargs.ref or pargs.moving

nitransforms/io/afni.py

Lines changed: 34 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
DisplacementsField,
1010
LinearParameters,
1111
TransformFileError,
12+
_ensure_image,
1213
)
1314

1415
LPS = np.diag([-1, -1, 1, 1])
@@ -34,19 +35,25 @@ def to_string(self, banner=True):
3435

3536
@classmethod
3637
def from_ras(cls, ras, moving=None, reference=None):
37-
"""Create an ITK affine from a nitransform's RAS+ matrix."""
38-
ras = ras.copy()
39-
pre = LPS.copy()
40-
post = LPS.copy()
41-
if _is_oblique(reference.affine):
38+
"""Create an AFNI affine from a nitransform's RAS+ matrix."""
39+
pre = LPS
40+
post = LPS
41+
42+
if reference is not None:
43+
reference = _ensure_image(reference)
44+
45+
if reference is not None and _is_oblique(reference.affine):
4246
print("Reference affine axes are oblique.")
4347
M = reference.affine
4448
A = shape_zoom_affine(
4549
reference.shape, voxel_sizes(M), x_flip=False, y_flip=False
4650
)
4751
pre = M.dot(np.linalg.inv(A)).dot(LPS)
4852

49-
if _is_oblique(moving.affine):
53+
if moving is not None:
54+
moving = _ensure_image(moving)
55+
56+
if moving is not None and _is_oblique(moving.affine):
5057
print("Moving affine axes are oblique.")
5158
M2 = moving.affine
5259
A2 = shape_zoom_affine(
@@ -55,7 +62,7 @@ def from_ras(cls, ras, moving=None, reference=None):
5562
post = A2.dot(np.linalg.inv(M2))
5663

5764
# swapaxes is necessary, as axis 0 encodes series of transforms
58-
parameters = np.swapaxes(post.dot(ras.dot(pre)), 0, 1)
65+
parameters = np.swapaxes(post @ ras @ pre, 0, 1)
5966

6067
tf = cls()
6168
tf.structarr["parameters"] = parameters.T
@@ -84,6 +91,26 @@ def from_string(cls, string):
8491
sa["parameters"] = parameters
8592
return tf
8693

94+
def to_ras(self, moving=None, reference=None):
95+
"""Return a nitransforms internal RAS+ matrix."""
96+
pre = LPS
97+
post = LPS
98+
99+
if reference is not None:
100+
reference = _ensure_image(reference)
101+
102+
if reference is not None and _is_oblique(reference.affine):
103+
raise NotImplementedError
104+
105+
if moving is not None:
106+
moving = _ensure_image(moving)
107+
108+
if moving is not None and _is_oblique(moving.affine):
109+
raise NotImplementedError
110+
111+
# swapaxes is necessary, as axis 0 encodes series of transforms
112+
return post @ np.swapaxes(self.structarr["parameters"].T, 0, 1) @ pre
113+
87114

88115
class AFNILinearTransformArray(BaseLinearTransformList):
89116
"""A string-based structure for series of AFNI linear transforms."""

nitransforms/linear.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,8 @@ def from_filename(cls, filename, fmt="X5", reference=None, moving=None):
243243
_factory = io.LinearTransformArray
244244
elif fmt.lower() == "fsl":
245245
_factory = io.fsl.FSLLinearTransformArray
246+
elif fmt.lower() == "afni":
247+
_factory = io.afni.AFNILinearTransformArray
246248
else:
247249
raise NotImplementedError
248250

nitransforms/tests/test_cli.py

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,12 +57,7 @@ def test_apply_nl(tmpdir, testdata_path):
5757
with pytest.raises(ValueError):
5858
ntcli(nlargs)
5959

60-
nlargs.extend(["--fmt", "afni"])
61-
# no linear afni support
62-
with pytest.raises(NotImplementedError):
63-
ntcli(nlargs)
64-
6560
output = "moved_from_warp.nii.gz"
66-
nlargs.extend(["--nonlinear", "--out", output])
61+
nlargs.extend(["--nonlinear", "--fmt", "afni", "--out", output])
6762
ntcli(nlargs)
6863
assert (tmpdir / output).check()

0 commit comments

Comments
 (0)