Skip to content

Commit 080360e

Browse files
authored
Merge pull request #826 from ANTsX/jacobian_tests
ENH: Expand jacobian tests
2 parents 89f1688 + 2ac5564 commit 080360e

File tree

1 file changed

+61
-18
lines changed

1 file changed

+61
-18
lines changed

tests/test_registration.py

Lines changed: 61 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,19 @@ def test_registration_types(self):
226226
)
227227
print("Finished long registration interface test")
228228

229+
def test_reg_precision_option(self):
230+
# Check that registration works with float and double precision
231+
fi = ants.image_read(ants.get_ants_data("r16"))
232+
mi = ants.image_read(ants.get_ants_data("r64"))
233+
fi = ants.resample_image(fi, (60, 60), 1, 0)
234+
mi = ants.resample_image(mi, (60, 60), 1, 0)
235+
mytx = ants.registration(fixed=fi, moving=mi, type_of_transform="SyN") # should be float precision
236+
info = ants.image_header_info(mytx["fwdtransforms"][0])
237+
self.assertEqual(info['pixeltype'], 'float')
238+
mytx = ants.registration(fixed=fi, moving=mi, type_of_transform="SyN", singleprecision=False)
239+
info = ants.image_header_info(mytx["fwdtransforms"][0])
240+
self.assertEqual(info['pixeltype'], 'double')
241+
229242

230243
class TestModule_metrics(unittest.TestCase):
231244
def setUp(self):
@@ -396,17 +409,60 @@ def test_deformation_gradient(self):
396409
fi = ants.resample_image(fi,(128,128),1,0)
397410
mi = ants.resample_image(mi,(128,128),1,0)
398411
mytx = ants.registration(fixed=fi , moving=mi, type_of_transform = ('SyN') )
399-
dg = ants.deformation_gradient( ants.image_read( mytx['fwdtransforms'][0] ) )
400412

401-
dg = ants.deformation_gradient( ants.image_read( mytx['fwdtransforms'][0] ),
413+
dg = ants.deformation_gradient( ants.image_read( mytx['fwdtransforms'][0] ) )
414+
# Expect some differences between these two methods
415+
dg_py = ants.deformation_gradient( ants.image_read( mytx['fwdtransforms'][0] ),
402416
py_based=True)
403417

404-
dg = ants.deformation_gradient( ants.image_read( mytx['fwdtransforms'][0] ),
418+
rot = ants.deformation_gradient( ants.image_read( mytx['fwdtransforms'][0] ),
405419
to_rotation=True)
406-
407-
dg = ants.deformation_gradient( ants.image_read( mytx['fwdtransforms'][0] ),
420+
rot_py = ants.deformation_gradient( ants.image_read( mytx['fwdtransforms'][0] ),
408421
to_rotation=True, py_based=True)
409422

423+
def rotation_angle_diff_field(rot_1, rot_2, degrees=False):
424+
"""
425+
Compute angular difference between two rotation matrix images.
426+
Inputs:
427+
rot_1: antsImage with dim*dim components representing the matrix
428+
rot_2: antsImage with same shape and dimension as rot_1
429+
Returns:
430+
angle_diff: numpy array with angle in radians (or degrees if degrees=True)
431+
"""
432+
# cast and reshape
433+
dim = rot_1.dimension
434+
if rot_2.dimension != dim:
435+
raise ValueError("Rotation images must have the same dimension.")
436+
if rot_1.shape != rot_2.shape:
437+
raise ValueError("Rotation images must have the same shape.")
438+
rot_py1 = rot_1.numpy().reshape(rot_1.shape + (dim, dim))
439+
rot_py2 = rot_2.numpy().reshape(rot_2.shape + (dim, dim))
440+
# Compute relative rotation: R_rel = R_py @ R.T
441+
R_rel = rot_py1 @ np.swapaxes(rot_py2, -2, -1)
442+
trace = np.trace(R_rel, axis1=-2, axis2=-1)
443+
if dim == 2:
444+
angle = np.arccos(np.clip((trace) / 2, -1.0, 1.0))
445+
elif dim == 3:
446+
angle = np.arccos(np.clip((trace - 1) / 2, -1.0, 1.0))
447+
else:
448+
raise ValueError("Only 2D or 3D rotation matrices are supported.")
449+
450+
return np.degrees(angle) if degrees else angle
451+
452+
rot_angle_diff = rotation_angle_diff_field(rot_py, rot, degrees=True)
453+
self.assertTrue(np.all(rot_angle_diff < 1))
454+
455+
rot_inv = ants.deformation_gradient( ants.image_read( mytx['fwdtransforms'][0] ),
456+
to_inverse_rotation=True)
457+
rot_py_inv = ants.deformation_gradient( ants.image_read( mytx['fwdtransforms'][0] ),
458+
to_inverse_rotation=True, py_based=True)
459+
460+
rot_angle_diff = rotation_angle_diff_field(rot_inv, rot_py_inv, degrees=True)
461+
self.assertTrue(np.all(rot_angle_diff < 1))
462+
463+
# Check it's actually the inverse
464+
self.assertTrue(np.allclose (rot_py.numpy(), rot_py_inv.numpy()[..., [0, 2, 1, 3]]))
465+
410466
def test_jacobian(self):
411467
fi = ants.image_read( ants.get_ants_data('r16'))
412468
mi = ants.image_read( ants.get_ants_data('r64'))
@@ -468,18 +524,5 @@ def test_label_image_registration(self):
468524
moving_intensity_images=mi)
469525

470526

471-
def test_reg_precision_option(self):
472-
# Check that registration and apply transforms works with float and double precision
473-
fi = ants.image_read(ants.get_ants_data("r16"))
474-
mi = ants.image_read(ants.get_ants_data("r64"))
475-
fi = ants.resample_image(fi, (60, 60), 1, 0)
476-
mi = ants.resample_image(mi, (60, 60), 1, 0)
477-
mytx = ants.registration(fixed=fi, moving=mi, type_of_transform="SyN") # should be float precision
478-
info = ants.image_header_info(mytx["fwdtransforms"][0])
479-
self.assertEqual(info['pixeltype'], 'float')
480-
mytx = ants.registration(fixed=fi, moving=mi, type_of_transform="SyN", singleprecision=False)
481-
info = ants.image_header_info(mytx["fwdtransforms"][0])
482-
self.assertEqual(info['pixeltype'], 'double')
483-
484527
if __name__ == "__main__":
485528
run_tests()

0 commit comments

Comments
 (0)