From 785e93d1a79a468269ff650ad0a434396aed212f Mon Sep 17 00:00:00 2001 From: Philip Cook Date: Sun, 2 Mar 2025 16:19:10 -0500 Subject: [PATCH 1/2] ENH: More label_geometry_measures tests --- tests/test_segmentation.py | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/tests/test_segmentation.py b/tests/test_segmentation.py index cfc105a2..127afc7b 100644 --- a/tests/test_segmentation.py +++ b/tests/test_segmentation.py @@ -177,9 +177,27 @@ def tearDown(self): pass def test_example(self): - fi = ants.image_read( ants.get_ants_data('r16') ) + fi = ants.resample_image(ants.image_read( ants.get_ants_data('r16') ), (140,140),1,0) seg = ants.kmeans_segmentation( fi, 3 )['segmentation'] geom = ants.label_geometry_measures(seg,fi) + expected_cols = ['Label', 'VolumeInVoxels', 'VolumeInMillimeters', + 'SurfaceAreaInMillimetersSquared', 'Eccentricity', 'Elongation', + 'Roundness', 'Flatness', 'Centroid_x', 'Centroid_y', 'AxesLength_x', + 'AxesLength_y', 'BoundingBoxLower_x', 'BoundingBoxLower_y', + 'BoundingBoxUpper_x', 'BoundingBoxUpper_y', 'MeanIntensity', + 'SigmaIntensity', 'MinIntensity', 'MaxIntensity', + 'IntegratedIntensity'] + for col in expected_cols: + self.assertTrue(col in geom.columns) + # Label column should have int type + self.assertTrue(np.issubdtype(geom['Label'].dtype, np.integer)) + # So should VolumeInVoxels + self.assertTrue(np.issubdtype(geom['VolumeInVoxels'].dtype, np.integer)) + # Check math of VolumeInMillimeters + self.assertTrue(np.allclose(geom['VolumeInMillimeters'], geom['VolumeInVoxels'] * np.prod(fi.spacing), atol=1e-6)) + # should be three rows + self.assertEqual(geom.shape[0], 3) + class TestModule_prior_based_segmentation(unittest.TestCase): @@ -198,7 +216,7 @@ def test_example(self): class TestModule_random(unittest.TestCase): - + def setUp(self): pass def tearDown(self): @@ -208,7 +226,7 @@ def test_fuzzy_cmeans(self): image = ants.image_read(ants.get_ants_data('r16')) mask = ants.get_mask(image) fuzzy = ants.fuzzy_spatial_cmeans_segmentation(image, mask, number_of_clusters=3) - + def test_functional_lung(self): image = ants.image_read(ants.get_data("mni")).resample_image((4,4,4)) mask = image.get_mask() @@ -216,7 +234,7 @@ def test_functional_lung(self): number_of_iterations=1, number_of_clusters=2, number_of_atropos_iterations=1) - + def test_anti_alias(self): img = ants.image_read(ants.get_data('r16')) mask = ants.get_mask(img) From 120428fff55544aefeb212b1e9fa58cd829144d4 Mon Sep 17 00:00:00 2001 From: Philip Cook Date: Mon, 3 Mar 2025 09:09:27 -0500 Subject: [PATCH 2/2] ENH: Check label geometry return type for problems --- ants/label/label_geometry_measures.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/ants/label/label_geometry_measures.py b/ants/label/label_geometry_measures.py index 00f2ceb8..0dcfae20 100644 --- a/ants/label/label_geometry_measures.py +++ b/ants/label/label_geometry_measures.py @@ -33,7 +33,6 @@ def label_geometry_measures(label_image, intensity_image=None): >>> seg = ants.kmeans_segmentation( fi, 3 )['segmentation'] >>> geom = ants.label_geometry_measures(seg,fi) """ - import numpy as np if intensity_image is None: intensity_image = label_image.clone() @@ -49,9 +48,11 @@ def label_geometry_measures(label_image, intensity_image=None): libfn = get_lib_fn('LabelGeometryMeasures') pp = libfn(veccer_processed) pp = pd.read_csv(outcsv) - import numpy as np - # pp['Label'] = np.sort(np.unique(label_image[label_image>0])).astype('int') if 'VolumeInVoxels' in pp.columns and not 'VolumeInMillimeters' in pp.columns: spc = np.prod(label_image.spacing) pp['VolumeInMillimeters'] = pp['VolumeInVoxels'] * spc + # Ensure that the label column is of integer type - if there is any NaN, it will be float + # Something has gone seriously wrong if the labels are not interpreted as integers + if not np.issubdtype(pp['Label'].dtype, np.integer): + raise ValueError('Label column not integer type, label values may be invalid') return pp