Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 39 additions & 18 deletions packages/core/python/itkwasm/itkwasm/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,19 +316,29 @@ def run(
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}"
input_array_index = 0
for transform in transform_list:
fixed_parameters = ""
parameters = ""

# Skip setting input arrays for Composite transforms as they don't have array data
if transform.transformType.transformParameterization != "Composite":
if transform.numberOfFixedParameters:
fpv = array_like_to_bytes(transform.fixedParameters)
else:
fpv = bytes([])
fixed_parameters_ptr = ri.set_input_array(fpv, index, input_array_index)
fixed_parameters = f"data:application/vnd.itk.address,0:{fixed_parameters_ptr}"
input_array_index += 1

if transform.numberOfParameters:
pv = array_like_to_bytes(transform.parameters)
else:
pv = bytes([])
parameters_ptr = ri.set_input_array(pv, index, input_array_index)
parameters = f"data:application/vnd.itk.address,0:{parameters_ptr}"
input_array_index += 1

transform_json = {
"transformType": asdict(transform.transformType),
"numberOfFixedParameters": transform.numberOfFixedParameters,
Expand Down Expand Up @@ -540,22 +550,33 @@ def run(
elif output.type == InterfaceTypes.TransformList:
transform_list_json = ri.get_output_json(index)
transform_list = []
for idx, transform_json in enumerate(transform_list_json):
output_array_index = 0
for transform_json in transform_list_json:
transform = Transform(**transform_json)

# Skip array reading for Composite transforms as they don't have array data
if transform.transformType.transformParameterization == "Composite":
transform_list.append(transform)
continue

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)
data_ptr = ri.get_output_array_address(0, index, output_array_index)
data_size = ri.get_output_array_size(0, index, output_array_index)
transform.fixedParameters = buffer_to_numpy_array(
FloatTypes.Float64,
ri.wasmtime_lift(data_ptr, data_size),
)
output_array_index += 1

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)
data_ptr = ri.get_output_array_address(0, index, output_array_index)
data_size = ri.get_output_array_size(0, index, output_array_index)
transform.parameters = buffer_to_numpy_array(
transform.transformType.parametersValueType,
ri.wasmtime_lift(data_ptr, data_size),
)
output_array_index += 1

transform_list.append(transform)
output_data = PipelineOutput(InterfaceTypes.TransformList, transform_list)
elif output.type == InterfaceTypes.PolyData:
Expand Down
2 changes: 1 addition & 1 deletion packages/core/python/itkwasm/itkwasm/pyodide.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from .point_set import PointSet, PointSetType
from .mesh import Mesh, MeshType
from .polydata import PolyData, PolyDataType
from .transform import Transform, TransformType
from .transform import Transform, TransformType, TransformList
from .binary_file import BinaryFile
from .binary_stream import BinaryStream
from .text_file import TextFile
Expand Down
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[
{
"transformType": {
"transformParameterization": "Composite",
"parametersValueType": "float32",
"inputDimension": 2,
"outputDimension": 2
},
"numberOfFixedParameters": 4,
"numberOfParameters": 9,
"name": "",
"inputSpaceName": "",
"outputSpaceName": "",
"fixedParameters": "data:application/vnd.itk.path,data/0/fixed-parameters.raw",
"parameters": "data:application/vnd.itk.path,data/0/parameters.raw",
"metadata": []
},
{
"transformType": {
"transformParameterization": "Rigid2D",
"parametersValueType": "float32",
"inputDimension": 2,
"outputDimension": 2
},
"numberOfFixedParameters": 2,
"numberOfParameters": 3,
"name": "",
"inputSpaceName": "",
"outputSpaceName": "",
"fixedParameters": "data:application/vnd.itk.path,data/1/fixed-parameters.raw",
"parameters": "data:application/vnd.itk.path,data/1/parameters.raw",
"metadata": []
},
{
"transformType": {
"transformParameterization": "Affine",
"parametersValueType": "float32",
"inputDimension": 2,
"outputDimension": 2
},
"numberOfFixedParameters": 2,
"numberOfParameters": 6,
"name": "",
"inputSpaceName": "",
"outputSpaceName": "",
"fixedParameters": "data:application/vnd.itk.path,data/2/fixed-parameters.raw",
"parameters": "data:application/vnd.itk.path,data/2/parameters.raw",
"metadata": []
}
]
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
[
{
"transformType": {
"transformParameterization": "Affine",
"parametersValueType": "float64",
"inputDimension": 3,
"outputDimension": 3
},
"numberOfFixedParameters": 3,
"numberOfParameters": 12,
"name": "",
"inputSpaceName": "",
"outputSpaceName": "",
"fixedParameters": "data:application/vnd.itk.path,data/0/fixed-parameters.raw",
"parameters": "data:application/vnd.itk.path,data/0/parameters.raw",
"metadata": []
}
]
Binary file not shown.
Binary file modified packages/core/python/itkwasm/test/input/transform-read-write-test.wasi.wasm
100755 → 100644
Binary file not shown.
156 changes: 155 additions & 1 deletion packages/core/python/itkwasm/test/test_pyodide.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from pytest_pyodide import run_in_pyodide, copy_files_to_pyodide

#from itkwasm import __version__ as test_package_version
test_package_version = '1.0b194'
test_package_version = '1.0b195'


def package_wheel():
Expand Down Expand Up @@ -273,6 +273,160 @@ async def test_transform_list_conversion(selenium):
assert translation_py.numberOfFixedParameters == 0
np.testing.assert_allclose(translation_py.parameters, translation_parameters)

@copy_files_to_pyodide(file_list=file_list, install_wheels=True)
@run_in_pyodide(packages=["numpy"])
async def test_linear_transform_conversion(selenium):
from itkwasm import Transform, TransformType, TransformParameterizations, FloatTypes, TransformList
from itkwasm.pyodide import to_js, to_py
import numpy as np

# Create a single linear (affine) transform
transform_type = TransformType(
transformParameterization=TransformParameterizations.Affine,
parametersValueType=FloatTypes.Float64,
inputDimension=3,
outputDimension=3
)

fixed_parameters = np.array([0.0, 0.0, 0.0]).astype(np.float64)
parameters = np.array([
1.0, 0.0, 0.0, # 3x3 matrix row 1
0.0, 1.0, 0.0, # 3x3 matrix row 2
0.0, 0.0, 1.0, # 3x3 matrix row 3
10.0, 20.0, 30.0 # translation vector
]).astype(np.float64)

transform = Transform(
transformType=transform_type,
numberOfParameters=12,
numberOfFixedParameters=3,
fixedParameters=fixed_parameters,
parameters=parameters
)

transform_list: TransformList = [transform]

# Convert to JS and back
transform_list_js = to_js(transform_list)
transform_list_py = to_py(transform_list_js)

# Verify the conversion
assert len(transform_list_py) == 1

transform_py = transform_list_py[0]
assert transform_py.transformType.transformParameterization == TransformParameterizations.Affine
assert transform_py.transformType.parametersValueType == FloatTypes.Float64
assert transform_py.transformType.inputDimension == 3
assert transform_py.transformType.outputDimension == 3
assert transform_py.numberOfFixedParameters == 3
assert transform_py.numberOfParameters == 12

np.testing.assert_allclose(transform_py.fixedParameters, fixed_parameters)
np.testing.assert_allclose(transform_py.parameters, parameters)


@copy_files_to_pyodide(file_list=file_list, install_wheels=True)
@run_in_pyodide(packages=["numpy"])
async def test_composite_transform_conversion(selenium):
from itkwasm import Transform, TransformType, TransformParameterizations, FloatTypes, TransformList
from itkwasm.pyodide import to_js, to_py
import numpy as np

# Create a composite transform
composite_transform_type = TransformType(
transformParameterization=TransformParameterizations.Composite,
parametersValueType=FloatTypes.Float32,
inputDimension=2,
outputDimension=2
)

composite_transform = Transform(
transformType=composite_transform_type,
numberOfParameters=9, # Sum of parameters from component transforms
numberOfFixedParameters=4, # Sum of fixed parameters from component transforms
fixedParameters=np.array([64.0, 64.0, 64.0, 64.0]).astype(np.float32),
parameters=np.array([
# Rigid2D parameters (3)
0.0, 64.0, 64.0,
# Affine parameters (6)
1.0, 0.0, 0.0, 1.0, 0.0, 0.0
]).astype(np.float32)
)

# Create first component transform (Rigid2D)
rigid_transform_type = TransformType(
transformParameterization=TransformParameterizations.Rigid2D,
parametersValueType=FloatTypes.Float32,
inputDimension=2,
outputDimension=2
)

rigid_transform = Transform(
transformType=rigid_transform_type,
numberOfParameters=3,
numberOfFixedParameters=2,
fixedParameters=np.array([64.0, 64.0]).astype(np.float32),
parameters=np.array([0.0, 64.0, 64.0]).astype(np.float32)
)

# Create second component transform (Affine)
affine_transform_type = TransformType(
transformParameterization=TransformParameterizations.Affine,
parametersValueType=FloatTypes.Float32,
inputDimension=2,
outputDimension=2
)

affine_transform = Transform(
transformType=affine_transform_type,
numberOfParameters=6,
numberOfFixedParameters=2,
fixedParameters=np.array([64.0, 64.0]).astype(np.float32),
parameters=np.array([1.0, 0.0, 0.0, 1.0, 0.0, 0.0]).astype(np.float32)
)

# Create transform list with composite + components
transform_list: TransformList = [composite_transform, rigid_transform, affine_transform]

# Convert to JS and back
transform_list_js = to_js(transform_list)
transform_list_py = to_py(transform_list_js)

# Verify the conversion
assert len(transform_list_py) == 3

# Verify composite transform
composite_py = transform_list_py[0]
assert composite_py.transformType.transformParameterization == TransformParameterizations.Composite
assert composite_py.transformType.parametersValueType == FloatTypes.Float32
assert composite_py.transformType.inputDimension == 2
assert composite_py.transformType.outputDimension == 2
assert composite_py.numberOfFixedParameters == 4
assert composite_py.numberOfParameters == 9

# Verify rigid transform
rigid_py = transform_list_py[1]
assert rigid_py.transformType.transformParameterization == TransformParameterizations.Rigid2D
assert rigid_py.transformType.parametersValueType == FloatTypes.Float32
assert rigid_py.transformType.inputDimension == 2
assert rigid_py.transformType.outputDimension == 2
assert rigid_py.numberOfFixedParameters == 2
assert rigid_py.numberOfParameters == 3
np.testing.assert_allclose(rigid_py.fixedParameters, np.array([64.0, 64.0]))
np.testing.assert_allclose(rigid_py.parameters, np.array([0.0, 64.0, 64.0]))

# Verify affine transform
affine_py = transform_list_py[2]
assert affine_py.transformType.transformParameterization == TransformParameterizations.Affine
assert affine_py.transformType.parametersValueType == FloatTypes.Float32
assert affine_py.transformType.inputDimension == 2
assert affine_py.transformType.outputDimension == 2
assert affine_py.numberOfFixedParameters == 2
assert affine_py.numberOfParameters == 6
np.testing.assert_allclose(affine_py.fixedParameters, np.array([64.0, 64.0]))
np.testing.assert_allclose(affine_py.parameters, np.array([1.0, 0.0, 0.0, 1.0, 0.0, 0.0]))


@copy_files_to_pyodide(file_list=file_list, install_wheels=True)
@run_in_pyodide(packages=["numpy"])
async def test_binary_stream_conversion(selenium):
Expand Down
Loading
Loading