|
3 | 3 | """ Utility routines for working with points and affine transforms
|
4 | 4 | """
|
5 | 5 |
|
| 6 | +from math import acos, pi as PI |
6 | 7 | import numpy as np
|
7 | 8 |
|
8 | 9 | from functools import reduce
|
@@ -296,3 +297,24 @@ def voxel_sizes(affine):
|
296 | 297 | """
|
297 | 298 | top_left = affine[:-1, :-1]
|
298 | 299 | return np.sqrt(np.sum(top_left ** 2, axis=0))
|
| 300 | + |
| 301 | + |
| 302 | +def obliquity(affine): |
| 303 | + r""" |
| 304 | + Estimate the obliquity an affine's axes represent, in degrees from plumb. |
| 305 | +
|
| 306 | + This implementation is inspired by `AFNI's implementation |
| 307 | + <https://github.com/afni/afni/blob/b6a9f7a21c1f3231ff09efbd861f8975ad48e525/src/thd_coords.c#L660-L698>`_ |
| 308 | +
|
| 309 | + >>> affine = np.array([ |
| 310 | + ... [2.74999725e+00, -2.74999817e-03, 2.74999954e-03, -7.69847980e+01], |
| 311 | + ... [2.98603540e-03, 2.73886840e+00, -2.47165887e-01, -8.36692043e+01], |
| 312 | + ... [-2.49170222e-03, 2.47168626e-01, 2.73886865e+00, -8.34056848e+01], |
| 313 | + ... [ 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 1.00000000e+00]]) |
| 314 | + >>> abs(5.15699 - obliquity(affine)) < 0.0001 |
| 315 | + True |
| 316 | +
|
| 317 | + """ |
| 318 | + vs = voxel_sizes(affine) |
| 319 | + fig_merit = (affine[:-1, :-1] / vs[np.newaxis, ...]).max(axis=1).min() |
| 320 | + return abs(acos(fig_merit) * 180 / PI) |
0 commit comments