Skip to content

Commit

Permalink
feat(transform-io); dispatch read and write functions
Browse files Browse the repository at this point in the history
  • Loading branch information
thewtex committed Nov 26, 2024
1 parent 395beb7 commit cc6d6b3
Show file tree
Hide file tree
Showing 17 changed files with 379 additions and 36 deletions.
1 change: 1 addition & 0 deletions packages/image-io/pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ pyodide-py = ">=0.26.3, <0.27"
pytest-pyodide = ">=0.58.3, <0.59"
itk-webassemblyinterface = ">=1.0b175, <2"
itkwasm = ">=1.0b179, <2"
itkwasm-image-io-wasi = { path = "python/itkwasm-image-io-wasi", editable = true }

[feature.python.tasks.test-wasi]
cmd = "pytest"
Expand Down
1 change: 1 addition & 0 deletions packages/mesh-io/pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ pyodide-py = ">=0.26.3, <0.27"
pytest-pyodide = ">=0.58.3, <0.59"
itk-webassemblyinterface = ">=1.0b175, <2"
itkwasm = ">=1.0b179, <2"
itkwasm-mesh-io-wasi = { path = "python/itkwasm-mesh-io-wasi", editable = true }

[feature.python.tasks.test-wasi]
cmd = "pytest"
Expand Down
14 changes: 14 additions & 0 deletions packages/transform-io/pixi.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions packages/transform-io/pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ pyodide-py = ">=0.26.4, <0.27"
pytest-pyodide = ">=0.58.3, <0.59"
itk-webassemblyinterface = ">=1.0b175, <2"
itkwasm = ">=1.0b185, <2"
itkwasm-transform-io-wasi = { path = "python/itkwasm-transform-io-wasi", editable = true }

[feature.python.tasks.test-wasi]
cmd = "pytest"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

test_input_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "input"
test_baseline_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "baseline"
test_output_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "output" / "python"
test_output_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "output" / "python-wasi"
test_output_path.mkdir(parents=True, exist_ok=True)

def verify_test_linear_transform(transform_list: TransformList):
Expand All @@ -20,4 +20,4 @@ def verify_test_linear_transform(transform_list: TransformList):
0.65631490118447, 0.5806583745824385, -0.4817536741017158,
-0.7407986817430222, 0.37486398378429736, -0.5573995934598175,
-0.14306664045479867, 0.7227121458012518, 0.676179776908723,
-65.99999999999997, 69.00000000000004, 32.000000000000036]))
-65.99999999999997, 69.00000000000004, 32.000000000000036]))
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
# Generated file. To retain edits, remove this comment.

"""itkwasm-transform-io: Input and output for scientific and medical coordinate transform file formats."""

from .read_transform_async import read_transform_async, transformread_async
from .read_transform import read_transform, transformread
from .write_transform_async import write_transform_async, transformwrite_async
from .write_transform import write_transform, transformwrite

from .hdf5_read_transform_async import hdf5_read_transform_async
from .hdf5_read_transform import hdf5_read_transform
from .hdf5_write_transform_async import hdf5_write_transform_async
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import os
from typing import Optional, Union

from itkwasm import (
environment_dispatch,
TransformList,
)

def read_transform(
serialized_transform: os.PathLike,
float_parameters: bool = False,
) -> TransformList:
"""Read a transform file format and convert it to the ITK-Wasm file format
:param serialized_transform: Input transform serialized in the file format
:type serialized_transform: os.PathLike
:param float_parameters: Use float for the parameter value type. The default is double.
:type float_parameters: bool
:return: Output transform
:rtype: TransformList
"""
func = environment_dispatch("itkwasm_transform_io", "read_transform")
output = func(serialized_transform, float_parameters=float_parameters)
return output

def transformread(
serialized_transform: os.PathLike,
float_parameters: bool = False,
) -> TransformList:
return read_transform(serialized_transform, float_parameters=float_parameters)

transformread.__doc__ = f"""{read_transform.__doc__}
Alias for read_transform.
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import os
from typing import Optional, Union

from itkwasm import (
environment_dispatch,
TransformList,
)

async def read_transform_async(
serialized_transform: os.PathLike,
float_parameters: bool = False,
) -> TransformList:
"""Read an transform file format and convert it to the ITK-Wasm file format.
:param serialized_transform: Input transform serialized in the file format
:type serialized_transform: os.PathLike
:param float_parameters: Use float for the parameter value type. The default is double.
:type float_parameters: bool
:return: Output transform
:rtype: TransformList
"""
func = environment_dispatch("itkwasm_transform_io", "read_transform_async")
output = await func(serialized_transform, float_parameters=float_parameters)
return output

async def transformread_async(
serialized_transform: os.PathLike,
float_parameters: bool = False,
) -> TransformList:
return await read_transform_async(serialized_transform, float_parameters=float_parameters)

transformread_async.__doc__ = f"""{read_transform_async.__doc__}
Alias for read_transform.
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import os
from typing import Dict, Tuple, Optional, List, Any

from itkwasm import (
environment_dispatch,
TransformList,
)

def write_transform(
transform: TransformList,
serialized_transform: str,
float_parameters: bool = False,
use_compression: bool = False,
) -> None:
"""Write an ITK-Wasm file format converted to a transform file format
:param transform: Input transform
:type transform: TransformList
:param serialized_transform: Output transform serialized in the file format.
:type serialized_transform: str
:param float_parameters: Use float for the parameter value type. The default is double.
:type float_parameters: bool
:param use_compression: Use compression in the written file
:type use_compression: bool
"""
func = environment_dispatch("itkwasm_transform_io", "write_transform")
func(transform, serialized_transform, float_parameters=float_parameters, use_compression=use_compression)
return

def transformwrite(
transform: TransformList,
serialized_transform: os.PathLike,
float_parameters: bool = False,
use_compression: bool = False,
) -> None:
return write_transform(transform, serialized_transform, float_parameters=float_parameters, use_compression=use_compression)

transformwrite.__doc__ = f"""{write_transform.__doc__}
Alias for write_transform.
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import os
from typing import Dict, Tuple, Optional, List, Any

from itkwasm import (
environment_dispatch,
TransformList,
)

async def write_transform_async(
transform: TransformList,
serialized_transform: str,
float_parameters: bool = False,
use_compression: bool = False,
) -> None:
"""Write an ITK-Wasm file format converted to a transform file format.
:param transform: Input transform
:type transform: TransformList
:param serialized_transform: Output transform serialized in the file format.
:type serialized_transform: str
:param float_parameters: Only write transform metadata -- do not write pixel data.
:type float_parameters: bool
:param use_compression: Use compression in the written file
:type use_compression: bool
"""
func = environment_dispatch("itkwasm_transform_io", "write_transform_async")
await func(transform, serialized_transform, float_parameters=float_parameters, use_compression=use_compression)
return

async def transformwrite_async(
transform: TransformList,
serialized_transform: os.PathLike,
float_parameters: bool = False,
use_compression: bool = False,
) -> None:
return await write_transform_async(transform, serialized_transform, float_parameters=float_parameters, use_compression=use_compression)

transformwrite_async.__doc__ = f"""{write_transform_async.__doc__}
Alias for write_transform.
"""
23 changes: 23 additions & 0 deletions packages/transform-io/python/itkwasm-transform-io/tests/common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from pathlib import Path
import numpy as np

from itkwasm import TransformList, TransformParameterizations, FloatTypes

test_input_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "input"
test_baseline_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "baseline"
test_output_path = Path(__file__).parent / ".." / ".." / ".." / "test" / "data" / "output" / "python-dispatch"
test_output_path.mkdir(parents=True, exist_ok=True)

def verify_test_linear_transform(transform_list: TransformList):
assert len(transform_list) == 1
transform = transform_list[0]
assert transform.transformType.transformParameterization == TransformParameterizations.Affine
assert transform.transformType.parametersValueType == FloatTypes.Float64
assert transform.numberOfParameters == 12
assert transform.numberOfFixedParameters == 3
np.testing.assert_allclose(transform.fixedParameters, np.array([0.0, 0.0, 0.0]))
np.testing.assert_allclose(transform.parameters, np.array([
0.65631490118447, 0.5806583745824385, -0.4817536741017158,
-0.7407986817430222, 0.37486398378429736, -0.5573995934598175,
-0.14306664045479867, 0.7227121458012518, 0.676179776908723,
-65.99999999999997, 69.00000000000004, 32.000000000000036]))
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ def emscripten_package_wheel():
@pytest.fixture
def input_data():
from pathlib import Path
input_base_path = Path(__file__).parent.parent / 'test' / 'data'
input_base_path = Path(__file__).parent.parent.parent.parent / 'test' / 'data' / 'input'
test_files = list(input_base_path.glob('*'))
data = {}
for test_file in test_files:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,12 @@
import pytest
import sys
from pathlib import Path

if sys.version_info < (3,10):
pytest.skip("Skipping pyodide tests on older Python", allow_module_level=True)
from itkwasm_transform_io import hdf5_read_transform

from pytest_pyodide import run_in_pyodide
from .common import test_input_path, test_output_path, verify_test_linear_transform

from .fixtures import emscripten_package_wheel, package_wheel, input_data
test_input_file_path = test_input_path / "LinearTransform.h5"

@run_in_pyodide(packages=['micropip'])
async def test_hdf5_read_transform(selenium, package_wheel, emscripten_package_wheel):
import micropip
await micropip.install(emscripten_package_wheel)
await micropip.install(package_wheel)

from itkwasm_transform_io import hdf5_read_transform

# Write your test code here
def test_hdf5_read_transform():
could_read, transform_list = hdf5_read_transform(test_input_file_path)
assert could_read
verify_test_linear_transform(transform_list)
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import pytest
import sys

if sys.version_info < (3,10):
pytest.skip("Skipping pyodide tests on older Python", allow_module_level=True)

from pytest_pyodide import run_in_pyodide

from .fixtures import package_wheel, input_data, emscripten_package_wheel

@run_in_pyodide(packages=['micropip'])
async def test_hdf5_read_transform_async(selenium, package_wheel, emscripten_package_wheel, input_data):
import micropip
await micropip.install(emscripten_package_wheel)
await micropip.install(package_wheel)

from pathlib import Path

import numpy as np
from itkwasm import TransformParameterizations, FloatTypes

from itkwasm_transform_io import hdf5_read_transform_async, hdf5_write_transform_async

def write_input_data_to_fs(input_data, filename):
with open(filename, 'wb') as fp:
fp.write(input_data[filename])

def verify_test_linear_transform(transform_list):
assert len(transform_list) == 1
transform = transform_list[0]
assert transform.transformType.transformParameterization == TransformParameterizations.Affine
assert transform.transformType.parametersValueType == FloatTypes.Float64
assert transform.numberOfParameters == 12
assert transform.numberOfFixedParameters == 3
np.testing.assert_allclose(transform.fixedParameters, np.array([0.0, 0.0, 0.0]))
np.testing.assert_allclose(transform.parameters, np.array([
0.65631490118447, 0.5806583745824385, -0.4817536741017158,
-0.7407986817430222, 0.37486398378429736, -0.5573995934598175,
-0.14306664045479867, 0.7227121458012518, 0.676179776908723,
-65.99999999999997, 69.00000000000004, 32.000000000000036]))

test_file_path = 'LinearTransform.h5'
write_input_data_to_fs(input_data, test_file_path)

assert Path(test_file_path).exists()

could_read, transform = await hdf5_read_transform_async(test_file_path)
assert could_read
verify_test_linear_transform(transform)

test_output_file_path = 'out-LinearTransform.h5'

use_compression = False
could_write = await hdf5_write_transform_async(transform, test_output_file_path, use_compression)
assert could_write

could_read, transform = await hdf5_read_transform_async(test_output_file_path)
assert could_read
verify_test_linear_transform(transform)
Loading

0 comments on commit cc6d6b3

Please sign in to comment.