From ffafc3b7362d921f676d18c75824f39b9a702ec1 Mon Sep 17 00:00:00 2001 From: Leonid Kostrykin Date: Tue, 16 Jul 2024 11:24:05 +0000 Subject: [PATCH 1/2] Add `util.convert_image_to_format_of` and tests --- giatools/__init__.py | 2 +- giatools/util.py | 43 +++++++++++++++++++++++++++++++++++++++++++ tests/test_util.py | 37 +++++++++++++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 giatools/util.py create mode 100644 tests/test_util.py diff --git a/giatools/__init__.py b/giatools/__init__.py index 2b20056..76a9a9b 100644 --- a/giatools/__init__.py +++ b/giatools/__init__.py @@ -1,6 +1,6 @@ VERSION_MAJOR = 0 VERSION_MINOR = 1 -VERSION_PATCH = 1 +VERSION_PATCH = 2 VERSION = '%d.%d%s' % (VERSION_MAJOR, VERSION_MINOR, '.%d' % VERSION_PATCH if VERSION_PATCH > 0 else '') diff --git a/giatools/util.py b/giatools/util.py new file mode 100644 index 0000000..36d54b9 --- /dev/null +++ b/giatools/util.py @@ -0,0 +1,43 @@ +""" +Copyright 2017-2024 Leonid Kostrykin, Biomedical Computer Vision Group, Heidelberg University. + +Distributed under the MIT license. +See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +""" + +import numpy as np +import skimage.util + + +def convert_image_to_format_of(image, format_image): + """ + Convert the first image to the format of the second image. + """ + + # There is nothing to do with the image if the formats match. + if format_image.dtype == image.dtype: + return image + + # Convert the image to uint8 if this is the format of the second image. + elif format_image.dtype == np.uint8: + return skimage.util.img_as_ubyte(image) + + # Convert the image to uint16 if this is the format of the second image. + elif format_image.dtype == np.uint16: + return skimage.util.img_as_uint(image) + + # Convert the image to int16 if this is the format of the second image. + elif format_image.dtype == np.int16: + return skimage.util.img_as_int(image) + + # Convert the image to float32 if this is the format of the second image. + elif format_image.dtype == np.float32: + return skimage.util.img_as_float32(image) + + # Convert the image to float64 if this is the format of the second image. + elif format_image.dtype == np.float64: + return skimage.util.img_as_float64(image) + + # Other formats are not supported yet (e.g., float16). + else: + raise ValueError(f'Unsupported image data type: {format_image.dtype}') diff --git a/tests/test_util.py b/tests/test_util.py new file mode 100644 index 0000000..ca741d9 --- /dev/null +++ b/tests/test_util.py @@ -0,0 +1,37 @@ +import unittest +import numpy as np +import skimage.util +import giatools.util + + +class convert_image_to_format_of(unittest.TestCase): + + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + np.random.seed(0) + img_float = np.random.rand(16, 16) + self.testdata = { + 'uint8': skimage.util.img_as_ubyte(img_float), + 'uint16': skimage.util.img_as_uint(img_float), + 'int16': skimage.util.img_as_int(img_float), + 'float32': skimage.util.img_as_float32(img_float), + 'float64': skimage.util.img_as_float64(img_float), + } + + def test_self_conversion(self): + for dtype, img in self.testdata.items(): + actual = giatools.util.convert_image_to_format_of(img, img) + self.assertIs(actual, img) + self.assertEqual(actual.dtype, getattr(np, dtype)) + + def test_cross_conversion(self): + for src_dtype, src_img in self.testdata.items(): + for dst_img in self.testdata.values(): + with self.subTest(src_dtype=src_dtype, dst_dtype=dst_img.dtype): + actual = giatools.util.convert_image_to_format_of(src_img, dst_img) + self.assertTrue(np.allclose(actual, dst_img)) + self.assertEqual(actual.dtype, dst_img.dtype) + + +if __name__ == '__main__': + unittest.main() From 473c8823f10dd082bf9d1d1faa223ae336d7d2c6 Mon Sep 17 00:00:00 2001 From: Leonid Kostrykin Date: Tue, 16 Jul 2024 11:48:16 +0000 Subject: [PATCH 2/2] Fix tests --- tests/test_io.py | 1 + tests/test_util.py | 33 +++++++++++++++++---------------- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/tests/test_io.py b/tests/test_io.py index 4c23b4c..61bb0ed 100644 --- a/tests/test_io.py +++ b/tests/test_io.py @@ -1,4 +1,5 @@ import unittest + import giatools.io diff --git a/tests/test_util.py b/tests/test_util.py index ca741d9..c0ee4cf 100644 --- a/tests/test_util.py +++ b/tests/test_util.py @@ -1,6 +1,9 @@ +import itertools import unittest + import numpy as np import skimage.util + import giatools.util @@ -9,28 +12,26 @@ class convert_image_to_format_of(unittest.TestCase): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) np.random.seed(0) - img_float = np.random.rand(16, 16) - self.testdata = { - 'uint8': skimage.util.img_as_ubyte(img_float), - 'uint16': skimage.util.img_as_uint(img_float), - 'int16': skimage.util.img_as_int(img_float), - 'float32': skimage.util.img_as_float32(img_float), - 'float64': skimage.util.img_as_float64(img_float), - } + img_uint8 = (np.random.rand(16, 16) * 255).round().astype(np.uint8) + self.testdata = [ + skimage.util.img_as_ubyte(img_uint8), # uint8 + skimage.util.img_as_uint(img_uint8), # uint16 + skimage.util.img_as_int(img_uint8), # int16 + skimage.util.img_as_float32(img_uint8), # float32 + skimage.util.img_as_float64(img_uint8), # float64 + ] def test_self_conversion(self): - for dtype, img in self.testdata.items(): + for img in self.testdata: actual = giatools.util.convert_image_to_format_of(img, img) self.assertIs(actual, img) - self.assertEqual(actual.dtype, getattr(np, dtype)) def test_cross_conversion(self): - for src_dtype, src_img in self.testdata.items(): - for dst_img in self.testdata.values(): - with self.subTest(src_dtype=src_dtype, dst_dtype=dst_img.dtype): - actual = giatools.util.convert_image_to_format_of(src_img, dst_img) - self.assertTrue(np.allclose(actual, dst_img)) - self.assertEqual(actual.dtype, dst_img.dtype) + for src_img, dst_img in itertools.product(self.testdata, self.testdata): + with self.subTest(f'{src_img.dtype} -> {dst_img.dtype}'): + actual = giatools.util.convert_image_to_format_of(src_img, dst_img) + self.assertEqual(actual.dtype, dst_img.dtype) + self.assertTrue(np.allclose(actual, dst_img, rtol=1e-2)) if __name__ == '__main__':