Skip to content

Commit 4df1194

Browse files
committed
fix: remove sign flip as it seems incorrect
1 parent 076c4fa commit 4df1194

File tree

2 files changed

+66
-5
lines changed

2 files changed

+66
-5
lines changed

nitransforms/io/itk.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -348,8 +348,6 @@ def from_image(cls, imgobj):
348348
hdr.set_intent("vector")
349349

350350
field = np.squeeze(np.asanyarray(imgobj.dataobj)).transpose(2, 1, 0, 3)
351-
field[..., (0, 1)] *= -1.0
352-
353351
return imgobj.__class__(field, LPS @ imgobj.affine, hdr)
354352

355353
@classmethod
@@ -360,7 +358,6 @@ def to_image(cls, imgobj):
360358
hdr.set_intent("vector")
361359

362360
field = imgobj.get_fdata().transpose(2, 1, 0, 3)[..., None, :]
363-
field[..., (0, 1)] *= -1.0
364361
return imgobj.__class__(field, LPS @ imgobj.affine, hdr)
365362

366363

nitransforms/tests/test_io.py

Lines changed: 66 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,13 @@
1717
from nibabel.affines import from_matvec
1818
from scipy.io import loadmat
1919
from nitransforms.linear import Affine
20+
from nitransforms import nonlinear as nitnl
2021
from nitransforms.io import (
2122
afni,
2223
fsl,
2324
lta as fs,
2425
itk,
26+
x5
2527
)
2628
from nitransforms.io.lta import (
2729
VolumeGeometry as VG,
@@ -695,6 +697,17 @@ def test_itk_linear_h5(tmpdir, data_path, testdata_path):
695697
itk.ITKLinearTransform.from_filename("test.h5")
696698

697699

700+
701+
def test_itk_disp_load_intent():
702+
"""Checks whether the NIfTI intent is fixed."""
703+
with pytest.warns(UserWarning):
704+
field = itk.ITKDisplacementsField.from_image(
705+
nb.Nifti1Image(np.zeros((20, 20, 20, 1, 3)), np.eye(4), None)
706+
)
707+
708+
assert field.header.get_intent()[0] == "vector"
709+
710+
698711
# Added tests for displacements fields orientations (ANTs/ITK)
699712
@pytest.mark.parametrize("image_orientation", ["RAS", "LAS", "LPS", "oblique"])
700713
def test_itk_displacements(tmp_path, get_testdata, image_orientation):
@@ -736,12 +749,63 @@ def test_itk_displacements(tmp_path, get_testdata, image_orientation):
736749
np.testing.assert_allclose(itk_nii.dataobj, nit_nii.dataobj)
737750
np.testing.assert_allclose(itk_nii.affine, nit_nii.affine)
738751

752+
# Check ITK-generated field has LPS-rotated affine
753+
np.testing.assert_allclose(itk_nii.affine, LPS @ ref_affine)
754+
# Test ITK-generated dataobject vs. original field
755+
np.testing.assert_allclose(itk_nii.dataobj, field.transpose(2, 1, 0, 3)[..., None, :])
756+
739757
# Test round trip
740758
assert itk_nit_nii.shape == field.shape
759+
np.testing.assert_allclose(itk_nit_nii.dataobj, field)
760+
np.testing.assert_allclose(itk_nit_nii.dataobj.transpose(2, 1, 0, 3)[..., None, :], nit_nii.dataobj)
741761
np.testing.assert_allclose(itk_nit_nii.affine, ref_affine)
762+
np.testing.assert_allclose(LPS @ itk_nit_nii.affine, nit_nii.affine)
742763

743-
field[..., (0, 1)] *= -1.0 # Undo LPS flip
744-
np.testing.assert_allclose(itk_nit_nii.dataobj, field)
764+
765+
@pytest.mark.parametrize("is_deltas", [True, False])
766+
def test_densefield_x5_roundtrip(tmp_path, is_deltas):
767+
"""Ensure dense field transforms roundtrip via X5."""
768+
ref = nb.Nifti1Image(np.zeros((2, 2, 2), dtype="uint8"), np.eye(4))
769+
disp = nb.Nifti1Image(np.random.rand(2, 2, 2, 3).astype("float32"), np.eye(4))
770+
771+
xfm = nitnl.DenseFieldTransform(disp, is_deltas=is_deltas, reference=ref)
772+
773+
node = xfm.to_x5(metadata={"GeneratedBy": "pytest"})
774+
assert node.type == "nonlinear"
775+
assert node.subtype == "densefield"
776+
assert node.representation == "displacements" if is_deltas else "deformations"
777+
assert node.domain.size == ref.shape
778+
assert node.metadata["GeneratedBy"] == "pytest"
779+
780+
fname = tmp_path / "test.x5"
781+
x5.to_filename(fname, [node])
782+
783+
xfm2 = nitnl.DenseFieldTransform.from_filename(fname, fmt="X5")
784+
785+
assert xfm2.reference.shape == ref.shape
786+
assert np.allclose(xfm2.reference.affine, ref.affine)
787+
assert xfm == xfm2
788+
789+
790+
def test_bspline_to_x5(tmp_path):
791+
"""Check BSpline transforms export to X5."""
792+
coeff = nb.Nifti1Image(np.zeros((2, 2, 2, 3), dtype="float32"), np.eye(4))
793+
ref = nb.Nifti1Image(np.zeros((2, 2, 2), dtype="uint8"), np.eye(4))
794+
795+
xfm = nitnl.BSplineFieldTransform(coeff, reference=ref)
796+
node = xfm.to_x5(metadata={"tool": "pytest"})
797+
assert node.type == "nonlinear"
798+
assert node.subtype == "bspline"
799+
assert node.representation == "coefficients"
800+
assert node.metadata["tool"] == "pytest"
801+
802+
fname = tmp_path / "bspline.x5"
803+
x5.to_filename(fname, [node])
804+
805+
xfm2 = nitnl.BSplineFieldTransform.from_filename(fname, fmt="X5")
806+
assert np.allclose(xfm._coeffs, xfm2._coeffs)
807+
assert xfm2.reference.shape == ref.shape
808+
assert np.allclose(xfm2.reference.affine, ref.affine)
745809

746810

747811
# Added tests for h5 orientation bug

0 commit comments

Comments
 (0)