Skip to content

Commit

Permalink
feat(mesh-io): add wasi read_mesh, write_mesh
Browse files Browse the repository at this point in the history
  • Loading branch information
thewtex committed Nov 28, 2023
1 parent 13e1a20 commit b3575a2
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 2 deletions.
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
# Generated file. To retain edits, remove this comment.

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

from .read_mesh import read_mesh, meshread
from .write_mesh import write_mesh, meshwrite

from .byu_read_mesh import byu_read_mesh
from .byu_write_mesh import byu_write_mesh
from .free_surfer_ascii_read_mesh import free_surfer_ascii_read_mesh
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from collections import OrderedDict

extension_to_mesh_io = OrderedDict([
('.vtk', 'vtk_poly_data'),
('.byu', 'byu'),
('.fsa', 'free_surfer_ascii'),
('.fsb', 'free_surfer_binary'),
('.obj', 'obj'),
('.off', 'off'),
('.stl', 'stl'),
('.swc', 'swc'),
('.iwm', 'wasm'),
('.iwm.cbor', 'wasm'),
('.iwm.cbor.zst', 'wasm_zstd'),
('.bmp', 'bmp'),
])
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
mesh_io_index = [
'vtk_poly_data',
'byu',
'free_surfer_ascii',
'free_surfer_binary',
'obj',
'off',
'stl',
'swc',
'wasm',
'wasm_zstd',
]

Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import os
import importlib
from pathlib import Path

from itkwasm import Mesh

from .extension_to_mesh_io import extension_to_mesh_io
from .mesh_io_index import mesh_io_index

def read_mesh(
serialized_mesh: os.PathLike,
information_only: bool = False,
) -> Mesh:
"""Read an mesh file format and convert it to the itk-wasm file format.
:param serialized_mesh: Input mesh serialized in the file format
:type serialized_mesh: os.PathLike
:param information_only: Only read mesh metadata -- do not read pixel data.
:type information_only: bool
:return: Output mesh
:rtype: Mesh
"""
extension = ''.join(Path(serialized_mesh).suffixes)

io = None
if extension in extension_to_mesh_io:
func = f"{extension_to_mesh_io[extension]}_read_mesh"
mod_name = f"itkwasm_mesh_io_wasi.{func}"
mod = importlib.import_module(mod_name)
io = getattr(mod, func)
else:
for ioname in mesh_io_index:
func = f"{ioname}_read_mesh"
mod_name = f"itkwasm_mesh_io_wasi.{func}"
mod = importlib.import_module(mod_name)
io = getattr(mod, func)
could_read, mesh = io(serialized_mesh, information_only=information_only)
if could_read:
return mesh

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

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

return mesh


def meshread(
serialized_mesh: os.PathLike,
information_only: bool = False,
) -> Mesh:
return read_mesh(serialized_mesh, information_only=information_only)

meshread.__doc__ = f"""{read_mesh.__doc__}
Alias for read_mesh.
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import os
import importlib
from pathlib import Path

from itkwasm import Mesh, PixelTypes, IntTypes, FloatTypes

from .extension_to_mesh_io import extension_to_mesh_io
from .mesh_io_index import mesh_io_index

def write_mesh(
mesh: Mesh,
serialized_mesh: os.PathLike,
information_only: bool = False,
use_compression: bool = False,
) -> None:
"""Write an itk-wasm Mesh to an mesh file format.
:param mesh: Input mesh
:type mesh: Mesh
:param serialized_mesh: Output mesh serialized in the file format.
:type serialized_mesh: str
:param information_only: Only write mesh metadata -- do not write pixel data.
:type information_only: bool
:param use_compression: Use compression in the written file
:type use_compression: bool
:param serialized_mesh: Input mesh serialized in the file format
:type serialized_mesh: os.PathLike
"""
extension = ''.join(Path(serialized_mesh).suffixes)

io = None
if extension in extension_to_mesh_io:
func = f"{extension_to_mesh_io[extension]}_write_mesh"
mod_name = f"itkwasm_mesh_io_wasi.{func}"
mod = importlib.import_module(mod_name)
io = getattr(mod, func)
else:
for ioname in mesh_io_index:
func = f"{ioname}_write_mesh"
mod_name = f"itkwasm_mesh_io_wasi.{func}"
mod = importlib.import_module(mod_name)
io = getattr(mod, func)
could_write = io(mesh, serialized_mesh, information_only=information_only, use_compression=use_compression)
if could_write:
return

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

could_write = io(mesh, serialized_mesh, information_only=information_only, use_compression=use_compression)
if not could_write:
raise RuntimeError(f"Could not write {serialized_mesh}")

def meshwrite(
mesh: Mesh,
serialized_mesh: os.PathLike,
information_only: bool = False,
use_compression: bool = False,
) -> None:
return write_mesh(mesh, serialized_mesh, information_only=information_only, use_compression=use_compression)

meshwrite.__doc__ = f"""{write_mesh.__doc__}
Alias for write_mesh.
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
from itkwasm import IntTypes, FloatTypes
import numpy as np

from itkwasm_mesh_io_wasi import read_mesh, meshread, write_mesh, meshwrite

from .common import test_input_path, test_output_path

test_input_file_path = test_input_path / "cow.vtk"
test_output_file_path = test_output_path / "read-write-cow.vtk"

def verify_mesh(mesh):
assert mesh.meshType.dimension == 3
assert mesh.meshType.pointComponentType == FloatTypes.Float32
assert mesh.meshType.pointPixelComponentType == IntTypes.Int8
assert mesh.numberOfPoints == 2903
assert np.allclose(mesh.points[0],3.71636)
assert np.allclose(mesh.points[1],2.34339)
assert mesh.numberOfCells == 3263
assert mesh.cellBufferSize == 18856
assert mesh.cells[0] == 4
assert mesh.cells[1] == 4
assert mesh.cells[2] == 250

def test_read_mesh():
mesh = read_mesh(test_input_file_path)
verify_mesh(mesh)

def test_meshread():
mesh = meshread(test_input_file_path)
verify_mesh(mesh)

def test_write_mesh():
mesh = read_mesh(test_input_file_path)

use_compression = False
write_mesh(mesh, test_output_file_path, use_compression=use_compression)

mesh = read_mesh(test_output_file_path)
verify_mesh(mesh)

def test_meshwrite():
mesh = meshread(test_input_file_path)

use_compression = False
meshwrite(mesh, test_output_file_path, use_compression=use_compression)

mesh = meshread(test_output_file_path)
verify_mesh(mesh)

0 comments on commit b3575a2

Please sign in to comment.