Skip to content

Commit

Permalink
feat(itkwasm-image-io-wasi): add read_image, imread
Browse files Browse the repository at this point in the history
  • Loading branch information
thewtex committed Nov 4, 2023
1 parent 4ff0d0a commit 020ac77
Show file tree
Hide file tree
Showing 8 changed files with 277 additions and 3 deletions.
16 changes: 15 additions & 1 deletion packages/core/python/itkwasm/itkwasm/cast_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,21 @@
def cast_image(input_image: Image,
pixel_type: Optional[PixelTypes]=None,
component_type: Optional[Union[IntTypes, FloatTypes]]=None) -> Image:
"""Cast an image to another pixel type and / or component type."""
"""Cast an image to another pixel type and / or component type.
:param input_image: Image to be cast.
:type input_image: Image
:param pixel_type: Pixel type to cast to.
:type pixel_Type: Optional[PixelTypes]
:param component_type: Component type to cast to.
:type component_type: Optional[Union[IntTypes, FloatTypes]]
:return: Cast image. Event if pixel_type or component_type are not specified, a copy is made.
:rtype: Image
"""
output_image_type = ImageType(**asdict(input_image.imageType))

if pixel_type is not None:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Generated file. To retain edits, remove this comment.

"""itkwasm-image-io-wasi: Input and output for scientific and medical image file formats. WASI implementation."""

from .read_image import read_image, imread

from .bio_rad_read_image import bio_rad_read_image
from .bio_rad_write_image import bio_rad_write_image
from .bmp_read_image import bmp_read_image
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from collections import OrderedDict

extension_to_image_io = OrderedDict([
('.bmp', 'bmp'),

('.dcm', 'gdcm'),

('.gipl', 'gipl'),
('.gipl.gz', 'gipl'),

('.hdf5', 'hdf5'),

('.jpg', 'jpeg'),
('.jpeg', 'jpeg'),

('.iwi', 'wasm'),
('.iwi.cbor', 'wasm'),
('.iwi.cbor.zst', 'wasm_zstd'),

('.lsm', 'lsm'),

('.mnc', 'mnc'),
('.mnc.gz', 'mnc'),
('.mnc2', 'mnc'),

('.mgh', 'mgh'),
('.mgz', 'mgh'),
('.mgh.gz', 'mgh'),

('.mha', 'meta'),
('.mhd', 'meta'),

('.mrc', 'mrc'),

('.nia', 'nifti'),
('.nii', 'nifti'),
('.nii.gz', 'nifti'),
('.hdr', 'nifti'),

('.nrrd', 'nrrd'),
('.nhdr', 'nrrd'),

('.png', 'png'),

('.pic', 'bio_rad'),

('.tif', 'tiff'),
('.tiff', 'tiff'),

('.vtk', 'vtk'),

('.isq', 'scanco'),
('.aim', 'scanco'),

('.fdf', 'fdf'),
])
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
image_io_index = [
'png',
'meta',
'tiff',
'nifti',
'jpeg',
'nrrd',
'vtk',
'bmp',
'hdf5',
'minc',
'mrc',
'lsm',
'mgh',
'bio_rad',
'gipl',
'ge_adw',
'ge4',
'ge5',
'gdcm',
'scanco',
'wasm',
'wasm_zstd',
]

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import os
import importlib
from pathlib import Path
from typing import Optional, Union

from itkwasm import Image, PixelTypes, IntTypes, FloatTypes, cast_image

from .extension_to_image_io import extension_to_image_io
from .image_io_index import image_io_index

def read_image(
serialized_image: os.PathLike,
information_only: bool = False,
pixel_type: Optional[PixelTypes]=None,
component_type: Optional[Union[IntTypes, FloatTypes]]=None,
) -> Image:
"""Read an image file format and convert it to the itk-wasm file format.
:param serialized_image: Input image serialized in the file format
:type serialized_image: os.PathLike
:param information_only: Only read image metadata -- do not read pixel data.
:type information_only: bool
:param pixel_type: Pixel type to cast to.
:type pixel_Type: Optional[PixelTypes]
:param component_type: Component type to cast to.
:type component_type: Optional[Union[IntTypes, FloatTypes]]
:return: Output image
:rtype: Image
"""
file_name = Path(serialized_image).name
extension = ''.join(Path(serialized_image).suffixes)

io = None
if extension in extension_to_image_io:
func = f"{extension_to_image_io[extension]}_read_image"
mod_name = f"itkwasm_image_io_wasi.{func}"
mod = importlib.import_module(mod_name)
io = getattr(mod, func)
else:
for ioname in image_io_index:
func = f"{ioname}_read_image"
mod_name = f"itkwasm_image_io_wasi.{func}"
mod = importlib.import_module(mod_name)
io = getattr(mod, func)
could_read, image = io(serialized_image, information_only=information_only)
if could_read:
if pixel_type or component_type:
image = cast_image(image, pixel_type=pixel_type, component_type=component_type)
return image

if io is None:
raise RuntimeError(f"Could not find an image reader for {extension}")

could_read, image = io(serialized_image, information_only=information_only)
if not could_read:
raise RuntimeError(f"Could not read {serialized_image}")

if pixel_type or component_type:
image = cast_image(image, pixel_type=pixel_type, component_type=component_type)
return image


def imread(
serialized_image: os.PathLike,
information_only: bool = False,
pixel_type: Optional[PixelTypes]=None,
component_type: Optional[Union[IntTypes, FloatTypes]]=None,
) -> Image:
return read_image(serialized_image, information_only=information_only, pixel_type=pixel_type, component_type=component_type)

imread.__doc__ = f"""{read_image.__doc__}
Alias for read_image.
"""
43 changes: 43 additions & 0 deletions packages/image-io/python/itkwasm-image-io-wasi/tests/test_png.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
from pathlib import Path

from itkwasm_image_io_wasi import png_read_image, png_write_image

from .common import test_input_path, test_output_path

test_input_file_path = test_input_path / "cthead1.png"
test_output_file_path = test_output_path / "png-test-cthead1.png"

def verify_image(image):
assert image.imageType.dimension == 2
assert image.imageType.componentType == "uint8"
assert image.imageType.pixelType == "RGB"
assert image.imageType.components == 3
assert image.origin[0] == 0.0
assert image.origin[1] == 0.0
assert image.spacing[0] == 1.0
assert image.spacing[1] == 1.0
assert image.direction[0, 0] == 1.0
assert image.direction[0, 1] == 0.0
assert image.direction[1, 0] == 0.0
assert image.direction[1, 1] == 1.0
assert image.size[0] == 256
assert image.size[1] == 256
assert image.data.shape[1] == 256
assert image.data.shape[0] == 256

def test_png_read_image():
could_read, image = png_read_image(test_input_file_path)
assert could_read
verify_image(image)

def test_png_write_image():
could_read, image = png_read_image(test_input_file_path)
assert could_read

use_compression = False
could_write = png_write_image(image, test_output_file_path, use_compression)
assert could_write

could_read, image = png_read_image(test_output_file_path)
assert could_read
verify_image(image)
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from pathlib import Path

from itkwasm import PixelTypes, IntTypes

from itkwasm_image_io_wasi import read_image, imread

from .common import test_input_path, test_output_path

test_input_file_path = test_input_path / "cthead1.png"
test_output_file_path = test_output_path / "read-write-cthead1.png"

def verify_image(image):
assert image.imageType.dimension == 2
assert image.imageType.componentType == "uint8"
assert image.imageType.pixelType == "RGB"
assert image.imageType.components == 3
assert image.origin[0] == 0.0
assert image.origin[1] == 0.0
assert image.spacing[0] == 1.0
assert image.spacing[1] == 1.0
assert image.direction[0, 0] == 1.0
assert image.direction[0, 1] == 0.0
assert image.direction[1, 0] == 0.0
assert image.direction[1, 1] == 1.0
assert image.size[0] == 256
assert image.size[1] == 256
assert image.data.shape[1] == 256
assert image.data.shape[0] == 256

def test_read_image():
image = read_image(test_input_file_path)
verify_image(image)

def test_read_image_pixel_type():
image = read_image(test_input_file_path, pixel_type=PixelTypes.Vector)
assert image.imageType.pixelType == "Vector"

def test_read_image_component_type():
image = read_image(test_input_file_path, component_type=IntTypes.UInt16)
assert image.imageType.componentType == "uint16"

def test_imread():
image = imread(test_input_file_path)
verify_image(image)

def test_write_image():
pass
return
could_read, image = png_read_image(test_input_file_path)
assert could_read

use_compression = False
could_write = png_write_image(image, test_output_file_path, use_compression)
assert could_write

could_read, image = png_read_image(test_output_file_path)
assert could_read
verify_image(image)
1 change: 1 addition & 0 deletions packages/image-io/typescript/src/extension-to-image-io.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const extensionToImageIo = new Map([
['vtk', 'vtk'],

['isq', 'scanco'],
['aim', 'scanco'],

['fdf', 'fdf'],
])
Expand Down

0 comments on commit 020ac77

Please sign in to comment.