Skip to content

Commit

Permalink
perf(readImageDicomFileSeries): Add parallel sorted series parallel p…
Browse files Browse the repository at this point in the history
…rocessing
  • Loading branch information
thewtex committed Aug 5, 2023
1 parent cd29728 commit f6745b8
Show file tree
Hide file tree
Showing 6 changed files with 121 additions and 76 deletions.
4 changes: 2 additions & 2 deletions packages/dicom/typescript/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
"author": "",
"license": "Apache-2.0",
"dependencies": {
"itk-wasm": "^1.0.0-b.118"
"itk-wasm": "^1.0.0-b.119"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^24.0.0",
Expand Down Expand Up @@ -67,4 +67,4 @@
"type": "git",
"url": "https://github.com/InsightSoftwareConsortium/itk-wasm"
}
}
}
5 changes: 3 additions & 2 deletions packages/dicom/typescript/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
// Generated file. To retain edits, remove this comment.

export * from './pipelines-base-url.js'
export * from './pipeline-worker-url.js'

Expand Down Expand Up @@ -62,3 +60,6 @@ export type { ReadImageDicomFileSeriesOptions }

import readImageDicomFileSeries from './read-image-dicom-file-series.js'
export { readImageDicomFileSeries }

import readImageDicomFileSeriesWorkerFunction from './read-image-dicom-file-series-worker-function.js'
export { readImageDicomFileSeriesWorkerFunction }
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
// Generated file. To retain edits, remove this comment.

import { Image } from 'itk-wasm'
import { Image, WorkerPool } from 'itk-wasm'

interface ReadImageDicomFileSeriesResult {
/** WebWorker used for computation */
webWorker: Worker | null
/** WebWorkerPool used for computation */
webWorkerPool: WorkerPool | null

/** Output image volume */
outputImage: Image
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import {
BinaryFile,
runPipeline,
PipelineOutput,
PipelineInput,
InterfaceTypes,
Image,
JsonObject,
} from 'itk-wasm'

import { getPipelinesBaseUrl } from './pipelines-base-url.js'
import { getPipelineWorkerUrl } from './pipeline-worker-url.js'

interface WorkerFunctionResult {
webWorker: Worker
outputImage: Image
sortedFilenames: string[]
}

async function readImageDicomFileSeriesWorkerFunction(
webWorker: Worker | null,
inputImages: BinaryFile[],
singleSortedSeries: boolean = false
): Promise<WorkerFunctionResult> {

const desiredOutputs: Array<PipelineOutput> = [
{ type: InterfaceTypes.Image },
{ type: InterfaceTypes.JsonObject },
]

const inputs: Array<PipelineInput> = [
]

const args = []
// Inputs
// Outputs
const outputImageName = '0'
args.push(outputImageName)

const sortedFilenamesName = '1'
args.push(sortedFilenamesName)

// Options
args.push('--memory-io')
args.push('--input-images')
inputImages.forEach((value) => {
inputs.push({ type: InterfaceTypes.BinaryFile, data: value as BinaryFile })
args.push(value.path)
})
if (typeof singleSortedSeries !== "undefined") {
singleSortedSeries && args.push('--single-sorted-series')
}

const pipelinePath = 'read-image-dicom-file-series'

const {
webWorker: usedWebWorker,
returnValue,
stderr,
outputs
} = await runPipeline(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl(), pipelineWorkerUrl: getPipelineWorkerUrl() })
if (returnValue !== 0) {
throw new Error(stderr)
}

const result = {
webWorker: usedWebWorker as Worker,
outputImage: outputs[0].data as Image,
sortedFilenames: ((outputs[1].data as JsonObject).data as string[]),
}
return result
}

export default readImageDicomFileSeriesWorkerFunction
104 changes: 38 additions & 66 deletions packages/dicom/typescript/src/read-image-dicom-file-series.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
// Generated file. To retain edits, remove this comment.

import {
Image,
JsonObject,
BinaryFile,
InterfaceTypes,
PipelineOutput,
PipelineInput,
runPipeline
stackImages,
WorkerPool,
} from 'itk-wasm'

import ReadImageDicomFileSeriesOptions from './read-image-dicom-file-series-options.js'
import ReadImageDicomFileSeriesResult from './read-image-dicom-file-series-result.js'
import readImageDicomFileSeriesWorkerFunction from './read-image-dicom-file-series-worker-function.js'


import { getPipelinesBaseUrl } from './pipelines-base-url.js'
import { getPipelineWorkerUrl } from './pipeline-worker-url.js'
const numberOfWorkers = typeof globalThis.navigator?.hardwareConcurrency === 'number' ? globalThis.navigator.hardwareConcurrency : 4
const seriesBlockSize = 8

/**
* Read a DICOM image series and return the associated image volume
Expand All @@ -25,69 +19,47 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js'
* @returns {Promise<ReadImageDicomFileSeriesResult>} - result object
*/
async function readImageDicomFileSeries(
webWorker: null | Worker,
webWorkerPool: null | WorkerPool,
options: ReadImageDicomFileSeriesOptions = { inputImages: [] as BinaryFile[] | File[] | string[], }
) : Promise<ReadImageDicomFileSeriesResult> {

const desiredOutputs: Array<PipelineOutput> = [
{ type: InterfaceTypes.Image },
{ type: InterfaceTypes.JsonObject },
]

const inputs: Array<PipelineInput> = [
]

const args = []
// Inputs
// Outputs
const outputImageName = '0'
args.push(outputImageName)

const sortedFilenamesName = '1'
args.push(sortedFilenamesName)

// Options
args.push('--memory-io')
if (typeof options.inputImages !== "undefined") {
if(options.inputImages.length < 1) {
throw new Error('"input-images" option must have a length > 1')
}
args.push('--input-images')

options.inputImages.forEach(async (value) => {
let valueFile = value
if (value instanceof File) {
const valueBuffer = await value.arrayBuffer()
valueFile = { path: value.name, data: new Uint8Array(valueBuffer) }
}
inputs.push({ type: InterfaceTypes.BinaryFile, data: valueFile as BinaryFile })
const name = value instanceof File ? value.name : (valueFile as BinaryFile).path
args.push(name)

})
}
if (typeof options.singleSortedSeries !== "undefined") {
options.singleSortedSeries && args.push('--single-sorted-series')
let workerPool = webWorkerPool
if (workerPool === null) {
workerPool = new WorkerPool(numberOfWorkers, readImageDicomFileSeriesWorkerFunction)
}

const pipelinePath = 'read-image-dicom-file-series'

const {
webWorker: usedWebWorker,
returnValue,
stderr,
outputs
} = await runPipeline(webWorker, pipelinePath, args, desiredOutputs, inputs, { pipelineBaseUrl: getPipelinesBaseUrl(), pipelineWorkerUrl: getPipelineWorkerUrl() })
if (returnValue !== 0) {
throw new Error(stderr)
const inputs: Array<BinaryFile> = [
]
if(options.inputImages.length < 1) {
throw new Error('"input-images" option must have a length > 1')
}

const result = {
webWorker: usedWebWorker as Worker,
outputImage: outputs[0].data as Image,
sortedFilenames: (outputs[1].data as JsonObject).data,
options.inputImages.forEach(async (value) => {
let valueFile = value
if (value instanceof File) {
const valueBuffer = await value.arrayBuffer()
valueFile = { path: value.name, data: new Uint8Array(valueBuffer) }
}
inputs.push(valueFile as BinaryFile)
})

if (options.singleSortedSeries) {
const taskArgsArray = []
for (let index = 0; index < inputs.length; index += seriesBlockSize) {
const block = inputs.slice(index, index + seriesBlockSize)
taskArgsArray.push([block, options.singleSortedSeries])
}
const results = await workerPool.runTasks(taskArgsArray).promise
const images = results.map((result) => result.outputImage)
const sortedFilenames = results.reduce((a, v) => a.concat(v.sortedFilenames), [])
let stacked = stackImages(images)
return { outputImage: stacked, webWorkerPool: workerPool, sortedFilenames }
} else {
const taskArgsArray = [[inputs, options.singleSortedSeries]]
const results = await workerPool.runTasks(taskArgsArray).promise
let image = results[0].outputImage
return { outputImage: image, webWorkerPool: workerPool, sortedFilenames: results[0].sortedFilenames }
}
return result
}

export default readImageDicomFileSeries
2 changes: 1 addition & 1 deletion src/bindgen/typescript/resources/template.package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"author": "",
"license": "Apache-2.0",
"dependencies": {
"itk-wasm": "^1.0.0-b.118"
"itk-wasm": "^1.0.0-b.119"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^24.0.0",
Expand Down

0 comments on commit f6745b8

Please sign in to comment.