Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(castImage): Function to cast to pixelType, componentType
- Loading branch information
Showing
6 changed files
with
322 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
import { PixelTypes } from "../../../dist" | ||
import compareImageToBaseline from "../../support/compareImageToBaseline" | ||
|
||
describe('castImage', () => { | ||
beforeEach(() => { | ||
cy.visit('/') | ||
}) | ||
|
||
|
||
it('copies the input when no options are passed', () => { | ||
cy.window().then(async (win) => { | ||
const itk = win.itk | ||
|
||
const inputImageType = new itk.ImageType() | ||
const inputImage = new itk.Image(inputImageType) | ||
inputImage.size = [256, 256] | ||
inputImage.data = new Uint8Array(256*256) | ||
inputImage.data.fill(7) | ||
inputImage.origin = [3.0, 4.0] | ||
inputImage.spacing = [9.0, 4.0] | ||
inputImage.direction[0] = -1.0 | ||
|
||
const outputImage = itk.castImage(inputImage, {}) | ||
|
||
compareImageToBaseline(itk, outputImage, inputImage) | ||
}) | ||
}) | ||
|
||
|
||
it('casts to the specified pixel type', () => { | ||
cy.window().then(async (win) => { | ||
const itk = win.itk | ||
|
||
const inputImageType = new itk.ImageType() | ||
const inputImage = new itk.Image(inputImageType) | ||
inputImage.size = [256, 256] | ||
inputImage.data = new Uint8Array(256*256) | ||
inputImage.data.fill(7) | ||
|
||
const outputImage = itk.castImage(inputImage, { pixelType: itk.PixelTypes.CovariantVector }) | ||
|
||
const baseline = inputImage | ||
baseline.imageType.pixelType = itk.PixelTypes.CovariantVector | ||
|
||
compareImageToBaseline(itk, outputImage, baseline) | ||
}) | ||
}) | ||
|
||
|
||
it('throws an error when casting a multi-component image to a scalar image', () => { | ||
cy.window().then(async (win) => { | ||
const itk = win.itk | ||
|
||
const inputImageType = new itk.ImageType(2, itk.IntTypes.UInt8, itk.PixelTypes.Complex, 2) | ||
const inputImage = new itk.Image(inputImageType) | ||
inputImage.size = [256, 256] | ||
inputImage.data = new Uint8Array(256*256 * 2) | ||
inputImage.data.fill(7) | ||
|
||
expect(() => { | ||
itk.castImage(inputImage, { pixelType: itk.PixelTypes.Scalar }) | ||
}).to.throw() | ||
}) | ||
}) | ||
|
||
it('casts to another TypedArray component type', () => { | ||
cy.window().then(async (win) => { | ||
const itk = win.itk | ||
|
||
const inputImageType = new itk.ImageType() | ||
const inputImage = new itk.Image(inputImageType) | ||
inputImage.size = [256, 256] | ||
inputImage.data = new Uint8Array(256*256) | ||
inputImage.data.fill(7) | ||
|
||
const outputImage = itk.castImage(inputImage, { componentType: itk.FloatTypes.Float32 }) | ||
|
||
const baseline = inputImage | ||
baseline.imageType.componentType = itk.FloatTypes.Float32 | ||
baseline.data = new Float32Array(baseline.data) | ||
|
||
compareImageToBaseline(itk, outputImage, baseline) | ||
}) | ||
}) | ||
|
||
it('casts to a 64-bit integer component type', () => { | ||
cy.window().then(async (win) => { | ||
const itk = win.itk | ||
|
||
const inputImageType = new itk.ImageType() | ||
const inputImage = new itk.Image(inputImageType) | ||
inputImage.size = [256, 256] | ||
inputImage.data = new Uint8Array(256*256) | ||
inputImage.data.fill(7) | ||
|
||
const outputImage = itk.castImage(inputImage, { componentType: itk.IntTypes.UInt64 }) | ||
|
||
const baseline = inputImage | ||
baseline.imageType.componentType = itk.IntTypes.UInt64 | ||
baseline.data = new BigUint64Array(baseline.data.length) | ||
baseline.data.fill(7n) | ||
|
||
compareImageToBaseline(itk, outputImage, baseline) | ||
}) | ||
}) | ||
|
||
it('casts from 64-bit to TypedArray component type', () => { | ||
cy.window().then(async (win) => { | ||
const itk = win.itk | ||
|
||
const inputImageType = new itk.ImageType(2, itk.IntTypes.UInt64, itk.PixelTypes.Scalar, 1) | ||
const inputImage = new itk.Image(inputImageType) | ||
inputImage.size = [256, 256] | ||
inputImage.data = new BigUint64Array(256*256) | ||
inputImage.data.fill(7n) | ||
|
||
const outputImage = itk.castImage(inputImage, { componentType: itk.FloatTypes.Float32 }) | ||
|
||
const baseline = inputImage | ||
baseline.imageType.componentType = itk.FloatTypes.Float32 | ||
baseline.data = new Float32Array(baseline.data.length) | ||
baseline.data.fill(7) | ||
|
||
compareImageToBaseline(itk, outputImage, baseline) | ||
}) | ||
}) | ||
|
||
it('casts from 64-bit to another 64-bit integer component type', () => { | ||
cy.window().then(async (win) => { | ||
const itk = win.itk | ||
|
||
const inputImageType = new itk.ImageType() | ||
const inputImage = new itk.Image(inputImageType) | ||
inputImage.size = [256, 256] | ||
inputImage.data = new BigInt64Array(256*256) | ||
inputImage.data.fill(7n) | ||
|
||
const outputImage = itk.castImage(inputImage, { componentType: itk.IntTypes.UInt64 }) | ||
|
||
const baseline = inputImage | ||
baseline.imageType.componentType = itk.IntTypes.UInt64 | ||
baseline.data = new BigUint64Array(baseline.data.length) | ||
baseline.data.fill(7n) | ||
|
||
compareImageToBaseline(itk, outputImage, baseline) | ||
}) | ||
}) | ||
}) |
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import IntTypes from './IntTypes.js' | ||
import FloatTypes from './FloatTypes.js' | ||
import PixelTypes from './PixelTypes.js' | ||
|
||
interface CastImageOptions { | ||
/** Component type, from itk-wasm IntTypes, FloatTypes, for the output pixel components. Defaults to the input component type. */ | ||
componentType?: typeof IntTypes[keyof typeof IntTypes] | typeof FloatTypes[keyof typeof FloatTypes] | ||
|
||
/** Pixel type, from itk-wasm PixelTypes, for the output pixels. Defaults to the input pixel type. */ | ||
pixelType?: typeof PixelTypes[keyof typeof PixelTypes] | ||
} | ||
|
||
export default CastImageOptions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,159 @@ | ||
import Image from './Image.js' | ||
import CastImageOptions from './CastImageOptions.js' | ||
import PixelTypes from './PixelTypes.js' | ||
import IntTypes from './IntTypes.js' | ||
import FloatTypes from './FloatTypes.js' | ||
|
||
/** | ||
* Cast an image to another PixelType or ComponentType | ||
* | ||
* @param {Image} image - The input image | ||
* @param {CastImageOptions} options - specify the componentType and/or pixelType of the output | ||
*/ | ||
function castImage (inputImage: Image, options: CastImageOptions): Image { | ||
const outputImageType = { ...inputImage.imageType } | ||
|
||
if (typeof options.pixelType !== 'undefined') { | ||
outputImageType.pixelType = options.pixelType | ||
if (options.pixelType === PixelTypes.Scalar && outputImageType.components !== 1) { | ||
throw new Error('Cannot cast multi-component image to a scalar image') | ||
} | ||
} | ||
if (typeof options.componentType !== 'undefined' && options.componentType !== inputImage.imageType.componentType) { | ||
outputImageType.componentType = options.componentType | ||
} | ||
|
||
const outputImage = new Image(outputImageType) | ||
|
||
outputImage.name = inputImage.name | ||
outputImage.origin = Array.from(inputImage.origin) | ||
outputImage.spacing = Array.from(inputImage.spacing) | ||
outputImage.direction = inputImage.direction.slice() | ||
outputImage.size = Array.from(inputImage.size) | ||
outputImage.metadata = { ...inputImage.metadata } | ||
|
||
if (inputImage.data !== null) { | ||
if (typeof options.componentType !== 'undefined' && options.componentType !== inputImage.imageType.componentType) { | ||
switch (inputImage.imageType.componentType) { | ||
case IntTypes.UInt8: | ||
case IntTypes.Int8: | ||
case IntTypes.UInt16: | ||
case IntTypes.Int16: | ||
case IntTypes.UInt32: | ||
case IntTypes.Int32: | ||
case FloatTypes.Float32: | ||
case FloatTypes.Float64: | ||
switch (outputImage.imageType.componentType) { | ||
case IntTypes.UInt8: | ||
outputImage.data = new Uint8Array(inputImage.data) | ||
break | ||
case IntTypes.Int8: | ||
outputImage.data = new Int8Array(inputImage.data) | ||
break | ||
case IntTypes.UInt16: | ||
outputImage.data = new Uint16Array(inputImage.data) | ||
break | ||
case IntTypes.Int16: | ||
outputImage.data = new Int16Array(inputImage.data) | ||
break | ||
case IntTypes.UInt32: | ||
outputImage.data = new Uint32Array(inputImage.data) | ||
break | ||
case IntTypes.Int32: | ||
outputImage.data = new Int32Array(inputImage.data) | ||
break | ||
case FloatTypes.Float32: | ||
outputImage.data = new Float32Array(inputImage.data) | ||
break | ||
case FloatTypes.Float64: | ||
outputImage.data = new Float64Array(inputImage.data) | ||
break | ||
case IntTypes.UInt64: | ||
outputImage.data = new BigUint64Array(inputImage.data.length) | ||
for (let idx = 0; idx < outputImage.data.length; idx++) { | ||
outputImage.data[idx] = BigInt.asIntN(64, BigInt(inputImage.data[idx])) | ||
} | ||
break | ||
case IntTypes.Int64: | ||
outputImage.data = new BigInt64Array(inputImage.data.length) | ||
for (let idx = 0; idx < outputImage.data.length; idx++) { | ||
outputImage.data[idx] = BigInt.asUintN(64, BigInt(inputImage.data[idx])) | ||
} | ||
break | ||
} | ||
break | ||
case IntTypes.UInt64: | ||
case IntTypes.Int64: | ||
switch (outputImage.imageType.componentType) { | ||
case IntTypes.UInt8: | ||
outputImage.data = new Uint8Array(inputImage.data.length) | ||
for (let idx = 0; idx < outputImage.data.length; idx++) { | ||
outputImage.data[idx] = Number(inputImage.data[idx]) | ||
} | ||
break | ||
case IntTypes.Int8: | ||
outputImage.data = new Int8Array(inputImage.data.length) | ||
for (let idx = 0; idx < outputImage.data.length; idx++) { | ||
outputImage.data[idx] = Number(inputImage.data[idx]) | ||
} | ||
break | ||
case IntTypes.UInt16: | ||
outputImage.data = new Uint16Array(inputImage.data.length) | ||
for (let idx = 0; idx < outputImage.data.length; idx++) { | ||
outputImage.data[idx] = Number(inputImage.data[idx]) | ||
} | ||
break | ||
case IntTypes.Int16: | ||
outputImage.data = new Int16Array(inputImage.data.length) | ||
for (let idx = 0; idx < outputImage.data.length; idx++) { | ||
outputImage.data[idx] = Number(inputImage.data[idx]) | ||
} | ||
break | ||
case IntTypes.UInt32: | ||
outputImage.data = new Uint32Array(inputImage.data.length) | ||
for (let idx = 0; idx < outputImage.data.length; idx++) { | ||
outputImage.data[idx] = Number(inputImage.data[idx]) | ||
} | ||
break | ||
case IntTypes.Int32: | ||
outputImage.data = new Int32Array(inputImage.data.length) | ||
for (let idx = 0; idx < outputImage.data.length; idx++) { | ||
outputImage.data[idx] = Number(inputImage.data[idx]) | ||
} | ||
break | ||
case FloatTypes.Float32: | ||
outputImage.data = new Float32Array(inputImage.data.length) | ||
for (let idx = 0; idx < outputImage.data.length; idx++) { | ||
outputImage.data[idx] = Number(inputImage.data[idx]) | ||
} | ||
break | ||
case FloatTypes.Float64: | ||
outputImage.data = new Float64Array(inputImage.data.length) | ||
for (let idx = 0; idx < outputImage.data.length; idx++) { | ||
outputImage.data[idx] = Number(inputImage.data[idx]) | ||
} | ||
break | ||
case IntTypes.UInt64: | ||
outputImage.data = new BigUint64Array(inputImage.data) | ||
break | ||
case IntTypes.Int64: | ||
outputImage.data = new BigInt64Array(inputImage.data) | ||
break | ||
} | ||
break | ||
} | ||
} else { | ||
// copy | ||
const CTor = inputImage.data.constructor as new(length: number) => typeof inputImage.data | ||
outputImage.data = new CTor(inputImage.data.length) | ||
if (outputImage.data != null) { | ||
// @ts-expect-error: error TS2345: Argument of type 'TypedArray' is not assignable to parameter of type 'ArrayLike<number> & ArrayLike<bigint>' | ||
outputImage.data.set(inputImage.data, 0) | ||
} | ||
} | ||
} | ||
|
||
return outputImage | ||
} | ||
|
||
export default castImage |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters