Skip to content

Commit

Permalink
feat(compare-images): add compare-images-node.ts
Browse files Browse the repository at this point in the history
  • Loading branch information
thewtex committed Aug 21, 2023
1 parent c3a17aa commit dab81de
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@ def compare_images(
) -> Tuple[Dict, Image, Image]:
"""Compare double pixel type images with a tolerance for regression testing.
For multi-component images, the intensity difference threshold
is based on the pixel vector magnitude.
:param test_image: The input test image
:type test_image: Image
Expand Down Expand Up @@ -68,5 +71,3 @@ def compare_images(
baseline_images_double = [_to_scalar_double(baseline_image) for baseline_image in baseline_images]

return compare_double_images(test_image_double, baseline_images=baseline_images_double, difference_threshold=difference_threshold, radius_tolerance=radius_tolerance, number_of_pixels_tolerance=number_of_pixels_tolerance, ignore_boundary_pixels=ignore_boundary_pixels)


64 changes: 64 additions & 0 deletions packages/compare-images/typescript/src/compare-images-node.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import {
Image,
FloatTypes,
PixelTypes,
castImage,
} from 'itk-wasm'

import CompareDoubleImagesOptions from './compare-double-images-options.js'
import CompareDoubleImagesNodeResult from './compare-double-images-node-result.js'
import compareDoubleImagesNode from './compare-double-images-node.js'
import vectorMagnitudeNode from './vector-magnitude-node.js'

async function _toScalarDouble(image: Image): Promise<Image> {
let scalarDouble = image

if (scalarDouble.imageType.componentType !== FloatTypes.Float64) {
let pixelType = undefined
if (image.imageType.pixelType !== PixelTypes.Scalar && image.imageType.pixelType !== PixelTypes.VariableLengthVector) {
pixelType = PixelTypes.VariableLengthVector
}
scalarDouble = castImage(image, { componentType: FloatTypes.Float64, pixelType })
} else {
if (image.imageType.pixelType !== PixelTypes.Scalar && image.imageType.pixelType !== PixelTypes.VariableLengthVector) {
const pixelType = PixelTypes.VariableLengthVector
scalarDouble = castImage(image, { pixelType })
}
}

if (scalarDouble.imageType.pixelType === PixelTypes.VariableLengthVector) {
const magnitude = await vectorMagnitudeNode(scalarDouble)
scalarDouble = magnitude.magnitudeImage
}

return scalarDouble
}

/**
* Compare images with a tolerance for regression testing.
*
* For multi-component images, the intensity difference threshold
* is based on the pixel vector magnitude.
*
* @param {Image} testImage - The input test image
* @param {CompareDoubleImagesOptions} options - options object
*
* @returns {Promise<CompareDoubleImagesNodeResult>} - result object
*/
async function compareImagesNode(
testImage: Image,
options: CompareDoubleImagesOptions = { baselineImages: [] as Image[], }
) : Promise<CompareDoubleImagesNodeResult> {

const testImageDouble = await _toScalarDouble(testImage)
const baselineImagesDouble = await Promise.all(options.baselineImages.map(async (image) => {
return await _toScalarDouble(image)
}))

const otherOptions = { ...options }
otherOptions.baselineImages = baselineImagesDouble

return compareDoubleImagesNode(testImageDouble, otherOptions)
}

export default compareImagesNode
3 changes: 3 additions & 0 deletions packages/compare-images/typescript/src/index-node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,6 @@ export type { CompareDoubleImagesOptions }

import compareDoubleImagesNode from './compare-double-images-node.js'
export { compareDoubleImagesNode }

import compareImagesNode from './compare-images-node.js'
export { compareImagesNode }
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import test from 'ava'
import path from 'path'

import { compareImagesNode } from '../../dist/bundles/compare-images-node.js'
import { readImageLocalFile } from 'itk-wasm'

const inputPathPrefix = '../test/data/input/'

test('compareImagesNode produces the expected metrics and difference images for uint8 inputs', async t => {
const testImageFile = 'cake_easy.png'
const testImagePath = path.join(inputPathPrefix, testImageFile)
const testImage = await readImageLocalFile(testImagePath)

const baselineImageFile = 'cake_hard.png'
const baselineImagePath = path.join(inputPathPrefix, baselineImageFile)
const baselineImage = await readImageLocalFile(baselineImagePath)

const { metrics, differenceImage, differenceUchar2dImage } = await compareImagesNode(testImage, { baselineImages: [baselineImage,] })

t.is(metrics.almostEqual, false)
t.is(metrics.numberOfPixelsWithDifferences, 9915)
t.is(metrics.minimumDifference, 1.0)
t.is(metrics.maximumDifference, 107.0)
t.is(metrics.totalDifference, 337334.0)
t.is(metrics.meanDifference, 34.02259203227433)

t.is(differenceImage.imageType.componentType, 'float64')
t.is(differenceUchar2dImage.imageType.componentType, 'uint8')
})

test('compareImagesNode produces the expected metrics and difference images for rgb inputs', async t => {
const testImageFile = 'apple.jpg'
const testImagePath = path.join(inputPathPrefix, testImageFile)
const testImage = await readImageLocalFile(testImagePath)

const baselineImageFile = 'orange.jpg'
const baselineImagePath = path.join(inputPathPrefix, baselineImageFile)
const baselineImage = await readImageLocalFile(baselineImagePath)

const { metrics, differenceImage, differenceUchar2dImage } = await compareImagesNode(testImage, { baselineImages: [baselineImage,] })

t.is(metrics.almostEqual, false)
t.is(metrics.numberOfPixelsWithDifferences, 26477)
t.is(metrics.minimumDifference, 0.002273026683894841)
t.is(metrics.maximumDifference, 312.2511648746159)
t.is(metrics.totalDifference, 3121703.1639738297)
t.is(metrics.meanDifference, 117.90244982338746)

t.is(differenceImage.imageType.componentType, 'float64')
t.is(differenceUchar2dImage.imageType.componentType, 'uint8')
})

0 comments on commit dab81de

Please sign in to comment.