def test_affreg_defaults(): # Test all default arguments with an arbitrary transform # Select an arbitrary transform (all of them are already tested # in test_affreg_all_transforms) transform_name = 'TRANSLATION' dim = 2 ttype = (transform_name, dim) aff_options = ['mass', 'voxel-origin', 'centers', None, np.eye(dim + 1)] for starting_affine in aff_options: if dim == 2: nslices = 1 else: nslices = 45 factor = factors[ttype][0] sampling_pc = factors[ttype][1] transform = regtransforms[ttype] id_param = transform.get_identity_parameters() static, moving, static_grid2world, moving_grid2world, smask, mmask, T = \ setup_random_transform(transform, factor, nslices, 1.0) # Sum of absolute differences start_sad = np.abs(static - moving).sum() metric = None x0 = None sigmas = None scale_factors = None level_iters = None static_grid2world = None moving_grid2world = None for ss_sigma_factor in [1.0, None]: affreg = imaffine.AffineRegistration(metric, level_iters, sigmas, scale_factors, 'L-BFGS-B', ss_sigma_factor, options=None) affine_map = affreg.optimize(static, moving, transform, x0, static_grid2world, moving_grid2world, starting_affine) transformed = affine_map.transform(moving) # Sum of absolute differences end_sad = np.abs(static - transformed).sum() reduction = 1 - end_sad / start_sad print("%s>>%f" % (ttype, reduction)) assert (reduction > 0.9) transformed_inv = affine_map.transform_inverse(static) # Sum of absolute differences end_sad = np.abs(moving - transformed_inv).sum() reduction = 1 - end_sad / start_sad print("%s>>%f" % (ttype, reduction)) assert (reduction > 0.9)
def test_affreg_defaults(): # Test all default arguments with an arbitrary transform # Select an arbitrary transform (all of them are already tested # in test_affreg_all_transforms) transform_name = 'TRANSLATION' dim = 2 ttype = (transform_name, dim) aff_options = ['mass', 'voxel-origin', 'centers', None, np.eye(dim+1)] for starting_affine in aff_options: if dim == 2: nslices = 1 else: nslices = 45 factor = factors[ttype][0] sampling_pc = factors[ttype][1] transform = regtransforms[ttype] id_param = transform.get_identity_parameters() static, moving, static_grid2world, moving_grid2world, smask, mmask, T = \ setup_random_transform(transform, factor, nslices, 1.0) # Sum of absolute differences start_sad = np.abs(static - moving).sum() metric = None x0 = None sigmas = None scale_factors = None level_iters = None static_grid2world = None moving_grid2world = None for ss_sigma_factor in [1.0, None]: affreg = imaffine.AffineRegistration(metric, level_iters, sigmas, scale_factors, 'L-BFGS-B', ss_sigma_factor, options=None) affine_map = affreg.optimize(static, moving, transform, x0, static_grid2world, moving_grid2world, starting_affine) transformed = affine_map.transform(moving) # Sum of absolute differences end_sad = np.abs(static - transformed).sum() reduction = 1 - end_sad / start_sad print("%s>>%f"%(ttype, reduction)) assert(reduction > 0.9) transformed_inv = affine_map.transform_inverse(static) # Sum of absolute differences end_sad = np.abs(moving - transformed_inv).sum() reduction = 1 - end_sad / start_sad print("%s>>%f"%(ttype, reduction)) assert(reduction > 0.9)
def test_mi_gradient(): np.random.seed(2022966) # Test the gradient of mutual information h = 1e-5 # Make sure dictionary entries are processed in the same order regardless # of the platform. Otherwise any random numbers drawn within the loop would # make the test non-deterministic even if we fix the seed before the loop: # in this case the samples are drawn with `np.random.randn` below for ttype in sorted(factors): transform = regtransforms[ttype] dim = ttype[1] if dim == 2: nslices = 1 else: nslices = 45 factor = factors[ttype][0] sampling_proportion = factors[ttype][1] theta = factors[ttype][2] # Start from a small rotation start = regtransforms[('ROTATION', dim)] nrot = start.get_number_of_parameters() starting_affine = start.param_to_matrix(0.25 * np.random.randn(nrot)) # Get data (pair of images related to each other by an known transform) static, moving, static_g2w, moving_g2w, smask, mmask, M = \ setup_random_transform(transform, factor, nslices, 2.0) # Prepare a MutualInformationMetric instance mi_metric = imaffine.MutualInformationMetric(32, sampling_proportion) mi_metric.setup( transform, static, moving, starting_affine=starting_affine) # Compute the gradient with the implementation under test actual = mi_metric.gradient(theta) # Compute the gradient using finite-diferences n = transform.get_number_of_parameters() expected = np.empty(n, dtype=np.float64) val0 = mi_metric.distance(theta) for i in range(n): dtheta = theta.copy() dtheta[i] += h val1 = mi_metric.distance(dtheta) expected[i] = (val1 - val0) / h dp = expected.dot(actual) enorm = npl.norm(expected) anorm = npl.norm(actual) nprod = dp / (enorm * anorm) assert(nprod >= 0.99)
def test_affreg_all_transforms(): # Test affine registration using all transforms with typical settings # Make sure dictionary entries are processed in the same order regardless # of the platform. # Otherwise any random numbers drawn within the loop would make # the test non-deterministic even if we fix the seed before the loop. # Right now, this test does not draw any samples, # but we still sort the entries # to prevent future related failures. for ttype in sorted(factors): dim = ttype[1] if dim == 2: nslices = 1 else: nslices = 45 factor = factors[ttype][0] sampling_pc = factors[ttype][1] transform = regtransforms[ttype] static, moving, static_grid2world, moving_grid2world, smask, mmask, T = \ setup_random_transform(transform, factor, nslices, 1.0) # Sum of absolute differences start_sad = np.abs(static - moving).sum() metric = imaffine.MutualInformationMetric(32, sampling_pc) affreg = imaffine.AffineRegistration(metric, [1000, 100, 50], [3, 1, 0], [4, 2, 1], 'L-BFGS-B', None, options=None) x0 = transform.get_identity_parameters() affine_map = affreg.optimize(static, moving, transform, x0, static_grid2world, moving_grid2world) transformed = affine_map.transform(moving) # Sum of absolute differences end_sad = np.abs(static - transformed).sum() reduction = 1 - end_sad / start_sad print("%s>>%f" % (ttype, reduction)) assert(reduction > 0.9) # Verify that exception is raised if level_iters is empty metric = imaffine.MutualInformationMetric(32) assert_raises(ValueError, imaffine.AffineRegistration, metric, [])
def test_image_registration(): with TemporaryDirectory() as temp_out_dir: static, moving, static_g2w, moving_g2w, smask, mmask, M\ = setup_random_transform(transform=regtransforms[('AFFINE', 3)], rfactor=0.1) save_nifti(pjoin(temp_out_dir, 'b0.nii.gz'), data=static, affine=static_g2w) save_nifti(pjoin(temp_out_dir, 't1.nii.gz'), data=moving, affine=moving_g2w) static_image_file = pjoin(temp_out_dir, 'b0.nii.gz') moving_image_file = pjoin(temp_out_dir, 't1.nii.gz') image_registration_flow = ImageRegistrationFlow() def read_distance(qual_fname): temp_val = 0 with open(pjoin(temp_out_dir, qual_fname), 'r') as f: temp_val = f.readlines()[-1] return float(temp_val) def test_com(): out_moved = pjoin(temp_out_dir, "com_moved.nii.gz") out_affine = pjoin(temp_out_dir, "com_affine.txt") image_registration_flow._force_overwrite = True image_registration_flow.run(static_image_file, moving_image_file, transform='com', out_dir=temp_out_dir, out_moved=out_moved, out_affine=out_affine) check_existence(out_moved, out_affine) def test_translation(): out_moved = pjoin(temp_out_dir, "trans_moved.nii.gz") out_affine = pjoin(temp_out_dir, "trans_affine.txt") image_registration_flow._force_overwrite = True image_registration_flow.run(static_image_file, moving_image_file, transform='trans', out_dir=temp_out_dir, out_moved=out_moved, out_affine=out_affine, save_metric=True, level_iters=[100, 10, 1], out_quality='trans_q.txt') dist = read_distance('trans_q.txt') npt.assert_almost_equal(float(dist), -0.3953547764454917, 1) check_existence(out_moved, out_affine) def test_rigid(): out_moved = pjoin(temp_out_dir, "rigid_moved.nii.gz") out_affine = pjoin(temp_out_dir, "rigid_affine.txt") image_registration_flow._force_overwrite = True image_registration_flow.run(static_image_file, moving_image_file, transform='rigid', out_dir=temp_out_dir, out_moved=out_moved, out_affine=out_affine, save_metric=True, level_iters=[100, 10, 1], out_quality='rigid_q.txt') dist = read_distance('rigid_q.txt') npt.assert_almost_equal(dist, -0.6900534794005155, 1) check_existence(out_moved, out_affine) def test_rigid_isoscaling(): out_moved = pjoin(temp_out_dir, "rigid_isoscaling_moved.nii.gz") out_affine = pjoin(temp_out_dir, "rigid_isoscaling_affine.txt") image_registration_flow._force_overwrite = True image_registration_flow.run(static_image_file, moving_image_file, transform='rigid_isoscaling', out_dir=temp_out_dir, out_moved=out_moved, out_affine=out_affine, save_metric=True, level_iters=[100, 10, 1], out_quality='rigid_isoscaling_q.txt') dist = read_distance('rigid_isoscaling_q.txt') npt.assert_almost_equal(dist, -0.6960044668271375, 1) check_existence(out_moved, out_affine) def test_rigid_scaling(): out_moved = pjoin(temp_out_dir, "rigid_scaling_moved.nii.gz") out_affine = pjoin(temp_out_dir, "rigid_scaling_affine.txt") image_registration_flow._force_overwrite = True image_registration_flow.run(static_image_file, moving_image_file, transform='rigid_scaling', out_dir=temp_out_dir, out_moved=out_moved, out_affine=out_affine, save_metric=True, level_iters=[100, 10, 1], out_quality='rigid_scaling_q.txt') dist = read_distance('rigid_scaling_q.txt') npt.assert_almost_equal(dist, -0.698688892993124, 1) check_existence(out_moved, out_affine) def test_affine(): out_moved = pjoin(temp_out_dir, "affine_moved.nii.gz") out_affine = pjoin(temp_out_dir, "affine_affine.txt") image_registration_flow._force_overwrite = True image_registration_flow.run(static_image_file, moving_image_file, transform='affine', out_dir=temp_out_dir, out_moved=out_moved, out_affine=out_affine, save_metric=True, level_iters=[100, 10, 1], out_quality='affine_q.txt') dist = read_distance('affine_q.txt') npt.assert_almost_equal(dist, -0.7670650775914811, 1) check_existence(out_moved, out_affine) # Creating the erroneous behavior def test_err(): image_registration_flow._force_overwrite = True npt.assert_raises(ValueError, image_registration_flow.run, static_image_file, moving_image_file, transform='notransform') image_registration_flow._force_overwrite = True npt.assert_raises(ValueError, image_registration_flow.run, static_image_file, moving_image_file, metric='wrong_metric') def check_existence(movedfile, affine_mat_file): assert os.path.exists(movedfile) assert os.path.exists(affine_mat_file) return True test_com() test_translation() test_rigid() test_rigid_isoscaling() test_rigid_scaling() test_affine() test_err()
def test_apply_affine_transform(): with TemporaryDirectory() as temp_out_dir: factors = { ('TRANSLATION', 3): (2.0, None, np.array([2.3, 4.5, 1.7])), ('RIGID', 3): (0.1, None, np.array([0.1, 0.15, -0.11, 2.3, 4.5, 1.7])), ('RIGIDISOSCALING', 3): (0.1, None, np.array([0.1, 0.15, -0.11, 2.3, 4.5, 1.7, 0.8])), ('RIGIDSCALING', 3): (0.1, None, np.array([0.1, 0.15, -0.11, 2.3, 4.5, 1.7, 0.8, 0.9, 1.1])), ('AFFINE', 3): (0.1, None, np.array([ 0.99, -0.05, 0.03, 1.3, 0.05, 0.99, -0.10, 2.5, -0.07, 0.10, 0.99, -1.4 ])) } image_registration_flow = ImageRegistrationFlow() apply_trans = ApplyTransformFlow() for i in factors.keys(): static, moving, static_g2w, moving_g2w, smask, mmask, M = \ setup_random_transform(transform=regtransforms[i], rfactor=factors[i][0]) stat_file = str(i[0]) + '_static.nii.gz' mov_file = str(i[0]) + '_moving.nii.gz' save_nifti(pjoin(temp_out_dir, stat_file), data=static, affine=static_g2w) save_nifti(pjoin(temp_out_dir, mov_file), data=moving, affine=moving_g2w) static_image_file = pjoin(temp_out_dir, str(i[0]) + '_static.nii.gz') moving_image_file = pjoin(temp_out_dir, str(i[0]) + '_moving.nii.gz') out_moved = pjoin(temp_out_dir, str(i[0]) + "_moved.nii.gz") out_affine = pjoin(temp_out_dir, str(i[0]) + "_affine.txt") if str(i[0]) == "TRANSLATION": transform_type = "trans" elif str(i[0]) == "RIGIDISOSCALING": transform_type = "rigid_isoscaling" elif str(i[0]) == "RIGIDSCALING": transform_type = "rigid_scaling" else: transform_type = str(i[0]).lower() image_registration_flow.run(static_image_file, moving_image_file, transform=transform_type, out_dir=temp_out_dir, out_moved=out_moved, out_affine=out_affine, level_iters=[1, 1, 1], save_metric=False) # Checking for the created moved file. assert os.path.exists(out_moved) assert os.path.exists(out_affine) images = pjoin(temp_out_dir, '*moving*') apply_trans.run(static_image_file, images, out_dir=temp_out_dir, transform_map_file=out_affine) # Checking for the transformed file. assert os.path.exists(pjoin(temp_out_dir, "transformed.nii.gz"))
def test_image_registration(): with TemporaryDirectory() as temp_out_dir: static, moving, static_g2w, moving_g2w, smask, mmask, M\ = setup_random_transform(transform=regtransforms[('AFFINE', 3)], rfactor=0.1) save_nifti(pjoin(temp_out_dir, 'b0.nii.gz'), data=static, affine=static_g2w) save_nifti(pjoin(temp_out_dir, 't1.nii.gz'), data=moving, affine=moving_g2w) static_image_file = pjoin(temp_out_dir, 'b0.nii.gz') moving_image_file = pjoin(temp_out_dir, 't1.nii.gz') image_registeration_flow = ImageRegistrationFlow() def read_distance(qual_fname): temp_val = 0 with open(pjoin(temp_out_dir, qual_fname), 'r') as f: temp_val = f.readlines()[-1] return float(temp_val) def test_com(): out_moved = pjoin(temp_out_dir, "com_moved.nii.gz") out_affine = pjoin(temp_out_dir, "com_affine.txt") image_registeration_flow._force_overwrite = True image_registeration_flow.run(static_image_file, moving_image_file, transform='com', out_dir=temp_out_dir, out_moved=out_moved, out_affine=out_affine) check_existence(out_moved, out_affine) def test_translation(): out_moved = pjoin(temp_out_dir, "trans_moved.nii.gz") out_affine = pjoin(temp_out_dir, "trans_affine.txt") image_registeration_flow._force_overwrite = True image_registeration_flow.run(static_image_file, moving_image_file, transform='trans', out_dir=temp_out_dir, out_moved=out_moved, out_affine=out_affine, save_metric=True, level_iters=[100, 10, 1], out_quality='trans_q.txt') dist = read_distance('trans_q.txt') npt.assert_almost_equal(float(dist), -0.3953547764454917, 1) check_existence(out_moved, out_affine) def test_rigid(): out_moved = pjoin(temp_out_dir, "rigid_moved.nii.gz") out_affine = pjoin(temp_out_dir, "rigid_affine.txt") image_registeration_flow._force_overwrite = True image_registeration_flow.run(static_image_file, moving_image_file, transform='rigid', out_dir=temp_out_dir, out_moved=out_moved, out_affine=out_affine, save_metric=True, level_iters=[100, 10, 1], out_quality='rigid_q.txt') dist = read_distance('rigid_q.txt') npt.assert_almost_equal(dist, -0.6900534794005155, 1) check_existence(out_moved, out_affine) def test_affine(): out_moved = pjoin(temp_out_dir, "affine_moved.nii.gz") out_affine = pjoin(temp_out_dir, "affine_affine.txt") image_registeration_flow._force_overwrite = True image_registeration_flow.run(static_image_file, moving_image_file, transform='affine', out_dir=temp_out_dir, out_moved=out_moved, out_affine=out_affine, save_metric=True, level_iters=[100, 10, 1], out_quality='affine_q.txt') dist = read_distance('affine_q.txt') npt.assert_almost_equal(dist, -0.7670650775914811, 1) check_existence(out_moved, out_affine) # Creating the erroneous behavior def test_err(): image_registeration_flow._force_overwrite = True npt.assert_raises(ValueError, image_registeration_flow.run, static_image_file, moving_image_file, transform='notransform') image_registeration_flow._force_overwrite = True npt.assert_raises(ValueError, image_registeration_flow.run, static_image_file, moving_image_file, metric='wrong_metric') def check_existence(movedfile, affine_mat_file): assert os.path.exists(movedfile) assert os.path.exists(affine_mat_file) return True test_com() test_translation() test_rigid() test_affine() test_err()
def test_apply_affine_transform(): with TemporaryDirectory() as temp_out_dir: factors = { ('TRANSLATION', 3): (2.0, None, np.array([2.3, 4.5, 1.7])), ('RIGID', 3): (0.1, None, np.array([0.1, 0.15, -0.11, 2.3, 4.5, 1.7])), ('AFFINE', 3): (0.1, None, np.array([0.99, -0.05, 0.03, 1.3, 0.05, 0.99, -0.10, 2.5, -0.07, 0.10, 0.99, -1.4]))} image_registeration_flow = ImageRegistrationFlow() apply_trans = ApplyTransformFlow() for i in factors.keys(): static, moving, static_g2w, moving_g2w, smask, mmask, M = \ setup_random_transform(transform=regtransforms[i], rfactor=factors[i][0]) stat_file = str(i[0]) + '_static.nii.gz' mov_file = str(i[0]) + '_moving.nii.gz' save_nifti(pjoin(temp_out_dir, stat_file), data=static, affine=static_g2w) save_nifti(pjoin(temp_out_dir, mov_file), data=moving, affine=moving_g2w) static_image_file = pjoin(temp_out_dir, str(i[0]) + '_static.nii.gz') moving_image_file = pjoin(temp_out_dir, str(i[0]) + '_moving.nii.gz') out_moved = pjoin(temp_out_dir, str(i[0]) + "_moved.nii.gz") out_affine = pjoin(temp_out_dir, str(i[0]) + "_affine.txt") if str(i[0]) == "TRANSLATION": transform_type = "trans" else: transform_type = str(i[0]).lower() image_registeration_flow.run(static_image_file, moving_image_file, transform=transform_type, out_dir=temp_out_dir, out_moved=out_moved, out_affine=out_affine, level_iters=[1, 1, 1], save_metric=False) # Checking for the created moved file. assert os.path.exists(out_moved) assert os.path.exists(out_affine) images = pjoin(temp_out_dir, '*moving*') apply_trans.run(static_image_file, images, out_dir=temp_out_dir, transform_map_file=out_affine) # Checking for the transformed file. assert os.path.exists(pjoin(temp_out_dir, "transformed.nii.gz"))