From c1fd4ef9182d3ef6dbd3bc4366b4e44fadde9479 Mon Sep 17 00:00:00 2001 From: Oscar Esteban Date: Wed, 21 Jul 2021 09:13:05 +0200 Subject: [PATCH] ENH: Add one test for the implementation of volume geometry of LTA The new LTA file and the matrix hard-coded on the test come from an issue discovered in *fMRIPrep* (see nipreps/fmriprep#2444). This test currently breaks master. --- nitransforms/tests/data/bold-to-t1w.lta | 32 +++++++++++++++++ nitransforms/tests/test_io.py | 46 +++++++++++++++++++++---- 2 files changed, 72 insertions(+), 6 deletions(-) create mode 100644 nitransforms/tests/data/bold-to-t1w.lta diff --git a/nitransforms/tests/data/bold-to-t1w.lta b/nitransforms/tests/data/bold-to-t1w.lta new file mode 100644 index 00000000..952be0aa --- /dev/null +++ b/nitransforms/tests/data/bold-to-t1w.lta @@ -0,0 +1,32 @@ +# +# created by oesteban with lta_convert from bold-to-t1w.v2v.lta + +type = 1 # LINEAR_RAS_TO_RAS +nxforms = 1 +mean = 0.0000 0.0000 0.0000 +sigma = 10000.0000 +1 4 4 +9.998173117637634e-01 -1.668193005025387e-02 9.299500845372677e-03 3.410797119140625e-01 +1.651172526180744e-02 9.996999502182007e-01 1.808840036392212e-02 -4.532470703125000e-01 +-9.598462842404842e-03 -1.793161034584045e-02 9.997929334640503e-01 -9.916595458984375e+00 +0.000000000000000e+00 0.000000000000000e+00 0.000000000000000e+00 1.000000000000000e+00 +src volume info +valid = 1 # volume info valid +filename = /work/fmriprep_wf/single_subject_10316_wf/func_preproc_task_bart_wf/bold_reg_wf/bbreg_wf/bbregister/uni_xform_masked.nii.gz +volume = 64 64 34 +voxelsize = 3.000000000000000e+00 3.000000000000000e+00 4.000000000000000e+00 +xras = -1.000000000000000e+00 -0.000000000000000e+00 0.000000000000000e+00 +yras = 0.000000000000000e+00 6.858183145523071e-01 7.277727723121643e-01 +zras = -0.000000000000000e+00 -7.277727723121643e-01 6.858183741569519e-01 +cras = -4.697326660156250e+00 -9.175056457519531e+00 1.141981506347656e+01 +dst volume info +valid = 1 # volume info valid +filename = /freesurfer/sub-10316/mri/orig.mgz +volume = 256 256 256 +voxelsize = 1.000000000000000e+00 1.000000000000000e+00 1.000000000000000e+00 +xras = -1.000000000000000e+00 0.000000000000000e+00 0.000000000000000e+00 +yras = 0.000000000000000e+00 0.000000000000000e+00 -1.000000000000000e+00 +zras = 0.000000000000000e+00 1.000000000000000e+00 0.000000000000000e+00 +cras = -1.008934020996094e+00 4.937973022460938e+00 1.715942382812500e+00 +subject sub-10316 +fscale 0.100000 diff --git a/nitransforms/tests/test_io.py b/nitransforms/tests/test_io.py index 01d8acd0..50ee15b7 100644 --- a/nitransforms/tests/test_io.py +++ b/nitransforms/tests/test_io.py @@ -3,6 +3,7 @@ """I/O test cases.""" import numpy as np import pytest +from io import StringIO import filecmp import nibabel as nb @@ -37,6 +38,22 @@ def test_VolumeGeometry(tmpdir, get_testdata): assert len(vg.to_string().split("\n")) == 8 +def test_VG_from_LTA(data_path): + """Check the affine interpolation from volume geometries.""" + # affine manually clipped after running mri_info on the image + oracle = np.loadtxt(StringIO("""\ +-3.0000 0.0000 -0.0000 91.3027 +-0.0000 2.0575 -2.9111 -25.5251 + 0.0000 2.1833 2.7433 -105.0820 + 0.0000 0.0000 0.0000 1.0000""")) + + lta_text = "\n".join( + (data_path / "bold-to-t1w.lta").read_text().splitlines()[13:21] + ) + r2r = VG.from_string(lta_text) + assert np.allclose(r2r.as_affine(), oracle, rtol=1e-4) + + def test_LinearTransform(tmpdir): lt = LT() assert lt["m_L"].shape == (4, 4) @@ -77,9 +94,10 @@ def test_LinearTransformArray(tmpdir, data_path): assert np.allclose(lta["xforms"][0]["m_L"], lta2["xforms"][0]["m_L"]) -def test_LT_conversions(data_path): - r = str(data_path / "affine-RAS.fs.lta") - v = str(data_path / "affine-RAS.fs.v2v.lta") +@pytest.mark.parametrize("fname", ["affine-RAS.fs", "bold-to-t1w"]) +def test_LT_conversions(data_path, fname): + r = str(data_path / f"{fname}.lta") + v = str(data_path / f"{fname}.v2v.lta") with open(r) as fa, open(v) as fb: r2r = LTA.from_fileobj(fa) v2v = LTA.from_fileobj(fb) @@ -92,11 +110,19 @@ def test_LT_conversions(data_path): # convert vox2vox LTA to ras2ras v2v["xforms"][0].set_type("LINEAR_RAS_TO_RAS") assert v2v["xforms"][0]["type"] == 1 - assert np.allclose(r2r_m, v2v_m, atol=1e-05) + assert np.allclose(r2r_m, v2v_m, rtol=1e-04) @pytest.mark.xfail(raises=(FileNotFoundError, NotImplementedError)) -@pytest.mark.parametrize("image_orientation", ["RAS", "LAS", "LPS", "oblique",]) +@pytest.mark.parametrize( + "image_orientation", + [ + "RAS", + "LAS", + "LPS", + "oblique", + ], +) @pytest.mark.parametrize("sw", ["afni", "fsl", "fs", "itk"]) def test_Linear_common(tmpdir, data_path, sw, image_orientation, get_testdata): tmpdir.chdir() @@ -143,7 +169,15 @@ def test_Linear_common(tmpdir, data_path, sw, image_orientation, get_testdata): assert np.allclose(xfm.to_ras(reference=reference, moving=moving), RAS) -@pytest.mark.parametrize("image_orientation", ["RAS", "LAS", "LPS", "oblique",]) +@pytest.mark.parametrize( + "image_orientation", + [ + "RAS", + "LAS", + "LPS", + "oblique", + ], +) @pytest.mark.parametrize("sw", ["afni", "fsl", "itk"]) def test_LinearList_common(tmpdir, data_path, sw, image_orientation, get_testdata): tmpdir.chdir()