diff --git a/packages/dicom/typescript/package.json b/packages/dicom/typescript/package.json index 6de2252bb..e62acf74c 100644 --- a/packages/dicom/typescript/package.json +++ b/packages/dicom/typescript/package.json @@ -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", @@ -67,4 +67,4 @@ "type": "git", "url": "https://github.com/InsightSoftwareConsortium/itk-wasm" } -} \ No newline at end of file +} diff --git a/packages/dicom/typescript/src/index.ts b/packages/dicom/typescript/src/index.ts index 436a4a864..2f7e51a5b 100644 --- a/packages/dicom/typescript/src/index.ts +++ b/packages/dicom/typescript/src/index.ts @@ -1,5 +1,3 @@ -// Generated file. To retain edits, remove this comment. - export * from './pipelines-base-url.js' export * from './pipeline-worker-url.js' @@ -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 } diff --git a/packages/dicom/typescript/src/read-image-dicom-file-series-result.ts b/packages/dicom/typescript/src/read-image-dicom-file-series-result.ts index 8a9fed861..11533953f 100644 --- a/packages/dicom/typescript/src/read-image-dicom-file-series-result.ts +++ b/packages/dicom/typescript/src/read-image-dicom-file-series-result.ts @@ -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 diff --git a/packages/dicom/typescript/src/read-image-dicom-file-series-worker-function.ts b/packages/dicom/typescript/src/read-image-dicom-file-series-worker-function.ts new file mode 100644 index 000000000..7b7ef9708 --- /dev/null +++ b/packages/dicom/typescript/src/read-image-dicom-file-series-worker-function.ts @@ -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 { + + const desiredOutputs: Array = [ + { type: InterfaceTypes.Image }, + { type: InterfaceTypes.JsonObject }, + ] + + const inputs: Array = [ + ] + + 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 diff --git a/packages/dicom/typescript/src/read-image-dicom-file-series.ts b/packages/dicom/typescript/src/read-image-dicom-file-series.ts index 37f0786f3..85452b69a 100644 --- a/packages/dicom/typescript/src/read-image-dicom-file-series.ts +++ b/packages/dicom/typescript/src/read-image-dicom-file-series.ts @@ -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 @@ -25,69 +19,47 @@ import { getPipelineWorkerUrl } from './pipeline-worker-url.js' * @returns {Promise} - result object */ async function readImageDicomFileSeries( - webWorker: null | Worker, + webWorkerPool: null | WorkerPool, options: ReadImageDicomFileSeriesOptions = { inputImages: [] as BinaryFile[] | File[] | string[], } ) : Promise { - const desiredOutputs: Array = [ - { type: InterfaceTypes.Image }, - { type: InterfaceTypes.JsonObject }, - ] - - const inputs: Array = [ - ] - - 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 = [ + ] + 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 diff --git a/src/bindgen/typescript/resources/template.package.json b/src/bindgen/typescript/resources/template.package.json index 87f7fe1f3..c11326c71 100644 --- a/src/bindgen/typescript/resources/template.package.json +++ b/src/bindgen/typescript/resources/template.package.json @@ -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",