How would you check that the “actual” output image of a filter is equal to the “excepted” image, in a Python unit test? Is there a helper function, like assert_equal_image(actual_image, expected_image)? I tried the following:
class MyTestCase(unittest.TestCase):
def _assert_equal_image(self, actual_image, expected_image) -> None:
"""Asserts that the actual image is equal to the expected one."""
self.assertTrue(actual_image.IsSameImageGeometryAs(expected_image))
self.assertEqual(
actual_image.GetBufferedRegion(), expected_image.GetBufferedRegion()
)
region = expected_image.GetBufferedRegion()
region_index = region.GetIndex()
region_size = region.GetSize()
for pixel_index in itertools.product(
range(region_index[0], region_index[0] + region_size[0]),
range(region_index[1], region_index[1] + region_size[1]),
):
self.assertEqual(
actual_image.GetPixel(pixel_index), expected_image.GetPixel(pixel_index)
)
My attempt may be nice (hopefully), but it isn’t complete (no 3D support yet, for example), and I’m afraid of re-inventing the wheel… any suggestion?
Thank you very much @phcerdan So something like this, right?
def _assert_equal_image(self, actual_image, expected_image) -> None:
"""Asserts that the actual image is equal to the expected one."""
self.assertTrue(actual_image.IsSameImageGeometryAs(expected_image))
np.testing.assert_array_equal(
actual=itk.array_view_from_image(actual_image),
desired=itk.array_view_from_image(expected_image),
strict=True,
)
Thanks @dzenanz Would comparison just be the difference, or the absolute difference of the two images?
If itk.comparison_image_filter creates a new image, I guess it’s more expensive than calling np.testing.assert_array_equal on the views returned by itk.array_view_from_image (as was suggested by @phcerdan), right?
Thanks for the link! I see, the documentation does not say that the image created by ComparisonImageFilter has absolute values. While this is essential if you want to do np.sum(comparison).
If all you need is exact comparison then you may want to look at the HashImageFilter. This filter generates an MD5 hash from the image’s buffer which can be used for efficient comparison.
Nice suggestion, thank Bradley. I guess such hash values would especially be useful when having large test images.
For unit tests, I would prefer to use small images, when possible, having around 16x16 pixels, for example. So for such small images, a simple straightforward “assert_array_equal” on the pixel data should be just fine, in my opinion.
I think it would be nice if itk.Image would support value-based equality comparison by image1 == image2. Just like Python lists:
There is ambiguity on if these comparison operators should be “broadcast” per pixel, or comparison on the whole image. Numpy has the following:
In [2]: a = np.array(range(4)); b = np.array(range(4))
In [3]: a == b
Out[3]: array([ True, True, True, True])
SimpleITK has these comparison operators overloaded as well. You can experiment with them there as well. In C++ they are an “optional” header, and work well with the move operator too.