Skip to content

Commit

Permalink
Upload CT_2D images and adjust tests
Browse files Browse the repository at this point in the history
Signed-off-by: Felix Schnabel <[email protected]>
  • Loading branch information
Shadow-Devil committed Jan 29, 2023
1 parent ce4fef5 commit e4b89cf
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 58 deletions.
14 changes: 7 additions & 7 deletions monai/data/itk_torch_affine_matrix_bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
]


# TODO remove
def metatensor_to_array(metatensor: MetaTensor):
metatensor = metatensor.squeeze()
metatensor = metatensor.permute(*torch.arange(metatensor.ndim - 1, -1, -1))
Expand Down Expand Up @@ -106,8 +107,7 @@ def itk_to_monai_affine(image, matrix, translation, center_of_rotation=None) ->
Converts an ITK affine matrix (2x2 for 2D or 3x3 for 3D matrix and translation vector) to a MONAI affine matrix.
Args:
image: The ITK image object. This is used to extract the spacing and
direction information.
image: The ITK image object. This is used to extract the spacing and direction information.
matrix: The 2x2 or 3x3 ITK affine matrix.
translation: The 2-element or 3-element ITK affine translation vector.
center_of_rotation: The center of rotation. If provided, the affine
Expand Down Expand Up @@ -150,8 +150,7 @@ def monai_to_itk_affine(image, affine_matrix, center_of_rotation=None):
3D matrix and translation vector). See also 'itk_to_monai_affine'.
Args:
image: The ITK image object. This is used to extract the spacing and
direction information.
image: The ITK image object. This is used to extract the spacing and direction information.
affine_matrix: The 3x3 for 2D or 4x4 for 3D MONAI affine matrix.
center_of_rotation: The center of rotation. If provided, the affine
matrix will be adjusted to account for the difference
Expand Down Expand Up @@ -208,8 +207,7 @@ def create_itk_affine_from_parameters(
Args:
image: The ITK image.
translation: The translation (shift) to apply to the image.
rotation: The rotation to apply to the image, specified as angles in radians
around the x, y, and z axes.
rotation: The rotation to apply to the image, specified as angles in radians around the x, y, and z axes.
scale: The scaling factor to apply to the image.
shear: The shear to apply to the image.
center_of_rotation: The center of rotation for the image. If not specified,
Expand Down Expand Up @@ -279,7 +277,9 @@ def itk_affine_resample(image, matrix, translation, center_of_rotation=None):


def monai_affine_resample(metatensor: MetaTensor, affine_matrix: NdarrayOrTensor):
# TODO documentation
# TODO documentation, change to mode=3
#affine = Affine(affine=affine_matrix, mode=3, padding_mode='mirror', dtype=torch.float64, image_only=True)
#output_tensor = cast(MetaTensor, affine(metatensor))
affine = Affine(affine=affine_matrix, padding_mode="zeros", dtype=torch.float64, image_only=True)
output_tensor = cast(MetaTensor, affine(metatensor, mode="bilinear"))

Expand Down
96 changes: 45 additions & 51 deletions tests/test_itk_torch_affine_matrix_bridge.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,37 +33,40 @@
monai_to_itk_affine,
)

TEST_CASES = [
TESTS = [
"CT_2D_head_fixed.mha",
"CT_2D_head_moving.mha",
#"copd1_highres_INSP_STD_COPD_img.nii.gz"
]
# Download URL: https://data.kitware.com/api/v1/file/62a0f067bddec9d0c4175c5a/download
# Download URL:
# SHA-521: 60193cd6ef0cf055c623046446b74f969a2be838444801bd32ad5bedc8a7eeecb343e8a1208769c9c7a711e101c806a3133eccdda7790c551a69a64b9b3701e9
#TEST_CASE_3D = {"filepath": "copd1_highres_INSP_STD_COPD_img.nii.gz"}
#TEST_CASE_3D_1 = [
# "copd1_highres_INSP_STD_COPD_img.nii.gz" # https://data.kitware.com/api/v1/file/62a0f067bddec9d0c4175c5a/download
# "copd1_highres_INSP_STD_COPD_img.nii.gz" # https://data.kitware.com/api/v1/item/62a0f045bddec9d0c4175c44/download
# ]



@unittest.skipUnless(has_itk, "Requires `itk` package.")
class TestITKTorchAffineMatrixBridge(unittest.TestCase):
def setUp(self):
# TODO: which data should be used
self.data_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), "testing_data")
self.reader = ITKReader(pixel_type=itk.F)
#data_dir = os.path.join(self.data_dir, "MedNIST")
#dataset_file = os.path.join(self.data_dir, "MedNIST.tar.gz")
#
#if not os.path.exists(data_dir):
# with skip_if_downloading_fails():
# data_spec = testing_data_config("images", "mednist")
# download_and_extract(
# data_spec["url"],
# dataset_file,
# self.data_dir,
# hash_val=data_spec["hash_val"],
# hash_type=data_spec["hash_type"],
# )

@parameterized.expand(TEST_CASES)
self.reader = ITKReader()

#for filepath in TEST_CASES:
# if not os.path.exists(os.path.join(self.data_dir, filepath)):
# with skip_if_downloading_fails():
# data_spec = testing_data_config("images", filepath)
# download_and_extract(
# data_spec["url"],
# filepath,
# self.data_dir,
# #hash_val=data_spec["hash_val"],
# #hash_type=data_spec["hash_type"],
# )

@parameterized.expand(TESTS)
def test_setting_affine_parameters(self, filepath):
# Read image
image = self.reader.read(os.path.join(self.data_dir, filepath))
Expand Down Expand Up @@ -91,10 +94,18 @@ def test_setting_affine_parameters(self, filepath):
###########################################################################
# Make sure that the array conversion of the inputs is the same
input_array_monai = metatensor_to_array(metatensor)
assert np.array_equal(input_array_monai, np.asarray(image))
#output_array_monai = ITKWriter.create_backend_obj(
# metatensor.array,
# channel_dim=None,
# affine=affine_matrix_for_monai,
# affine_lps_to_ras=False, # False if the affine is in itk convention
#)
np.testing.assert_array_equal(input_array_monai, np.asarray(image))

# Compare outputs
print("MONAI-ITK: ", np.allclose(output_array_monai, output_array_itk))
percentage = 100 * np.isclose(output_array_monai, output_array_itk).sum() / output_array_itk.size
print("MONAI equals result: ", percentage, "%")
self.assertGreaterEqual(percentage, 99.0)

diff_output = output_array_monai - output_array_itk
print(f"[Min, Max] MONAI: [{output_array_monai.min()}, {output_array_monai.max()}]")
Expand All @@ -107,7 +118,7 @@ def test_setting_affine_parameters(self, filepath):
# itk.imwrite(itk.GetImageFromArray(output_array_itk), "./output/output_itk.tif")
###########################################################################

@parameterized.expand(TEST_CASES)
@parameterized.expand(TESTS)
def test_arbitary_center_of_rotation(self, filepath):
# Read image
image = self.reader.read(os.path.join(self.data_dir, filepath))
Expand Down Expand Up @@ -141,19 +152,21 @@ def test_arbitary_center_of_rotation(self, filepath):

# Make sure that the array conversion of the inputs is the same
input_array_monai = metatensor_to_array(metatensor)
assert np.array_equal(input_array_monai, np.asarray(image))
np.testing.assert_array_equal(input_array_monai, np.asarray(image))

###########################################################################
# Compare outputs
print("MONAI-ITK: ", np.allclose(output_array_monai, output_array_itk))
percentage = 100 * np.isclose(output_array_monai, output_array_itk).sum() / output_array_itk.size
print("MONAI equals result: ", percentage, "%")
self.assertGreaterEqual(percentage, 99.0)

diff_output = output_array_monai - output_array_itk
print(f"[Min, Max] MONAI: [{output_array_monai.min()}, {output_array_monai.max()}]")
print(f"[Min, Max] ITK: [{output_array_itk.min()}, {output_array_itk.max()}]")
print(f"[Min, Max] diff: [{diff_output.min()}, {diff_output.max()}]")
###########################################################################

@parameterized.expand(TEST_CASES)
@parameterized.expand(TESTS)
def test_monai_to_itk(self, filepath):
print("\nTEST: MONAI affine matrix -> ITK matrix + translation vector -> transform")
# Read image
Expand Down Expand Up @@ -192,19 +205,21 @@ def test_monai_to_itk(self, filepath):

# Make sure that the array conversion of the inputs is the same
input_array_monai = metatensor_to_array(metatensor)
assert np.array_equal(input_array_monai, np.asarray(image))
np.testing.assert_array_equal(input_array_monai, np.asarray(image))

###########################################################################
# Compare outputs
print("MONAI-ITK: ", np.allclose(output_array_monai, output_array_itk))
percentage = 100 * np.isclose(output_array_monai, output_array_itk).sum() / output_array_itk.size
print("MONAI equals result: ", percentage, "%")
self.assertGreaterEqual(percentage, 99.0)

diff_output = output_array_monai - output_array_itk
print(f"[Min, Max] MONAI: [{output_array_monai.min()}, {output_array_monai.max()}]")
print(f"[Min, Max] ITK: [{output_array_itk.min()}, {output_array_itk.max()}]")
print(f"[Min, Max] diff: [{diff_output.min()}, {diff_output.max()}]")
###########################################################################

@parameterized.expand(TEST_CASES)
@parameterized.expand(TESTS)
def test_cyclic_conversion(self, filepath):
image = self.reader.read(os.path.join(self.data_dir, filepath))
ndim = image.ndim
Expand Down Expand Up @@ -232,30 +247,9 @@ def test_cyclic_conversion(self, filepath):

matrix_result, translation_result = monai_to_itk_affine(image, affine_matrix, center_of_rotation)

print("Matrix cyclic conversion: ", np.allclose(matrix, matrix_result))
print("Translation cyclic conversion: ", np.allclose(translation, translation_result))
np.testing.assert_allclose(matrix, matrix_result)
np.testing.assert_allclose(translation, translation_result)


if __name__ == "__main__":

# test_utils.download_test_data()

## 2D cases
# filepath0 = str(test_utils.TEST_DATA_DIR / 'CT_2D_head_fixed.mha')
# filepath1 = str(test_utils.TEST_DATA_DIR / 'CT_2D_head_moving.mha')
#
# test_setting_affine_parameters(filepath=filepath0)
# test_arbitary_center_of_rotation(filepath=filepath0)
# test_monai_to_itk(filepath=filepath0)
# test_cyclic_conversion(filepath=filepath0)
#
## 3D cases
# filepath2 = str(test_utils.TEST_DATA_DIR / 'copd1_highres_INSP_STD_COPD_img.nii.gz')
# filepath3 = str(test_utils.TEST_DATA_DIR / 'copd1_highres_EXP_STD_COPD_img.nii.gz')
#
# test_setting_affine_parameters(filepath=filepath2)
# test_arbitary_center_of_rotation(filepath=filepath2)
# test_monai_to_itk(filepath=filepath2)
# test_cyclic_conversion(filepath=filepath2)

unittest.main()
Binary file added tests/testing_data/CT_2D_head_fixed.mha
Binary file not shown.
Binary file added tests/testing_data/CT_2D_head_moving.mha
Binary file not shown.

0 comments on commit e4b89cf

Please sign in to comment.