Skip to content

Commit

Permalink
Merge pull request #1277 from thewtex/transform-io-python
Browse files Browse the repository at this point in the history
transform io python
  • Loading branch information
thewtex authored Nov 26, 2024
2 parents e61f0cf + e72fc66 commit dc66568
Show file tree
Hide file tree
Showing 83 changed files with 1,671 additions and 359 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/python-wasm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ jobs:
matrix:
os: [ubuntu-22.04, windows-2022, macos-14]
python-minor-version: [11, 12]
package: [compress-stringify, compare-images, dicom, mesh-io, image-io, downsample]
package: [compress-stringify, compare-images, dicom, mesh-io, image-io, transform-io, downsample]

steps:
- name: Checkout
Expand Down
2 changes: 1 addition & 1 deletion packages/core/python/itkwasm/itkwasm/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""itkwasm: Python interface to itk-wasm WebAssembly modules."""

__version__ = "1.0b180"
__version__ = "1.0b185"

from .interface_types import InterfaceTypes
from .image import Image, ImageType, ImageRegion
Expand Down
2 changes: 1 addition & 1 deletion packages/core/python/itkwasm/itkwasm/interface_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@ class InterfaceTypes(str, Enum):
Mesh = "Mesh"
PointSet = "PointSet"
PolyData = "PolyData"
Transform = "Transform"
TransformList = "TransformList"
JsonCompatible = "JsonCompatible"
54 changes: 53 additions & 1 deletion packages/core/python/itkwasm/itkwasm/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from .binary_file import BinaryFile
from .image import Image
from .mesh import Mesh
from .transform import Transform
from .point_set import PointSet
from .polydata import PolyData
from .json_compatible import JsonCompatible
Expand All @@ -45,6 +46,8 @@
WasiConfig,
Linker,
WasmtimeError,
DirPerms,
FilePerms
)

# Get the value of the ITKWASM_CACHE_DIR environment variable
Expand Down Expand Up @@ -83,7 +86,7 @@ def __init__(
wasi_config.argv = args

for preopen in preopen_directories:
wasi_config.preopen_dir(preopen, preopen)
wasi_config.preopen_dir(preopen, preopen, DirPerms.READ_WRITE, FilePerms.READ_WRITE)

store.set_wasi(wasi_config)

Expand Down Expand Up @@ -299,6 +302,34 @@ def run(
"pointData": f"data:application/vnd.itk.address,0:{point_data_ptr}",
}
ri.set_input_json(point_set_json, index)
elif input_.type == InterfaceTypes.TransformList:
transform_list = input_.data
transform_list_json = []
for idx, transform in enumerate(transform_list):
if transform.numberOfFixedParameters:
fpv = array_like_to_bytes(transform.fixedParameters)
else:
fpv = bytes([])
fixed_parameters_ptr = ri.set_input_array(fpv, index, idx * 2)
fixed_parameters = f"data:application/vnd.itk.address,0:{fixed_parameters_ptr}"
if transform.numberOfParameters:
pv = array_like_to_bytes(transform.parameters)
else:
pv = bytes([])
parameters_ptr = ri.set_input_array(pv, index, idx * 2 + 1)
parameters = f"data:application/vnd.itk.address,0:{parameters_ptr}"
transform_json = {
"transformType": asdict(transform.transformType),
"numberOfFixedParameters": transform.numberOfFixedParameters,
"numberOfParameters": transform.numberOfParameters,
"name": transform.name,
"inputSpaceName": transform.inputSpaceName,
"outputSpaceName": transform.outputSpaceName,
"fixedParameters": fixed_parameters,
"parameters": parameters,
}
transform_list_json.append(transform_json)
ri.set_input_json(transform_list_json, index)
elif input_.type == InterfaceTypes.PolyData:
polydata = input_.data
if polydata.numberOfPoints:
Expand Down Expand Up @@ -489,6 +520,27 @@ def run(
point_set.pointData = buffer_to_numpy_array(point_set.pointSetType.pointPixelComponentType, bytes([]))

output_data = PipelineOutput(InterfaceTypes.PointSet, point_set)
elif output.type == InterfaceTypes.TransformList:
transform_list_json = ri.get_output_json(index)
transform_list = []
for idx, transform_json in enumerate(transform_list_json):
transform = Transform(**transform_json)
if transform.numberOfFixedParameters > 0:
data_ptr = ri.get_output_array_address(0, index, idx * 2)
data_size = ri.get_output_array_size(0, index, idx * 2)
transform.fixedParameters = buffer_to_numpy_array(
transform.transformType.parametersValueType,
ri.wasmtime_lift(data_ptr, data_size),
)
if transform.numberOfParameters > 0:
data_ptr = ri.get_output_array_address(0, index, idx * 2 + 1)
data_size = ri.get_output_array_size(0, index, idx * 2 + 1)
transform.parameters = buffer_to_numpy_array(
transform.transformType.parametersValueType,
ri.wasmtime_lift(data_ptr, data_size),
)
transform_list.append(transform)
output_data = PipelineOutput(InterfaceTypes.TransformList, transform_list)
elif output.type == InterfaceTypes.PolyData:
polydata_json = ri.get_output_json(index)
polydata = PolyData(**polydata_json)
Expand Down
22 changes: 22 additions & 0 deletions packages/core/python/itkwasm/itkwasm/pyodide.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from .point_set import PointSet, PointSetType
from .mesh import Mesh, MeshType
from .polydata import PolyData, PolyDataType
from .transform import Transform, TransformType
from .binary_file import BinaryFile
from .binary_stream import BinaryStream
from .text_file import TextFile
Expand Down Expand Up @@ -147,6 +148,20 @@ def to_py(js_proxy):
if polydata_dict["cellData"] is not None:
polydata_dict["cellData"] = buffer_to_numpy_array(cell_pixel_component_type, polydata_dict["cellData"])
return PolyData(**polydata_dict)
elif hasattr(js_proxy, "transformType"):
transform_dict = js_proxy.to_py()
transform_type = TransformType(**transform_dict["transformType"])
transform_dict["transformType"] = transform_type
parameters_value_type = transform_type.parametersValueType
if transform_dict["fixedParameters"] is not None:
transform_dict["fixedParameters"] = buffer_to_numpy_array(
parameters_value_type, transform_dict["fixedParameters"]
)
if transform_dict["parameters"] is not None:
transform_dict["parameters"] = buffer_to_numpy_array(
parameters_value_type, transform_dict["parameters"]
)
return Transform(**transform_dict)
elif hasattr(js_proxy, "path") and hasattr(js_proxy, "data") and isinstance(js_proxy.data, str):
with open(js_proxy.path, "w") as fp:
fp.write(js_proxy.data)
Expand Down Expand Up @@ -222,6 +237,13 @@ def to_js(py, **kwargs):
if polydata_dict["cellData"] is not None:
polydata_dict["cellData"] = polydata_dict["cellData"].ravel()
return pyodide.ffi.to_js(polydata_dict, dict_converter=js.Object.fromEntries)
elif isinstance(py, Transform):
transform_dict = asdict(py)
if transform_dict["fixedParameters"] is not None:
transform_dict["fixedParameters"] = transform_dict["fixedParameters"].ravel()
if transform_dict["parameters"] is not None:
transform_dict["parameters"] = transform_dict["parameters"].ravel()
return pyodide.ffi.to_js(transform_dict, dict_converter=js.Object.fromEntries)
elif isinstance(py, TextStream):
text_stream_dict = asdict(py)
return pyodide.ffi.to_js(text_stream_dict, dict_converter=js.Object.fromEntries)
Expand Down
5 changes: 4 additions & 1 deletion packages/core/python/itkwasm/itkwasm/transform.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
from numpy import ndarray as ArrayLike
import numpy as np

from .float_types import FloatTypes

class TransformParameterizations(str, Enum):
Composite = "Composite"
Identity = "Identity"
Expand Down Expand Up @@ -40,9 +42,10 @@ class TransformParameterizations(str, Enum):

@dataclass
class TransformType:
transformParameterization: TransformParameterizations = TransformParameterizations.Identity
parametersValueType: FloatTypes = FloatTypes.Float64
inputDimension: int = 3
outputDimension: int = 3
transformParameterization: TransformParameterizations = TransformParameterizations.Identity

@dataclass
class Transform:
Expand Down
63 changes: 31 additions & 32 deletions packages/core/python/itkwasm/pixi.lock

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

Loading

0 comments on commit dc66568

Please sign in to comment.