Skip to content

Commit

Permalink
feat(compare-images): add compare_images.py, compare_images_async.py …
Browse files Browse the repository at this point in the history
…to dispatch
  • Loading branch information
thewtex committed Aug 22, 2023
1 parent 9b20e09 commit 827e10c
Show file tree
Hide file tree
Showing 9 changed files with 355 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from .compare_double_images_async import compare_double_images_async
from .compare_double_images import compare_double_images
from .compare_images_async import compare_images_async
from .compare_images import compare_images
from .vector_magnitude_async import vector_magnitude_async
from .vector_magnitude import vector_magnitude

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import os
from typing import Dict, Tuple, Optional, List, Any

from itkwasm import (
environment_dispatch,
Image,
)

def compare_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[Any, Image, Image]:
"""Compare 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: Any
:return: Absolute difference image
:rtype: Image
:return: Unsigned char, 2D difference image for rendering
:rtype: Image
"""
func = environment_dispatch("itkwasm_compare_images", "compare_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
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import os
from typing import Dict, Tuple, Optional, List, Any

from itkwasm import (
environment_dispatch,
Image,
)

async def compare_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[Any, Image, Image]:
"""Compare 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: Any
:return: Absolute difference image
:rtype: Image
:return: Unsigned char, 2D difference image for rendering
:rtype: Image
"""
func = environment_dispatch("itkwasm_compare_images", "compare_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
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,26 @@ path = "itkwasm_compare_images/_version.py"
[tool.hatch.envs.default]
dependencies = [
"pytest",
"pytest-pyodide",
"itk-webassemblyinterface >= 1.0.b127",
"itkwasm >= 1.0.b130",
]

[project.urls]
Home = "https://github.com/InsightSoftwareConsortium/itk-wasm"
Source = "https://github.com/InsightSoftwareConsortium/itk-wasm"

[tool.hatch.envs.default.scripts]
test = "pytest"

test = [
"hatch build -t wheel",
"pytest -s --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",
]

[tool.hatch.build]
exclude = [
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import pytest
import sys
import pickle

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

from itkwasm_compare_images import __version__ as test_package_version

@pytest.fixture
def package_wheel():
return f"itkwasm_compare_images-{test_package_version}-py3-none-any.whl"

@pytest.fixture
def input_data():
from pathlib import Path
input_base_path = Path('..', '..', 'test', 'data')
test_files = [
Path('input') / 'cake_easy.iwi.cbor',
Path('input') / 'cake_hard.iwi.cbor',
Path('input') / 'cake_easy.png',
Path('input') / 'cake_hard.png',
Path('input') / 'apple.jpg',
Path('input') / 'orange.jpg',
]
data = {}
for f in test_files:
path = str(input_base_path / f) + '.pickle'
with open(path, 'rb') as fp:
data[str(f.name)] = pickle.load(fp)
return data
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
from pathlib import Path
import itk
from itkwasm import Image

def test_compare_double_images():
from itkwasm_compare_images_wasi import compare_double_images

test_image_file = 'cake_easy.iwi.cbor'
test_image_path = Path('..', '..', 'test', 'data', 'input', test_image_file)
test_image = itk.imread(test_image_path)
test_dict = itk.dict_from_image(test_image)
test_image = Image(**test_dict)

baseline_image_file = 'cake_hard.iwi.cbor'
baseline_image_path = Path('..', '..', 'test', 'data', 'input', baseline_image_file)
baseline_image = itk.imread(baseline_image_path)
baseline_dict = itk.dict_from_image(baseline_image)
baseline_image = Image(**baseline_dict)

metrics, difference_image, difference_image_rendering = compare_double_images(test_image, baseline_images=[baseline_image])

assert metrics['almostEqual'] == False
assert metrics['numberOfPixelsWithDifferences'] == 9915
assert metrics['minimumDifference'] == 1.0
assert metrics['maximumDifference'] == 107.0
assert metrics['totalDifference'] == 337334.0
assert metrics['meanDifference'] == 34.02259203227433

assert difference_image.imageType.componentType == 'float64'
assert difference_image_rendering.imageType.componentType == 'uint8'
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
from pathlib import Path
import itk
from itkwasm import Image

def test_compare_double_images():
from itkwasm_compare_images import compare_images

test_image_file = 'cake_easy.iwi.cbor'
test_image_path = Path('..', '..', 'test', 'data', 'input', test_image_file)
test_image = itk.imread(test_image_path)
test_dict = itk.dict_from_image(test_image)
test_image = Image(**test_dict)

baseline_image_file = 'cake_hard.iwi.cbor'
baseline_image_path = Path('..', '..', 'test', 'data', 'input', baseline_image_file)
baseline_image = itk.imread(baseline_image_path)
baseline_dict = itk.dict_from_image(baseline_image)
baseline_image = Image(**baseline_dict)

metrics, difference_image, difference_image_rendering = compare_images(test_image, baseline_images=[baseline_image])

assert metrics['almostEqual'] == False
assert metrics['numberOfPixelsWithDifferences'] == 9915
assert metrics['minimumDifference'] == 1.0
assert metrics['maximumDifference'] == 107.0
assert metrics['totalDifference'] == 337334.0
assert metrics['meanDifference'] == 34.02259203227433

assert difference_image.imageType.componentType == 'float64'
assert difference_image_rendering.imageType.componentType == 'uint8'

def test_compare_uint8_images():
from itkwasm_compare_images import compare_images

test_image_file = 'cake_easy.png'
test_image_path = Path('..', '..', 'test', 'data', 'input', test_image_file)
test_image = itk.imread(test_image_path)
test_dict = itk.dict_from_image(test_image)
test_image = Image(**test_dict)

baseline_image_file = 'cake_hard.png'
baseline_image_path = Path('..', '..', 'test', 'data', 'input', baseline_image_file)
baseline_image = itk.imread(baseline_image_path)
baseline_dict = itk.dict_from_image(baseline_image)
baseline_image = Image(**baseline_dict)

metrics, difference_image, difference_image_rendering = compare_images(test_image, baseline_images=[baseline_image])

assert metrics['almostEqual'] == False
assert metrics['numberOfPixelsWithDifferences'] == 9915
assert metrics['minimumDifference'] == 1.0
assert metrics['maximumDifference'] == 107.0
assert metrics['totalDifference'] == 337334.0
assert metrics['meanDifference'] == 34.02259203227433

assert difference_image.imageType.componentType == 'float64'
assert difference_image_rendering.imageType.componentType == 'uint8'

def test_compare_rgb_images():
from itkwasm_compare_images import compare_images

test_image_file = 'apple.jpg'
test_image_path = Path('..', '..', 'test', 'data', 'input', test_image_file)
test_image = itk.imread(test_image_path)
test_dict = itk.dict_from_image(test_image)
test_image = Image(**test_dict)

baseline_image_file = 'orange.jpg'
baseline_image_path = Path('..', '..', 'test', 'data', 'input', baseline_image_file)
baseline_image = itk.imread(baseline_image_path)
baseline_dict = itk.dict_from_image(baseline_image)
baseline_image = Image(**baseline_dict)

metrics, difference_image, difference_image_rendering = compare_images(test_image, baseline_images=[baseline_image])

assert metrics['almostEqual'] == False
assert metrics['numberOfPixelsWithDifferences'] == 26477
assert metrics['minimumDifference'] == 0.002273026683894841
assert metrics['maximumDifference'] == 312.2511648746159
assert metrics['totalDifference'] == 3121656.100202402
assert metrics['meanDifference'] == 117.90067228924735

assert difference_image.imageType.componentType == 'float64'
assert difference_image_rendering.imageType.componentType == 'uint8'
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
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

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

from itkwasm_compare_images import compare_double_images_async
import numpy as np
from itkwasm import Image
from itkwasm.pyodide import to_js as itkwasm_to_js

test_image_file = 'cake_easy.iwi.cbor'
test_image = Image(**input_data[test_image_file])

baseline_image_file = 'cake_hard.iwi.cbor'
baseline_image = Image(**input_data[baseline_image_file])

metrics, difference_image, difference_image_rendering = await compare_double_images_async(test_image, baseline_images=[baseline_image])

assert metrics['almostEqual'] == False
assert metrics['numberOfPixelsWithDifferences'] == 9915
assert metrics['minimumDifference'] == 1.0
assert metrics['maximumDifference'] == 107.0
assert metrics['totalDifference'] == 337334.0
assert metrics['meanDifference'] == 34.02259203227433

assert difference_image.imageType.componentType == 'float64'
assert difference_image_rendering.imageType.componentType == 'uint8'

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

from itkwasm_compare_images import compare_images_async
import numpy as np
from itkwasm import Image
from itkwasm.pyodide import to_js as itkwasm_to_js

test_image_file = 'cake_easy.iwi.cbor'
test_image = Image(**input_data[test_image_file])

baseline_image_file = 'cake_hard.iwi.cbor'
baseline_image = Image(**input_data[baseline_image_file])

metrics, difference_image, difference_image_rendering = await compare_images_async(test_image, baseline_images=[baseline_image])

assert metrics['almostEqual'] == False
assert metrics['numberOfPixelsWithDifferences'] == 9915
assert metrics['minimumDifference'] == 1.0
assert metrics['maximumDifference'] == 107.0
assert metrics['totalDifference'] == 337334.0
assert metrics['meanDifference'] == 34.02259203227433

assert difference_image.imageType.componentType == 'float64'
assert difference_image_rendering.imageType.componentType == 'uint8'

test_image_file = 'cake_easy.png'
test_image = Image(**input_data[test_image_file])

baseline_image_file = 'cake_hard.png'
baseline_image = Image(**input_data[baseline_image_file])

metrics, difference_image, difference_image_rendering = await compare_images_async(test_image, baseline_images=[baseline_image])

assert metrics['almostEqual'] == False
assert metrics['numberOfPixelsWithDifferences'] == 9915
assert metrics['minimumDifference'] == 1.0
assert metrics['maximumDifference'] == 107.0
assert metrics['totalDifference'] == 337334.0
assert metrics['meanDifference'] == 34.02259203227433

assert difference_image.imageType.componentType == 'float64'
assert difference_image_rendering.imageType.componentType == 'uint8'

test_image_file = 'apple.jpg'
test_image = Image(**input_data[test_image_file])

baseline_image_file = 'orange.jpg'
baseline_image = Image(**input_data[baseline_image_file])

metrics, difference_image, difference_image_rendering = await compare_images_async(test_image, baseline_images=[baseline_image])

assert metrics['almostEqual'] == False
assert metrics['numberOfPixelsWithDifferences'] == 26477
assert metrics['minimumDifference'] == 0.002273026683894841
assert metrics['maximumDifference'] == 312.2511648746159
assert metrics['totalDifference'] == 3121656.100202402
assert metrics['meanDifference'] == 117.90067228924735

assert difference_image.imageType.componentType == 'float64'
assert difference_image_rendering.imageType.componentType == 'uint8'

0 comments on commit 827e10c

Please sign in to comment.