`nibabel.orientations.aff2axcodes` potentially returns incorrect results
Hello,
I am using `aff2axcodes` to determine the `axcodes` of an affine matrix and the results are a bit convoluted.
Specifically, this is about affine matrices, that are rotated around 45 degrees in multiple directions. I do not even know what the "correct" results really should be...
Let us consider the following affine matrix:
```python
affine = \
[[-0.585182553995787, 0.5048269789762401, -0.6345952251606463, -2.218487624719689],
[-0.5327455539210799, 0.35065247835655966, 0.7702110192666194, 2.028722778552794],
[-0.6113456904863974, -0.7887918361140193, -0.06374861569935834, 4.227025896592773],
[0.0, 0.0, 0.0, 1.0]]
```
This matrix is orthonormal and valid (generated with `scipy.spatial.transform.Rotation.from_rotvec().as_matrix()`):
```python
np.linalg.inv(affine[:3,:3]) - affine[:3, :3].T
# test for orthonormal, approx zero
# [[ 2.22044605e-16 3.33066907e-16 1.11022302e-16], [-3.33066907e-16 -2.22044605e-16 2.22044605e-16], [ 3.33066907e-16 -5.55111512e-16 1.66533454e-16]]
np.linalg.norm(affine[:3,:3], axis=0) , np.linalg.norm(affine[:3,:3], axis=1)
# test for length of vectors: ([1. 1. 1.], [1. 1. 1.])
```
an even more extreme affine is
```python
affine = \
[[0.14794184343060812, 0.4876343794531119, -0.6167057020473639, -0.38513162667728795],
[0.5617554027693318, -0.5045939256658585, -0.26422686774925774, -0.13797634685442106],
[0.5500400698329341, 0.38418443768129973, 0.4357272534759381, 0.652584993353186],
[0.0, 0.0, 0.0, 1.0]] # scale factors are 0.8, 0.8, 0.8
```
which following this paradigm is either `'asl'` or `'ars'` --> the second vector may be least aligned with dimension 3, but nonetheless, vectors 1 and 3 are more aligned with the other two directions still.
Running `nibabel.orientations.aff2axcodes`:
```python
"".join(nib.orientations.aff2axcodes(affine, ("lr", "pa", "is"))) # 'ira'
```
The problem here is, that it really should be `'lia'`!, why:
Well, instead of going through the list in `axis=2` direction, the algorithm should go by largest absolute value (technically for normalized column vectors, but column vectors are normalized here).
In reality, the issue traces back to `nibabel.orientations.io_orientation`, where the first, second and third direction are identified by the maximum absolute value. Instead, maybe we should consider going by largest absolute value first.
I know that in practice, this all is a bit of an edge case, nonetheless, it is currently breaking one of my test cases.
关闭于 2026-02-05 2 条评论