@@ -226,6 +226,19 @@ def test_registration_types(self):
226
226
)
227
227
print ("Finished long registration interface test" )
228
228
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
+
229
242
230
243
class TestModule_metrics (unittest .TestCase ):
231
244
def setUp (self ):
@@ -396,17 +409,60 @@ def test_deformation_gradient(self):
396
409
fi = ants .resample_image (fi ,(128 ,128 ),1 ,0 )
397
410
mi = ants .resample_image (mi ,(128 ,128 ),1 ,0 )
398
411
mytx = ants .registration (fixed = fi , moving = mi , type_of_transform = ('SyN' ) )
399
- dg = ants .deformation_gradient ( ants .image_read ( mytx ['fwdtransforms' ][0 ] ) )
400
412
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 ] ),
402
416
py_based = True )
403
417
404
- dg = ants .deformation_gradient ( ants .image_read ( mytx ['fwdtransforms' ][0 ] ),
418
+ rot = ants .deformation_gradient ( ants .image_read ( mytx ['fwdtransforms' ][0 ] ),
405
419
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 ] ),
408
421
to_rotation = True , py_based = True )
409
422
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
+
410
466
def test_jacobian (self ):
411
467
fi = ants .image_read ( ants .get_ants_data ('r16' ))
412
468
mi = ants .image_read ( ants .get_ants_data ('r64' ))
@@ -468,18 +524,5 @@ def test_label_image_registration(self):
468
524
moving_intensity_images = mi )
469
525
470
526
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
-
484
527
if __name__ == "__main__" :
485
528
run_tests ()
0 commit comments