Skip to content

Commit 0d687c2

Browse files
oestebanfeilong
andcommitted
enh: add failing test cases demonstrating #137 and #171
In particular, leverages @feilong's dataset he posted on #171 and adds it to the test dataset. Co-authored-by: Feilong Ma <[email protected]>
1 parent 0dff054 commit 0d687c2

File tree

1 file changed

+106
-0
lines changed

1 file changed

+106
-0
lines changed

nitransforms/tests/test_io.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -672,3 +672,109 @@ def test_itk_linear_h5(tmpdir, data_path, testdata_path):
672672
# Error raised if the we try to use the single affine loader
673673
with pytest.raises(TransformIOError):
674674
itk.ITKLinearTransform.from_filename("test.h5")
675+
676+
# Added tests for h5 orientation bug
677+
678+
679+
@pytest.mark.xfail(
680+
reason="GH-137/GH-171: displacement field dimension order is wrong",
681+
strict=False,
682+
)
683+
def test_itk_h5_field_order(tmp_path):
684+
"""Displacement fields stored in row-major order should fail to round-trip."""
685+
shape = (3, 4, 5)
686+
vals = np.arange(np.prod(shape), dtype=float).reshape(shape)
687+
field = np.stack([vals, vals + 100, vals + 200], axis=0)
688+
689+
params = field.reshape(-1, order="C")
690+
fixed = np.array(list(shape) + [0, 0, 0] + [1, 1, 1] + list(np.eye(3).ravel()), dtype=float)
691+
fname = tmp_path / "field.h5"
692+
with H5File(fname, "w") as f:
693+
grp = f.create_group("TransformGroup")
694+
grp.create_group("0")["TransformType"] = np.array([b"CompositeTransform_double_3_3"])
695+
g1 = grp.create_group("1")
696+
g1["TransformType"] = np.array([b"DisplacementFieldTransform_float_3_3"])
697+
g1["TransformFixedParameters"] = fixed
698+
g1["TransformParameters"] = params
699+
700+
img = itk.ITKCompositeH5.from_filename(fname)[0]
701+
expected = np.moveaxis(field, 0, -1)
702+
expected[..., (0, 1)] *= -1
703+
assert np.allclose(img.get_fdata(), expected)
704+
705+
706+
def _load_composite_testdata(data_path):
707+
"""Return the composite HDF5 and displacement field from regressions."""
708+
h5file = data_path / "regressions" / "ants_t1_to_mniComposite.h5"
709+
# Generated using
710+
# CompositeTransformUtil --disassemble ants_t1_to_mniComposite.h5 \
711+
# ants_t1_to_mniComposite
712+
warpfile = data_path / "regressions" / (
713+
"01_ants_t1_to_mniComposite_DisplacementFieldTransform.nii.gz"
714+
)
715+
if not (h5file.exists() and warpfile.exists()):
716+
pytest.skip("Composite transform test data not available")
717+
return h5file, warpfile
718+
719+
720+
@pytest.mark.xfail(
721+
reason="GH-137/GH-171: displacement field dimension order is wrong",
722+
strict=False,
723+
)
724+
def test_itk_h5_displacement_mismatch(testdata_path):
725+
"""Composite displacements should match the standalone field"""
726+
h5file, warpfile = _load_composite_testdata(testdata_path)
727+
xforms = itk.ITKCompositeH5.from_filename(h5file)
728+
field_h5 = xforms[1]
729+
field_img = itk.ITKDisplacementsField.from_filename(warpfile)
730+
731+
np.testing.assert_array_equal(
732+
np.asanyarray(field_h5.dataobj), np.asanyarray(field_img.dataobj)
733+
)
734+
735+
736+
def test_itk_h5_transpose_fix(testdata_path):
737+
"""Check the displacement field orientation explicitly.
738+
739+
ITK stores displacement fields with the vector dimension leading in
740+
Fortran (column-major) order [1]_. Transposing the parameters from the HDF5
741+
composite file accordingly should match the standalone displacement image.
742+
743+
References
744+
----------
745+
.. [1] ITK Software Guide. https://itk.org/ItkSoftwareGuide.pdf
746+
"""
747+
h5file, warpfile = _load_composite_testdata(testdata_path)
748+
749+
with H5File(h5file, "r") as f:
750+
group = f["TransformGroup"]["2"]
751+
size = group["TransformFixedParameters"][:3].astype(int)
752+
params = group["TransformParameters"][:].reshape(*size, 3)
753+
754+
img = nb.load(warpfile)
755+
ref = np.squeeze(np.asanyarray(img.dataobj))
756+
757+
np.testing.assert_array_equal(params.transpose(2, 1, 0, 3), ref)
758+
759+
760+
def test_itk_h5_field_order_fortran(tmp_path):
761+
"""Verify Fortran-order displacement fields load correctly"""
762+
shape = (3, 4, 5)
763+
vals = np.arange(np.prod(shape), dtype=float).reshape(shape)
764+
field = np.stack([vals, vals + 100, vals + 200], axis=0)
765+
766+
params = field.reshape(-1, order="F")
767+
fixed = np.array(list(shape) + [0, 0, 0] + [1, 1, 1] + list(np.eye(3).ravel()), dtype=float)
768+
fname = tmp_path / "field_f.h5"
769+
with H5File(fname, "w") as f:
770+
grp = f.create_group("TransformGroup")
771+
grp.create_group("0")["TransformType"] = np.array([b"CompositeTransform_double_3_3"])
772+
g1 = grp.create_group("1")
773+
g1["TransformType"] = np.array([b"DisplacementFieldTransform_float_3_3"])
774+
g1["TransformFixedParameters"] = fixed
775+
g1["TransformParameters"] = params
776+
777+
img = itk.ITKCompositeH5.from_filename(fname)[0]
778+
expected = np.moveaxis(field, 0, -1)
779+
expected[..., (0, 1)] *= -1
780+
assert np.allclose(img.get_fdata(), expected)

0 commit comments

Comments
 (0)