From 0796515a1cf2fad110e6fcd8a7d5f372be47fade Mon Sep 17 00:00:00 2001 From: Philip Cook Date: Mon, 20 May 2024 11:41:31 -0400 Subject: [PATCH] ENH: Threshold mask in images_to_matrix Also add some more tests --- ants/utils/matrix_image.py | 12 +++++++----- tests/test_core_ants_image_io.py | 15 +++++++++++---- tests/test_registration.py | 15 ++++++++------- 3 files changed, 26 insertions(+), 16 deletions(-) diff --git a/ants/utils/matrix_image.py b/ants/utils/matrix_image.py index 32f45c1f..cd02cb45 100644 --- a/ants/utils/matrix_image.py +++ b/ants/utils/matrix_image.py @@ -123,13 +123,14 @@ def images_to_matrix(image_list, mask=None, sigma=None, epsilon=0.5): images to convert to ndarray mask : ANTsImage (optional) - image containing binary mask. voxels in the mask are placed in the matrix + Mask image, voxels in the mask (>= epsilon) are placed in the matrix. If None, + the first image in image_list is thresholded at its mean value to create a mask. sigma : scaler (optional) smoothing factor epsilon : scalar - threshold for mask + threshold for mask, values >= epsilon are included in the mask. Returns ------- @@ -149,6 +150,7 @@ def images_to_matrix(image_list, mask=None, sigma=None, epsilon=0.5): mask = ants.get_mask(image_list[0]) num_images = len(image_list) + mask_thresh = mask.clone() >= epsilon mask_arr = mask.numpy() >= epsilon num_voxels = np.sum(mask_arr) @@ -157,9 +159,9 @@ def images_to_matrix(image_list, mask=None, sigma=None, epsilon=0.5): for i, img in enumerate(image_list): if do_smooth: img = ants.smooth_image(img, sigma, sigma_in_physical_coordinates=True) - if np.sum(np.array(img.shape) - np.array(mask.shape)) != 0: - img = ants.resample_image_to_target(img, mask, 2) - data_matrix[i, :] = img[mask] + if np.sum(np.array(img.shape) - np.array(mask_thresh.shape)) != 0: + img = ants.resample_image_to_target(img, mask_thresh, 2) + data_matrix[i, :] = img[mask_thresh] return data_matrix diff --git a/tests/test_core_ants_image_io.py b/tests/test_core_ants_image_io.py index 01607864..3f9ec44b 100644 --- a/tests/test_core_ants_image_io.py +++ b/tests/test_core_ants_image_io.py @@ -164,6 +164,7 @@ def test_images_to_matrix(self): imgmat = ants.images_to_matrix(imglist, mask=mask) self.assertTrue(imgmat.shape[0] == len(imglist)) self.assertTrue(imgmat.shape[1] == (mask>0).sum()) + self.assertTrue(np.allclose(img[mask], imgmat[0,:])) # go back to images imglist2 = ants.matrix_to_images(imgmat, mask) @@ -178,20 +179,26 @@ def test_images_to_matrix(self): imgmat = ants.images_to_matrix(imglist, mask=mask, sigma=2.) # with no mask - mask = ants.image_clone( img > img.mean(), pixeltype = 'float' ) - imglist = [img.clone(),img.clone(),img.clone()] imgmat = ants.images_to_matrix(imglist) + # Mask not binary + mask = ants.image_clone( img / img.mean(), pixeltype = 'float' ) + imgmat = ants.images_to_matrix(imglist, mask=mask, epsilon=1) + # with mask of different shape s = [65]*img.dimension - mask2 = ants.from_numpy(np.random.randn(*s)) + mask2 = ants.from_numpy(np.random.randn(*s), spacing=[4.0, 4.0]) mask2 = mask2 > mask2.mean() imgmat = ants.images_to_matrix(imglist, mask=mask2) + self.assertTrue(imgmat.shape[0] == len(imglist)) + self.assertTrue(imgmat.shape[1] == (mask2>0).sum()) + + def timeseries_to_matrix(self): img = ants.make_image( (10,10,10,5 ) ) mat = ants.timeseries_to_matrix( img ) - + img = ants.make_image( (10,10,10,5 ) ) mask = ants.ndimage_to_list( img )[0] * 0 mask[ 4:8, 4:8, 4:8 ] = 1 diff --git a/tests/test_registration.py b/tests/test_registration.py index f0b4c550..bc50a9cb 100644 --- a/tests/test_registration.py +++ b/tests/test_registration.py @@ -292,7 +292,7 @@ def test_resample_image_example(self): fi = ants.image_read(ants.get_ants_data("r16")) finn = ants.resample_image(fi, (50, 60), True, 0) filin = ants.resample_image(fi, (1.5, 1.5), False, 1) - + def test_resample_channels(self): img = ants.image_read( ants.get_ants_data("r16")) img = ants.merge_channels([img, img]) @@ -304,6 +304,7 @@ def test_resample_image_to_target_example(self): fi = ants.image_read(ants.get_ants_data("r16")) fi2mm = ants.resample_image(fi, (2, 2), use_voxels=0, interp_type=1) resampled = ants.resample_image_to_target(fi2mm, fi, verbose=True) + self.assertTrue(ants.image_physical_space_consistency(fi, resampled, 0.0001, datatype=True)) class TestModule_symmetrize_image(unittest.TestCase): @@ -365,7 +366,7 @@ def setUp(self): def tearDown(self): pass - + def test_landmark_transforms(self): fixed = np.array([[50.0,50.0],[200.0,50.0],[200.0,200.0]]) moving = np.array([[50.0,50.0],[50.0,200.0],[200.0,200.0]]) @@ -381,10 +382,10 @@ def test_landmark_transforms(self): xfrm = ants.fit_transform_to_paired_points(moving, fixed, transform_type="bspline", domain_image=domain_image, number_of_fitting_levels=5) xfrm = ants.fit_transform_to_paired_points(moving, fixed, transform_type="diffeo", domain_image=domain_image, number_of_fitting_levels=6) - res = ants.fit_time_varying_transform_to_point_sets([fixed, moving, moving], + res = ants.fit_time_varying_transform_to_point_sets([fixed, moving, moving], domain_image=ants.image_read(ants.get_data('r16')), verbose=True) - + def test_deformation_gradient(self): fi = ants.image_read( ants.get_ants_data('r16')) mi = ants.image_read( ants.get_ants_data('r64')) @@ -392,16 +393,16 @@ def test_deformation_gradient(self): mi = ants.resample_image(mi,(128,128),1,0) mytx = ants.registration(fixed=fi , moving=mi, type_of_transform = ('SyN') ) dg = ants.deformation_gradient( ants.image_read( mytx['fwdtransforms'][0] ) ) - + dg = ants.deformation_gradient( ants.image_read( mytx['fwdtransforms'][0] ), py_based=True) dg = ants.deformation_gradient( ants.image_read( mytx['fwdtransforms'][0] ), to_rotation=True) - + dg = ants.deformation_gradient( ants.image_read( mytx['fwdtransforms'][0] ), to_rotation=True, py_based=True) - + def test_jacobian(self): fi = ants.image_read( ants.get_ants_data('r16')) mi = ants.image_read( ants.get_ants_data('r64'))