-
Notifications
You must be signed in to change notification settings - Fork 260
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ENH: Add a utility to calculate obliquity of affines #815
Conversation
This implementation mimics the implementation of AFNI.
Codecov Report
@@ Coverage Diff @@
## master #815 +/- ##
=========================================
+ Coverage 90.1% 90.1% +<.01%
=========================================
Files 96 96
Lines 11911 11914 +3
Branches 2125 2125
=========================================
+ Hits 10732 10735 +3
Misses 834 834
Partials 345 345
Continue to review full report at Codecov.
|
Thanks for this. Some quick thoughts:
R = affine[:-1, :-1] / vs
col_cosines = R @ R.T
upper_cosines = col_cosines[np.triu_indices(3, 1)]
angles = np.arccos(upper_cosines)
np.any(np.abs(angles - np.pi / 2) > thresh) |
Addressing one of @matthew-brett's comments.
Sure, the latest commit should address this.
The doctest did not stay, but now I'm generating the matrix in a more understandable way (first, generate an aligned matrix; second explicitly rotate it).
TBH I just transferred AFNI's implementation because it behaves differently when the affines are not alligned when applying transforms, so I needed to identify this situation for AFNI. Now looking at the code, I believe AFNI's implementation is pretty close to your suggestion since it first projects each column of the affine to the canonical axes, then finds the projection for each axis (i.e. that I don't mind either way. However, I'd be interested in having an implementation parallel to AFNI's to be able to predict it's behavior. In other words, I can check whether your implementation is equivalent for the largest angle. If not, then rename the function to afni_obliquity or something that notes this particular. |
Comparing implementations import numpy as np
from math import acos, pi as PI
from nibabel.eulerangles import euler2mat
from nibabel.affines import from_matvec, voxel_sizes
aligned = np.diag([2.0, 2.0, 2.3, 1.0])
aligned[:-1, -1] = [-10, -10, -7]
R = from_matvec(euler2mat(x=0.09, y=0.001, z=0.001), [0.0, 0.0, 0.0])
oblique = R.dot(aligned)
vs = voxel_sizes(oblique)
O = oblique[:-1, :-1] / vs[np.newaxis, ...]
fig_merit = O.max(axis=1).min()
afni = abs(acos(fig_merit) * 180 / PI)
col_cosines = O @ O.T
upper_cosines = col_cosines[np.triu_indices(3, 1)]
angles = np.arccos(upper_cosines)
angles_deg = np.abs(angles - np.pi / 2)
I suspect your code is actually checking the orthogonality of the axes. |
From a quick glance it looks like they're using the inf-norm of the cosines instead of the 2-norm, so perhaps you could parametrize the norm? |
In https://github.com/nipy/nibabel/pull/815/files#diff-fadc4e2f32f9100f1b5ce2384d00238fR311, the |
Oh - sorry - yes - my code is definitely checking the orthogonality of axes, and that's because I thought that's what you wanted to test. So now I realize I need to ask - what does 'obliquity' mean, exactly? Some rotation that puts the axes out of alignment with any permutation of the RAS+ axes? In that case
and so on. I'd rather stick with radians if possible, we're not using degrees anywhere else, I think. By the way, I believe the the |
Yes, in AFNI's terms they have an explanation (where they mix up the concept of "obliquity" with the orientation of NIfTI images) here.
I'll add a
I preferred to be explicit to make sure the columns were normalized. But yes, both are equivalent. Beyond explicitness, I have no preference - let me know what aligns best with existing code. |
Hello @oesteban, Thank you for updating! Cheers! There are no style issues detected in this Pull Request. 🍻 To test for issues locally, Comment last updated at 2019-09-27 15:52:05 UTC |
7dc812c
to
da8da56
Compare
Do you agree with me about If you prefer to make the broadcasting rule explicit with The Can you put more explanation in the docstring aboutt what 'obliquity' is? |
bfc0933
to
253a256
Compare
@matthew-brett, did the last commit address all your concerns? |
Yes - thanks for your patience. Can you also add a link to https://sscc.nimh.nih.gov/sscc/dglen/Obliquity in the docstring? Is it worth checking this calculation for non-orthogonal axes? It will say 'oblique', but I suppose that is what is intended? |
Like adding a test where just one of the axes is not orthogonal to the plane where the other two are?. |
Thanks for your patience, anything else I should address here? |
OK with me - Chris - OK with you? |
I didn't follow this very closely, but I have no objections. |
This implementation mimics the implementation of AFNI, and will be useful in #656 .