tensor_math
tit.pre.qsi.tensor_math ¶
Tensor and transform algebra for the DTI -> SimNIBS path (numpy only).
Conventions:
- "world" is scanner RAS in mm (the NIfTI sform), the frame SimNIBS meshes live in.
A tensor field held in memory is always a world-frame
(..., 3, 3)array. - SimNIBS
cond2elmdata(correct_FSL=True)reads a stored 6-vectorSasT_world = M S M^TwithMfrom :func:simnibs_fsl_matrix. We storeS = inv(M) T_world inv(M)^Twith that exactM, so the round trip is exact for any output affine, isotropic or not. - An ITK/ANTs transform named
from-A_to-Bmaps points of B (the fixed image) to A. ITK stores it in LPS asy = R (x - c) + c + t.
sym ¶
(..., 6) upper triangle in FSL order -> (..., 3, 3) symmetric tensors.
Source code in tit/pre/qsi/tensor_math.py
unsym ¶
rotate ¶
simnibs_fsl_matrix ¶
Exactly SimNIBS 4.6 cond_utils.cond2elmdata with correct_FSL=True.
M = A[:3, :3] / colnorm[:, None] (rows divided by the column norms, as SimNIBS
writes it), then M = M @ diag(-1, 1, 1) when det(M) > 0.
Source code in tit/pre/qsi/tensor_math.py
world_to_simnibs ¶
World tensors -> the 6-vectors SimNIBS will read back as those world tensors.
simnibs_to_world ¶
Stored 6-vectors -> the world tensors SimNIBS builds from them.
itk_euler_to_ras ¶
itk_euler_to_ras(params, center) -> ndarray
ITK transform parameters -> 4x4 RAS point map.
params is an Euler3DTransform (6 values: angles x, y, z in radians, then the
translation; rotation R = Rz @ Rx @ Ry, ITK's default ZXY order) or an
AffineTransform (12 values: the matrix row-major, then the translation).
center is the ITK fixed parameter. Both are in LPS; the result is in RAS.
Source code in tit/pre/qsi/tensor_math.py
qsiprep_anat_affines ¶
Reproduce QSIPrep's Conform(deoblique_header=True): (A_lps, A_anat).
QSIPrep reorients the input T1w to LPS (A_lps), then replaces an oblique
affine with diag(zooms * sign(diag)) keeping the translation column
(A_anat). The voxel array is unchanged, so
raw world = A_lps @ inv(A_anat) @ anat world. No transform file records this
step. Assumes one input T1w and no resize, QSIPrep's behaviour for a single T1w.
Source code in tit/pre/qsi/tensor_math.py
acpc_to_t1_world ¶
4x4 map from QSIPrep ACPC world to raw-T1 (= charm m2m T1) world.
G = A_lps @ inv(A_anat) @ inv(X), where acpc_to_anat_ras is X, the RAS
form of QSIPrep's from-ACPC_to-anat transform (it maps anat points to ACPC).
Source code in tit/pre/qsi/tensor_math.py
polar_rotation ¶
Rotation factor of a 3x3 (or 4x4) linear map (exact for a rigid map).
eig_desc ¶
Eigenvalues (descending) and matching eigenvectors (columns).
fa_md ¶
Fractional anisotropy and mean diffusivity from (..., 3) eigenvalues.