Skip to content

Commit

Permalink
Add test case for spacing/resolution metadata
Browse files Browse the repository at this point in the history
Signed-off-by: Gigon Bae <gbae@nvidia.com>
  • Loading branch information
gigony committed Jul 29, 2022
1 parent 13c11a4 commit f56a4cf
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 9 deletions.
49 changes: 45 additions & 4 deletions python/cucim/tests/fixtures/testimage.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@
from ..util.gen_image import ImageGenerator


def gen_image(tmpdir_factory, recipe):
def gen_image(tmpdir_factory, recipe, resolution=None):
dataset_path = tmpdir_factory.mktemp('datasets').strpath
dataset_gen = ImageGenerator(dataset_path, [recipe])
dataset_gen = ImageGenerator(dataset_path, [recipe], [resolution])
image_path = dataset_gen.gen()
return (dataset_path, image_path[0])

Expand Down Expand Up @@ -63,9 +63,8 @@ def testimg_tiff_stripe_32x24_16_raw(tmpdir_factory):
def testimg_tiff_stripe_32x24_16(request):
return request.param

# tiff_stripe_4096x4096_256


# tiff_stripe_4096x4096_256
@pytest.fixture(scope='session')
def testimg_tiff_stripe_4096x4096_256_jpeg(tmpdir_factory):
dataset_path, image_path = gen_image(
Expand Down Expand Up @@ -137,3 +136,45 @@ def testimg_tiff_stripe_100000x100000_256_raw(tmpdir_factory):
])
def testimg_tiff_stripe_100000x100000_256(request):
return request.param


# testimg_tiff_stripe_4096_4096_256_jpeg_resolution
@pytest.fixture(scope='session')
def testimg_tiff_stripe_4096_4096_256_jpeg_resolution_3_5_centimeter(
tmpdir_factory):
resolution = (0.3, 0.5, "CENTIMETER")
dataset_path, image_path = gen_image(
tmpdir_factory, 'tiff::stripe:4096x4096:256:jpeg', resolution)
yield image_path, resolution
# Clean up fake dataset folder
shutil.rmtree(dataset_path)


@pytest.fixture(scope='session')
def testimg_tiff_stripe_4096_4096_256_jpeg_resolution_4_7_inch(tmpdir_factory):
resolution = (0.4, 0.7, "INCH")
dataset_path, image_path = gen_image(
tmpdir_factory, 'tiff::stripe:4096x4096:256:jpeg', resolution)
yield image_path, resolution
# Clean up fake dataset folder
shutil.rmtree(dataset_path)


@pytest.fixture(scope='session')
def testimg_tiff_stripe_4096_4096_256_jpeg_resolution_9_1_none(tmpdir_factory):
resolution = (9, 1, "NONE")
dataset_path, image_path = gen_image(
tmpdir_factory, 'tiff::stripe:4096x4096:256:jpeg', resolution)
yield image_path, resolution
# Clean up fake dataset folder
shutil.rmtree(dataset_path)


@pytest.fixture(scope='session', params=[
lazy_fixture(
'testimg_tiff_stripe_4096_4096_256_jpeg_resolution_3_5_centimeter'),
lazy_fixture('testimg_tiff_stripe_4096_4096_256_jpeg_resolution_4_7_inch'),
lazy_fixture('testimg_tiff_stripe_4096_4096_256_jpeg_resolution_9_1_none'),
])
def testimg_tiff_stripe_4096_4096_256_jpeg_resolution(request):
return request.param
39 changes: 39 additions & 0 deletions python/cucim/tests/unit/clara/test_load_image_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#

from ...util.io import open_image_cucim
import math


def test_load_image_metadata(testimg_tiff_stripe_32x24_16):
Expand Down Expand Up @@ -71,6 +72,44 @@ def test_load_image_metadata(testimg_tiff_stripe_32x24_16):
assert img.raw_metadata == '{"axes": "YXC", "shape": [24, 32, 3]}'


def test_load_image_resolution_metadata(testimg_tiff_stripe_4096_4096_256_jpeg_resolution): # noqa: E501
image, resolution = testimg_tiff_stripe_4096_4096_256_jpeg_resolution
img = open_image_cucim(image)

x_resolution, y_resolution, resolution_unit = resolution

if resolution_unit == "CENTIMETER":
x_spacing = 10000.0 / x_resolution
y_spacing = 10000.0 / y_resolution
spacing_unit = "micrometer"
elif resolution_unit == "INCH":
x_spacing = 25400.0 / x_resolution
y_spacing = 25400.0 / y_resolution
spacing_unit = "micrometer"
else:
x_spacing = x_resolution
y_spacing = y_resolution
spacing_unit = ""

# Returns physical size in tuple.
assert all(map(lambda a, b: math.isclose(a, b, rel_tol=0.1),
img.spacing(), (y_spacing, x_spacing, 1.0)))
# Units for each spacing element (size is same with `ndim`).
assert img.spacing_units() == [spacing_unit, spacing_unit, 'color']

# A metadata object as `dict`
metadata = img.metadata
print(metadata)
assert isinstance(metadata, dict)
assert len(metadata) == 2 # 'cucim' and 'tiff'
assert math.isclose(metadata['tiff']['x_resolution'],
x_resolution, rel_tol=0.00001)
assert math.isclose(metadata['tiff']['y_resolution'],
y_resolution, rel_tol=0.00001)
unit_value = resolution_unit.lower() if resolution_unit != "NONE" else ""
assert metadata['tiff']['resolution_unit'] == unit_value


def test_load_rgba_image_metadata(tmpdir):
"""Test accessing RGBA image's metadata.
Expand Down
16 changes: 12 additions & 4 deletions python/cucim/tests/util/gen_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,16 +28,23 @@


class ImageGenerator:
def __init__(self, dest, recipes, logger=None):
def __init__(self, dest, recipes, resolutions=None, logger=None):
self.logger = logger or logging.getLogger(__name__)
self.dest = dest
self.recipes = recipes

if resolutions is None:
resolutions = [(1, 1, "CENTIMETER")] * len(recipes)
if len(resolutions) != len(recipes):
raise RuntimeError(
'Number of resolutions must be equal to number of recipes')
self.resolutions = resolutions

def gen(self):

results = []

for recipe in self.recipes:
for recipe, resolution in zip(self.recipes, self.resolutions):
items = recipe.split(':')
item_len = len(items)
if not (1 <= item_len <= 6):
Expand Down Expand Up @@ -69,7 +76,7 @@ def gen(self):
raise RuntimeError(
f'No data generated from [pattern={pattern},'
+ f' image_size={image_size}, tile_size={tile_size},'
+ f' compression={compression}].')
+ f' compression={compression}, resolution={resolution}].')

file_name = f'{kind}_{pattern}_{image_size_str}_{tile_size}'

Expand All @@ -81,7 +88,8 @@ def gen(self):
pattern=pattern,
image_size=image_size,
tile_size=tile_size,
compression=compression)
compression=compression,
resolution=resolution)
self.logger.info(' Generated %s...', image_path)
results.append(image_path)

Expand Down
9 changes: 8 additions & 1 deletion python/cucim/tests/util/gen_tiff.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ def get_image(self, pattern, image_size):
return None

def save_image(self, image_data, dest_folder, file_name, kind, subpath,
pattern, image_size, tile_size, compression):
pattern, image_size, tile_size, compression, resolution):
# You can add pyramid images (0: largest resolution)
if isinstance(image_data, list):
arr_stack = image_data
Expand All @@ -55,10 +55,16 @@ def save_image(self, image_data, dest_folder, file_name, kind, subpath,
tiff_file_name = str(
(Path(dest_folder) / f'{file_name}.tif').absolute())

level_resolution = None
with TiffWriter(tiff_file_name, bigtiff=True) as tif:
for level in range(len(arr_stack)): # save from the largest image
src_arr = arr_stack[level]

if resolution:
level_resolution = (resolution[0] / (level + 1),
resolution[1] / (level + 1),
resolution[2])

tif.write(
src_arr,
software="tifffile",
Expand All @@ -68,6 +74,7 @@ def save_image(self, image_data, dest_folder, file_name, kind, subpath,
planarconfig="CONTIG",
compression=compression, # requires imagecodecs
subfiletype=1 if level else 0,
resolution=level_resolution,
)
return tiff_file_name

Expand Down

0 comments on commit f56a4cf

Please sign in to comment.