diff --git a/packages/compare-images/python/itkwasm-compare-images-emscripten/README.md b/packages/compare-images/python/itkwasm-compare-images-emscripten/README.md
new file mode 100644
index 000000000..e5270efcf
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images-emscripten/README.md
@@ -0,0 +1,23 @@
+# itkwasm-compare-images-emscripten
+
+[![PyPI version](https://badge.fury.io/py/itkwasm-compare-images-emscripten.svg)](https://badge.fury.io/py/itkwasm-compare-images-emscripten)
+
+Read files and images related to compare-images file format. Emscripten implementation.
+
+This package provides the Emscripten WebAssembly implementation. It is usually not called directly. Please use the [`itkwasm-compare-images`](https://pypi.org/project/itkwasm-compare-images/) instead.
+
+
+## Installation
+
+```sh
+import micropip
+await micropip.install('itkwasm-compare-images-emscripten')
+```
+
+## Development
+
+```sh
+pip install hatch
+hatch run download-pyodide
+hatch run test
+```
diff --git a/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/__init__.py b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/__init__.py
new file mode 100644
index 000000000..bc8eb0467
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/__init__.py
@@ -0,0 +1,5 @@
+"""itkwasm-compare-images-emscripten: Read files and images related to compare-images file format. Emscripten implementation."""
+
+from .compare_double_images_async import compare_double_images_async
+
+from ._version import __version__
diff --git a/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/_version.py b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/_version.py
new file mode 100644
index 000000000..5becc17c0
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/_version.py
@@ -0,0 +1 @@
+__version__ = "1.0.0"
diff --git a/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/compare_double_images_async.py b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/compare_double_images_async.py
new file mode 100644
index 000000000..5b2ae21e0
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/compare_double_images_async.py
@@ -0,0 +1,86 @@
+# Generated file. Do not edit.
+
+from pathlib import Path
+import os
+from typing import Dict, Tuple, Optional, List, Any
+
+from .js_package import js_package
+
+from itkwasm.pyodide import (
+ to_js,
+ to_py,
+ js_resources
+)
+from itkwasm import (
+ InterfaceTypes,
+ Image,
+)
+
+async def compare_double_images_async(
+ test_image: Image,
+ baseline_images: List[Image] = [],
+ difference_threshold: float = 0,
+ radius_tolerance: int = 0,
+ number_of_pixels_tolerance: int = 0,
+ ignore_boundary_pixels: bool = False,
+) -> Tuple[Dict, Image, Image]:
+ """Compare double pixel type images with a tolerance for regression testing.
+
+ :param test_image: The input test image
+ :type test_image: Image
+
+ :param baseline_images: Baseline images compare against
+ :type baseline_images: Image
+
+ :param difference_threshold: Intensity difference for pixels to be considered different.
+ :type difference_threshold: float
+
+ :param radius_tolerance: Radius of the neighborhood around a pixel to search for similar intensity values.
+ :type radius_tolerance: int
+
+ :param number_of_pixels_tolerance: Number of pixels that can be different before the test fails.
+ :type number_of_pixels_tolerance: int
+
+ :param ignore_boundary_pixels: Ignore boundary pixels. Useful when resampling may have introduced difference pixel values along the image edge.
+ :type ignore_boundary_pixels: bool
+
+ :return: Metrics for the baseline with the fewest number of pixels outside the tolerances.
+ :rtype: Dict
+
+ :return: Absolute difference image
+ :rtype: Image
+
+ :return: Unsigned char, 2D difference image for rendering
+ :rtype: Image
+ """
+ js_module = await js_package.js_module
+ web_worker = js_resources.web_worker
+
+ kwargs = {}
+ if baseline_images is not None:
+ kwargs["baselineImages"] = to_js(baseline_images)
+ if difference_threshold:
+ kwargs["differenceThreshold"] = to_js(difference_threshold)
+ if radius_tolerance:
+ kwargs["radiusTolerance"] = to_js(radius_tolerance)
+ if number_of_pixels_tolerance:
+ kwargs["numberOfPixelsTolerance"] = to_js(number_of_pixels_tolerance)
+ if ignore_boundary_pixels:
+ kwargs["ignoreBoundaryPixels"] = to_js(ignore_boundary_pixels)
+
+ outputs = await js_module.compareDoubleImages(web_worker, to_js(test_image), **kwargs)
+
+ output_web_worker = None
+ output_list = []
+ outputs_object_map = outputs.as_object_map()
+ for output_name in outputs.object_keys():
+ if output_name == 'webWorker':
+ output_web_worker = outputs_object_map[output_name]
+ else:
+ output_list.append(to_py(outputs_object_map[output_name]))
+
+ js_resources.web_worker = output_web_worker
+
+ if len(output_list) == 1:
+ return output_list[0]
+ return tuple(output_list)
diff --git a/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/js_package.py b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/js_package.py
new file mode 100644
index 000000000..a940ad6cd
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images-emscripten/itkwasm_compare_images_emscripten/js_package.py
@@ -0,0 +1,6 @@
+from itkwasm.pyodide import JsPackageConfig, JsPackage
+
+from ._version import __version__
+
+default_config = JsPackageConfig(f"https://cdn.jsdelivr.net/npm/@itk-wasm/compare-images@{__version__}/dist/bundles/compare-images.js")
+js_package = JsPackage(default_config)
diff --git a/packages/compare-images/python/itkwasm-compare-images-emscripten/pyproject.toml b/packages/compare-images/python/itkwasm-compare-images-emscripten/pyproject.toml
new file mode 100644
index 000000000..49cd962f2
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images-emscripten/pyproject.toml
@@ -0,0 +1,72 @@
+[build-system]
+requires = ["hatchling", "hatch-vcs"]
+build-backend = "hatchling.build"
+
+[project]
+name = "itkwasm-compare-images-emscripten"
+readme = "README.md"
+license = "Apache-2.0"
+dynamic = ["version", "description"]
+classifiers = [
+ "License :: OSI Approved :: Apache Software License",
+ "Programming Language :: Python",
+ "Programming Language :: C++",
+ "Environment :: WebAssembly",
+ "Environment :: WebAssembly :: Emscripten",
+ "Environment :: WebAssembly :: WASI",
+ "Development Status :: 3 - Alpha",
+ "Intended Audience :: Developers",
+ "Intended Audience :: Science/Research",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.7",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+]
+keywords = [
+ "itkwasm",
+ "webassembly",
+ "emscripten",
+]
+
+requires-python = ">=3.7"
+dependencies = [
+ "itkwasm >= 1.0.b105",
+]
+
+[tool.hatch.version]
+path = "itkwasm_compare_images_emscripten/_version.py"
+
+[tool.hatch.envs.default]
+dependencies = [
+ "pytest",
+ "pytest-pyodide",
+]
+
+[project.urls]
+Home = "https://github.com/InsightSoftwareConsortium/itk-wasm"
+Source = "https://github.com/InsightSoftwareConsortium/itk-wasm"
+
+[tool.hatch.envs.default.scripts]
+test = [
+ "hatch build -t wheel",
+ "pytest --dist-dir=./dist --rt=chrome",
+]
+download-pyodide = [
+ "curl -L https://github.com/pyodide/pyodide/releases/download/0.23.1/pyodide-0.23.1.tar.bz2 -o pyodide.tar.bz2",
+ "tar xjf pyodide.tar.bz2",
+ "rm -rf dist pyodide.tar.bz2",
+ "mv pyodide dist",
+]
+serve = [
+ "hatch build -t wheel",
+ 'echo "\nVisit http://localhost:8877/console.html\n"',
+ "python -m http.server --directory=./dist 8877",
+]
+
+
+[tool.hatch.build]
+exclude = [
+ "/examples",
+]
diff --git a/packages/compare-images/python/itkwasm-compare-images-emscripten/test/test_itkwasm_compare_images.py b/packages/compare-images/python/itkwasm-compare-images-emscripten/test/test_itkwasm_compare_images.py
new file mode 100644
index 000000000..4b92204d8
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images-emscripten/test/test_itkwasm_compare_images.py
@@ -0,0 +1,20 @@
+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 itkwasm_compare_images_emscripten import __version__ as test_package_version
+
+@pytest.fixture
+def package_wheel():
+ return f"itkwasm_compare_images_emscripten-{test_package_version}-py3-none-any.whl"
+
+@run_in_pyodide(packages=['micropip'])
+async def test_example(selenium, package_wheel):
+ import micropip
+ await micropip.install(package_wheel)
+
+ # Write your test code here
diff --git a/packages/compare-images/python/itkwasm-compare-images-wasi/README.md b/packages/compare-images/python/itkwasm-compare-images-wasi/README.md
new file mode 100644
index 000000000..57d22252c
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images-wasi/README.md
@@ -0,0 +1,26 @@
+# itkwasm-compare-images-wasi
+
+[![PyPI version](https://badge.fury.io/py/itkwasm-compare-images-wasi.svg)](https://badge.fury.io/py/itkwasm-compare-images-wasi)
+
+Read files and images related to compare-images file format. WASI implementation.
+
+This package provides the WASI WebAssembly implementation. It is usually not called directly. Please use [`itkwasm-compare-images`](https://pypi.org/project/itkwasm-compare-images/) instead.
+
+
+## Installation
+
+```sh
+pip install itkwasm-compare-images-wasi
+```
+
+## Development
+
+```sh
+pip install pytest
+pip install -e .
+pytest
+
+# or
+pip install hatch
+hatch run test
+```
diff --git a/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/__init__.py b/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/__init__.py
new file mode 100644
index 000000000..d0d7c1621
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/__init__.py
@@ -0,0 +1,5 @@
+"""itkwasm-compare-images-wasi: Read files and images related to compare-images file format. WASI implementation."""
+
+from .compare_double_images import compare_double_images
+
+from ._version import __version__
diff --git a/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/_version.py b/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/_version.py
new file mode 100644
index 000000000..5becc17c0
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/_version.py
@@ -0,0 +1 @@
+__version__ = "1.0.0"
diff --git a/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/compare_double_images.py b/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/compare_double_images.py
new file mode 100644
index 000000000..065643baf
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/compare_double_images.py
@@ -0,0 +1,112 @@
+# Generated file. Do not edit.
+
+from pathlib import Path, PurePosixPath
+import os
+from typing import Dict, Tuple, Optional, List, Any
+
+from importlib_resources import files as file_resources
+
+_pipeline = None
+
+from itkwasm import (
+ InterfaceTypes,
+ PipelineOutput,
+ PipelineInput,
+ Pipeline,
+ Image,
+)
+
+def compare_double_images(
+ test_image: Image,
+ baseline_images: List[Image] = [],
+ difference_threshold: float = 0,
+ radius_tolerance: int = 0,
+ number_of_pixels_tolerance: int = 0,
+ ignore_boundary_pixels: bool = False,
+) -> Tuple[Dict, Image, Image]:
+ """Compare double pixel type images with a tolerance for regression testing.
+
+ :param test_image: The input test image
+ :type test_image: Image
+
+ :param baseline_images: Baseline images compare against
+ :type baseline_images: Image
+
+ :param difference_threshold: Intensity difference for pixels to be considered different.
+ :type difference_threshold: float
+
+ :param radius_tolerance: Radius of the neighborhood around a pixel to search for similar intensity values.
+ :type radius_tolerance: int
+
+ :param number_of_pixels_tolerance: Number of pixels that can be different before the test fails.
+ :type number_of_pixels_tolerance: int
+
+ :param ignore_boundary_pixels: Ignore boundary pixels. Useful when resampling may have introduced difference pixel values along the image edge.
+ :type ignore_boundary_pixels: bool
+
+ :return: Metrics for the baseline with the fewest number of pixels outside the tolerances.
+ :rtype: Dict
+
+ :return: Absolute difference image
+ :rtype: Image
+
+ :return: Unsigned char, 2D difference image for rendering
+ :rtype: Image
+ """
+ global _pipeline
+ if _pipeline is None:
+ _pipeline = Pipeline(file_resources('itkwasm_compare_images_wasi').joinpath(Path('wasm_modules') / Path('compare-double-images.wasi.wasm')))
+
+ pipeline_outputs: List[PipelineOutput] = [
+ PipelineOutput(InterfaceTypes.JsonObject),
+ PipelineOutput(InterfaceTypes.Image),
+ PipelineOutput(InterfaceTypes.Image),
+ ]
+
+ pipeline_inputs: List[PipelineInput] = [
+ PipelineInput(InterfaceTypes.Image, test_image),
+ ]
+
+ args: List[str] = ['--memory-io',]
+ # Inputs
+ args.append('0')
+ # Outputs
+ args.append('0')
+ args.append('1')
+ args.append('2')
+ # Options
+ if len(baseline_images) > 1:
+ if len(baseline_images) < 1:
+ raise ValueError('"baseline-images" option must have a length > 1')
+
+ args.append('--baseline-images')
+ for value in baseline_images:
+ input_count_string = str(len(pipeline_inputs))
+ pipeline_inputs.push(PipelineInput(InterfaceTypes.Image, value))
+ args.append(input_count_string)
+
+ if difference_threshold:
+ args.append('--difference-threshold')
+ args.append(str(difference_threshold))
+
+ if radius_tolerance:
+ args.append('--radius-tolerance')
+ args.append(str(radius_tolerance))
+
+ if number_of_pixels_tolerance:
+ args.append('--number-of-pixels-tolerance')
+ args.append(str(number_of_pixels_tolerance))
+
+ if ignore_boundary_pixels:
+ args.append('--ignore-boundary-pixels')
+
+
+ outputs = _pipeline.run(args, pipeline_outputs, pipeline_inputs)
+
+ result = (
+ outputs[0].data,
+ outputs[1].data,
+ outputs[2].data,
+ )
+ return result
+
diff --git a/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/wasm_modules/compare-double-images.wasi.wasm b/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/wasm_modules/compare-double-images.wasi.wasm
new file mode 100755
index 000000000..faa55383d
Binary files /dev/null and b/packages/compare-images/python/itkwasm-compare-images-wasi/itkwasm_compare_images_wasi/wasm_modules/compare-double-images.wasi.wasm differ
diff --git a/packages/compare-images/python/itkwasm-compare-images-wasi/pyproject.toml b/packages/compare-images/python/itkwasm-compare-images-wasi/pyproject.toml
new file mode 100644
index 000000000..ceb1628f7
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images-wasi/pyproject.toml
@@ -0,0 +1,59 @@
+[build-system]
+requires = ["hatchling", "hatch-vcs"]
+build-backend = "hatchling.build"
+
+[project]
+name = "itkwasm-compare-images-wasi"
+readme = "README.md"
+license = "Apache-2.0"
+dynamic = ["version", "description"]
+classifiers = [
+ "License :: OSI Approved :: Apache Software License",
+ "Programming Language :: Python",
+ "Programming Language :: C++",
+ "Environment :: WebAssembly",
+ "Environment :: WebAssembly :: Emscripten",
+ "Environment :: WebAssembly :: WASI",
+ "Development Status :: 3 - Alpha",
+ "Intended Audience :: Developers",
+ "Intended Audience :: Science/Research",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.7",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+]
+keywords = [
+ "itkwasm",
+ "webassembly",
+ "wasi",
+]
+
+requires-python = ">=3.7"
+dependencies = [
+ "itkwasm >= 1.0.b105",
+ "importlib_resources",
+
+]
+
+[tool.hatch.version]
+path = "itkwasm_compare_images_wasi/_version.py"
+
+[tool.hatch.envs.default]
+dependencies = [
+ "pytest",
+]
+
+[project.urls]
+Home = "https://github.com/InsightSoftwareConsortium/itk-wasm"
+Source = "https://github.com/InsightSoftwareConsortium/itk-wasm"
+
+[tool.hatch.envs.default.scripts]
+test = "pytest"
+
+
+[tool.hatch.build]
+exclude = [
+ "/examples",
+]
diff --git a/packages/compare-images/python/itkwasm-compare-images/README.md b/packages/compare-images/python/itkwasm-compare-images/README.md
new file mode 100644
index 000000000..e45cb12d2
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images/README.md
@@ -0,0 +1,11 @@
+# itkwasm-compare-images
+
+[![PyPI version](https://badge.fury.io/py/itkwasm-compare-images.svg)](https://badge.fury.io/py/itkwasm-compare-images)
+
+Read files and images related to compare-images file format.
+
+## Installation
+
+```sh
+pip install itkwasm-compare-images
+```
diff --git a/packages/compare-images/python/itkwasm-compare-images/docs/Makefile b/packages/compare-images/python/itkwasm-compare-images/docs/Makefile
new file mode 100644
index 000000000..d4bb2cbb9
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images/docs/Makefile
@@ -0,0 +1,20 @@
+# Minimal makefile for Sphinx documentation
+#
+
+# You can set these variables from the command line, and also
+# from the environment for the first two.
+SPHINXOPTS ?=
+SPHINXBUILD ?= sphinx-build
+SOURCEDIR = .
+BUILDDIR = _build
+
+# Put it first so that "make" without argument is like "make help".
+help:
+ @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
+
+.PHONY: help Makefile
+
+# Catch-all target: route all unknown targets to Sphinx using the new
+# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
+%: Makefile
+ @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
diff --git a/packages/compare-images/python/itkwasm-compare-images/docs/_static/favicon.png b/packages/compare-images/python/itkwasm-compare-images/docs/_static/favicon.png
new file mode 100644
index 000000000..bd1e535c6
Binary files /dev/null and b/packages/compare-images/python/itkwasm-compare-images/docs/_static/favicon.png differ
diff --git a/packages/compare-images/python/itkwasm-compare-images/docs/_static/logo.svg b/packages/compare-images/python/itkwasm-compare-images/docs/_static/logo.svg
new file mode 100644
index 000000000..669a445ed
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images/docs/_static/logo.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/packages/compare-images/python/itkwasm-compare-images/docs/conf.py b/packages/compare-images/python/itkwasm-compare-images/docs/conf.py
new file mode 100644
index 000000000..a12ffb792
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images/docs/conf.py
@@ -0,0 +1,56 @@
+# Configuration file for the Sphinx documentation builder.
+#
+# For the full list of built-in configuration values, see the documentation:
+# https://www.sphinx-doc.org/en/master/usage/configuration.html
+
+# -- Project information -----------------------------------------------------
+# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
+
+from datetime import date
+
+project = 'itkwasm-compare-images'
+copyright = f'{date.today().year}, NumFOCUS'
+author = 'Insight Software Consortium'
+
+extensions = [
+ 'sphinx.ext.autosummary',
+ 'autodoc2',
+ 'myst_parser',
+ 'sphinx.ext.intersphinx',
+ 'sphinx_copybutton',
+ 'sphinxext.opengraph',
+ 'sphinx_design',
+]
+
+myst_enable_extensions = ["colon_fence", "fieldlist"]
+
+templates_path = ['_templates']
+exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
+
+autodoc2_packages = [
+ {
+ "path": "../itkwasm_compare_images",
+ "exclude_files": ["_version.py"],
+ },
+]
+autodoc2_render_plugin = "myst"
+
+intersphinx_mapping = {
+ "python": ("https://docs.python.org/3/", None),
+ "numpy": ("https://numpy.org/doc/stable", None),
+ "itkwasm": ("https://itkwasm.readthedocs.io/en/latest/", None),
+}
+
+html_theme = 'furo'
+html_static_path = ['_static']
+html_logo = "_static/logo.svg"
+html_favicon = "_static/favicon.png"
+html_title = f"{project}"
+
+# Furo options
+html_theme_options = {
+ "top_of_page_button": "edit",
+ "source_repository": "https://github.com/InsightSoftwareConsortium/itk-wasm",
+ "source_branch": "main",
+ "source_directory": "docs",
+}
\ No newline at end of file
diff --git a/packages/compare-images/python/itkwasm-compare-images/docs/index.md b/packages/compare-images/python/itkwasm-compare-images/docs/index.md
new file mode 100644
index 000000000..869640205
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images/docs/index.md
@@ -0,0 +1,35 @@
+itkwasm-compare-images
+=======
+
+> Read files and images related to compare-images file format.
+
+[![itkwasm-compare-images version](https://badge.fury.io/py/itkwasm_compare_images.svg)](https://pypi.org/project/itkwasm_compare_images/)
+
+## Installation
+
+::::{tab-set}
+
+:::{tab-item} System
+```shell
+pip install itkwasm-compare-images
+```
+:::
+
+:::{tab-item} Browser
+In Pyodide, e.g. the [Pyodide REPL](https://pyodide.org/en/stable/console.html) or [JupyterLite](https://jupyterlite.readthedocs.io/en/latest/try/lab),
+
+```python
+import micropip
+await micropip.install('itkwasm-compare-images')
+:::
+
+::::
+
+```{toctree}
+:hidden:
+:maxdepth: 3
+:caption: 📖 Reference
+
+apidocs/index.rst
+itkwasm docs
+```
\ No newline at end of file
diff --git a/packages/compare-images/python/itkwasm-compare-images/docs/make.bat b/packages/compare-images/python/itkwasm-compare-images/docs/make.bat
new file mode 100644
index 000000000..32bb24529
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images/docs/make.bat
@@ -0,0 +1,35 @@
+@ECHO OFF
+
+pushd %~dp0
+
+REM Command file for Sphinx documentation
+
+if "%SPHINXBUILD%" == "" (
+ set SPHINXBUILD=sphinx-build
+)
+set SOURCEDIR=.
+set BUILDDIR=_build
+
+%SPHINXBUILD% >NUL 2>NUL
+if errorlevel 9009 (
+ echo.
+ echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
+ echo.installed, then set the SPHINXBUILD environment variable to point
+ echo.to the full path of the 'sphinx-build' executable. Alternatively you
+ echo.may add the Sphinx directory to PATH.
+ echo.
+ echo.If you don't have Sphinx installed, grab it from
+ echo.https://www.sphinx-doc.org/
+ exit /b 1
+)
+
+if "%1" == "" goto help
+
+%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+goto end
+
+:help
+%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O%
+
+:end
+popd
diff --git a/packages/compare-images/python/itkwasm-compare-images/docs/requirements.txt b/packages/compare-images/python/itkwasm-compare-images/docs/requirements.txt
new file mode 100644
index 000000000..eaed1dc05
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images/docs/requirements.txt
@@ -0,0 +1,7 @@
+sphinx
+furo
+sphinx-autodoc2
+myst-parser
+sphinx-copybutton
+sphinxext-opengraph
+sphinx-design
\ No newline at end of file
diff --git a/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/__init__.py b/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/__init__.py
new file mode 100644
index 000000000..72ceb7536
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/__init__.py
@@ -0,0 +1,6 @@
+"""itkwasm-compare-images: Read files and images related to compare-images file format."""
+
+from .compare_double_images_async import compare_double_images_async
+from .compare_double_images import compare_double_images
+
+from ._version import __version__
diff --git a/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/_version.py b/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/_version.py
new file mode 100644
index 000000000..5becc17c0
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/_version.py
@@ -0,0 +1 @@
+__version__ = "1.0.0"
diff --git a/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/compare_double_images.py b/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/compare_double_images.py
new file mode 100644
index 000000000..748075827
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/compare_double_images.py
@@ -0,0 +1,50 @@
+# Generated file. Do not edit.
+
+import os
+from typing import Dict, Tuple, Optional, List, Any
+
+from itkwasm import (
+ environment_dispatch,
+ Image,
+)
+
+def compare_double_images(
+ test_image: Image,
+ baseline_images: List[Image] = [],
+ difference_threshold: float = 0,
+ radius_tolerance: int = 0,
+ number_of_pixels_tolerance: int = 0,
+ ignore_boundary_pixels: bool = False,
+) -> Tuple[Dict, Image, Image]:
+ """Compare double pixel type images with a tolerance for regression testing.
+
+ :param test_image: The input test image
+ :type test_image: Image
+
+ :param baseline_images: Baseline images compare against
+ :type baseline_images: Image
+
+ :param difference_threshold: Intensity difference for pixels to be considered different.
+ :type difference_threshold: float
+
+ :param radius_tolerance: Radius of the neighborhood around a pixel to search for similar intensity values.
+ :type radius_tolerance: int
+
+ :param number_of_pixels_tolerance: Number of pixels that can be different before the test fails.
+ :type number_of_pixels_tolerance: int
+
+ :param ignore_boundary_pixels: Ignore boundary pixels. Useful when resampling may have introduced difference pixel values along the image edge.
+ :type ignore_boundary_pixels: bool
+
+ :return: Metrics for the baseline with the fewest number of pixels outside the tolerances.
+ :rtype: Dict
+
+ :return: Absolute difference image
+ :rtype: Image
+
+ :return: Unsigned char, 2D difference image for rendering
+ :rtype: Image
+ """
+ func = environment_dispatch("itkwasm_compare_images", "compare_double_images")
+ output = func(test_image, baseline_images=baseline_images, difference_threshold=difference_threshold, radius_tolerance=radius_tolerance, number_of_pixels_tolerance=number_of_pixels_tolerance, ignore_boundary_pixels=ignore_boundary_pixels)
+ return output
diff --git a/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/compare_double_images_async.py b/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/compare_double_images_async.py
new file mode 100644
index 000000000..4b312e555
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images/itkwasm_compare_images/compare_double_images_async.py
@@ -0,0 +1,50 @@
+# Generated file. Do not edit.
+
+import os
+from typing import Dict, Tuple, Optional, List, Any
+
+from itkwasm import (
+ environment_dispatch,
+ Image,
+)
+
+async def compare_double_images_async(
+ test_image: Image,
+ baseline_images: List[Image] = [],
+ difference_threshold: float = 0,
+ radius_tolerance: int = 0,
+ number_of_pixels_tolerance: int = 0,
+ ignore_boundary_pixels: bool = False,
+) -> Tuple[Dict, Image, Image]:
+ """Compare double pixel type images with a tolerance for regression testing.
+
+ :param test_image: The input test image
+ :type test_image: Image
+
+ :param baseline_images: Baseline images compare against
+ :type baseline_images: Image
+
+ :param difference_threshold: Intensity difference for pixels to be considered different.
+ :type difference_threshold: float
+
+ :param radius_tolerance: Radius of the neighborhood around a pixel to search for similar intensity values.
+ :type radius_tolerance: int
+
+ :param number_of_pixels_tolerance: Number of pixels that can be different before the test fails.
+ :type number_of_pixels_tolerance: int
+
+ :param ignore_boundary_pixels: Ignore boundary pixels. Useful when resampling may have introduced difference pixel values along the image edge.
+ :type ignore_boundary_pixels: bool
+
+ :return: Metrics for the baseline with the fewest number of pixels outside the tolerances.
+ :rtype: Dict
+
+ :return: Absolute difference image
+ :rtype: Image
+
+ :return: Unsigned char, 2D difference image for rendering
+ :rtype: Image
+ """
+ func = environment_dispatch("itkwasm_compare_images", "compare_double_images_async")
+ output = await func(test_image, baseline_images=baseline_images, difference_threshold=difference_threshold, radius_tolerance=radius_tolerance, number_of_pixels_tolerance=number_of_pixels_tolerance, ignore_boundary_pixels=ignore_boundary_pixels)
+ return output
diff --git a/packages/compare-images/python/itkwasm-compare-images/pyproject.toml b/packages/compare-images/python/itkwasm-compare-images/pyproject.toml
new file mode 100644
index 000000000..d311dc0a5
--- /dev/null
+++ b/packages/compare-images/python/itkwasm-compare-images/pyproject.toml
@@ -0,0 +1,61 @@
+[build-system]
+requires = ["hatchling", "hatch-vcs"]
+build-backend = "hatchling.build"
+
+[project]
+name = "itkwasm-compare-images"
+readme = "README.md"
+license = "Apache-2.0"
+dynamic = ["version", "description"]
+classifiers = [
+ "License :: OSI Approved :: Apache Software License",
+ "Programming Language :: Python",
+ "Programming Language :: C++",
+ "Environment :: WebAssembly",
+ "Environment :: WebAssembly :: Emscripten",
+ "Environment :: WebAssembly :: WASI",
+ "Development Status :: 3 - Alpha",
+ "Intended Audience :: Developers",
+ "Intended Audience :: Science/Research",
+ "Programming Language :: Python :: 3",
+ "Programming Language :: Python :: 3.7",
+ "Programming Language :: Python :: 3.8",
+ "Programming Language :: Python :: 3.9",
+ "Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
+]
+keywords = [
+ "itkwasm",
+ "webassembly",
+ "wasi",
+ "emscripten",
+]
+
+requires-python = ">=3.7"
+dependencies = [
+ "itkwasm >= 1.0.b105",
+ "itkwasm-compare-images-wasi; sys_platform != \"emscripten\"",
+ "itkwasm-compare-images-emscripten; sys_platform == \"emscripten\"",
+
+]
+
+[tool.hatch.version]
+path = "itkwasm_compare_images/_version.py"
+
+[tool.hatch.envs.default]
+dependencies = [
+ "pytest",
+]
+
+[project.urls]
+Home = "https://github.com/InsightSoftwareConsortium/itk-wasm"
+Source = "https://github.com/InsightSoftwareConsortium/itk-wasm"
+
+[tool.hatch.envs.default.scripts]
+test = "pytest"
+
+
+[tool.hatch.build]
+exclude = [
+ "/examples",
+]