Description
I believe there is a bug in nibabel.orientations.ornt_transform
.
In specific it seems to me, that all other functions follow the format flip first then reorder as can best be seen in lia
below.
Some examples
from nibabel.orientations import *
import numpy as np
ras_affine = np.eye(4)
ras_ornt = io_orientation(ras_affine).astype(int)
print("RAS:", ras_ornt.tolist())
RAS: [[0, 1], [1, 1], [2, 1]]
lia_ornt = axcodes2ornt("LIA").astype(int)
print("LIA:", lia_ornt.tolist())
LIA: [[0, -1], [2, -1], [1, 1]]
ras2lia = ornt_transform(ras_ornt, lia_ornt).astype(int)
print("RAS2LIA:", ras2lia.tolist())
RAS2LIA: [[0, -1], [2, 1], [1, -1]]
But it seems to me ornt_transform
and also its test (explicitly test 2 in nibabel.test.test_orientations.test_ornt_transform
in
nibabel/nibabel/tests/test_orientations.py
Line 302 in 2fb125c
ras2lia should 1+2. flip the first and second axes, and 3. reoder swapping 2nd and 3rd axes. Instead ras2lia flips 1 and 3 and swaps 2 and 3.
Furthermore, I do not understand, why ras2lia is different than just lia. That seems wrong as ras is besically the Null transform, it does not do anything.
Similar observations for ras2asl
asl_ornt = axcodes2ornt("ASL").astype(int)
print("ASL:", asl_ornt.tolist())
ASL: [[1, 1], [2, 1], [0, -1]]
ras2asl = ornt_transform(lia_ornt, asl_ornt).astype(int)
print("RAS2ASL:", ras2asl.tolist())
RAS2ASL: [[2, 1], [1, -1], [0, 1]]
Finally, if we just concatenate ras2lia and lia2ras, we should be back in ras (noop).
ras2ras = ornt_transform(ras_ornt, ras_ornt).astype(int)
print("RAS2RAS:", ras2ras.tolist())
RAS2RAS: [[0, 1], [1, 1], [2, 1]]
This is correct
print("RAS2RAS via LIA:", ornt_transform(
ornt_transform(ras_ornt, lia_ornt),
ornt_transform(lia_ornt, ras_ornt)).astype(int).tolist())
RAS2RAS via LIA: [[0, 1], [1, -1], [2, -1]]
This is not correct