How to build ImageRegistration8 example with ITK-WASM?

Hi @matt.mccormick ,
Could you give me some advice, I’m trying to make a registration between 2 complete series of Dicom images. The goal is to make a synchronization on the Z axis of the slices between 2 series displayed on 2 viewports. How can I run a process with 2 folders containing images in Web assembly? I know how to do it in C++ on the server side but in web assembly, I don’t see how to make an itk::wasm::Pipeline() with folders. If you have examples, I’m all ears.
I wonder if such processing can be done on the browser side and with the web assembly?

Browsers don’t want to expose user’s filesystem to the web applications. See this StackOverflow discussion. @matt.mccormick any further comments?

Hi @matt.mccormick, what do you think ?

For reading DICOM file series in the browser, we have the function readImageDICOMFileSeries that itk-wasm provides. This can take a JavaScript Array of File’s, which can retrieved from the local filesystem with an HTML <input> element.

For running server side, there is the equivalent read-image-dicom-file-series.wasi.wasm built as part of the itk-wasm image IO.

Either way, if the volumes have the same dimensions and modality, then finding corresponding slices could be achieved with normalized cross correlation. The ITKMontage module may be helpful. If they have different dimensions or of a different modality, then a slice-by-slice approach with a different similarity metric may be required.

1 Like

Hi @dzenanz / @matt.mccormick ,

Now I’m testing a browser version of the mean-squares-versor-registration example and I don’t know what I should put in the parameters of the itk.runPipelineBrowser() function
I tried this:

          const args = ["--memory-io", "0", "0"];
          const inputs = [{ type: itk.InterfaceTypes.Image, data: fixedImage }, { type: itk.InterfaceTypes.Image, data: movingImage }];
          const desiredOutputs = [{ type: itk.InterfaceTypes.Image}];

          itk
            .runPipelineBrowser(null, wasmURL, args, desiredOutputs, inputs)

It works very well with the input-output example available in itk-wasm but when I apply the same thing there, it doesn’t work.
I activated the debug mode, in the browser to see what is in the Pipeline parameters in the C++ code, and there I see this :slight_smile:

We see that there are 4 expected arguments (argc: 4), but (argv: “./this.program”), the Pipeline object is empty.

Maybe it’s because I’m trying to pass MHA type files directly?
Do you have any idea what’s wrong?

thx in advance

I attached the index.html file.
index.html (3.2 KB)

Hi @David_SAMSONOFF ,

Great work debugging the pipeline! :beetle: :eye:

It looks like args needs to be updated for the arguments for your pipeline:

const args = [“–memory-io”, “0”, “0”];

should be:

const args = ["0", "1", "0", "--memory-io"]

For the first and second input and the output.


We do have beta support for generating TypeScript/JavaScript bindings and a package for your pipeline.

In this case, run

npx itk-wasm bindgen --package-name @itk-wasm/mean-squares-versor-registration --package-description “Example 3D versor transform registration with a mean-squares similarity metric”

Full example addition / test:

I am not sure if the debugger is correctly identifying all arguments in argv.

In typescript/src/mean-squares-versor-registration.ts,

 32   const desiredOutputs: Array<PipelineOutput> = [                                                                                                                                                                              
 33     { type: InterfaceTypes.Image },                                                                                                                                                                                            
 34   ]                                                                                                                                                                                                                            
 35   const inputs: Array<PipelineInput> = [                                                                                                                                                                                       
 36     { type: InterfaceTypes.Image, data: fixedImage },                                                                                                                                                                          
 37     { type: InterfaceTypes.Image, data: movingImage },                                                                                                                                                                         
 38   ]                                                                                                                                                                                                                            
 39                                                                                                                                                                                                                                
 40   const args = []                                                                                                                                                                                                              
 41   // Inputs                                                                                                                                                                                                                    
 42   args.push('0')                                                                                                                                                                                                               
 43   args.push('1')                                                                                                                                                                                                               
 44   // Outputs                                                                                                                                                                                                                   
 45   args.push('0')                                                                                                                                                                                                               
 46   // Options                                                                                                                                                                                                                   
 47   args.push('--memory-io')  

I forgot to also mention that another option for server-side execution is Node.js bindings. You can access and read DICOM series from the local filesystem with the readImageLocalDICOMFileSeries function and the bindgen bindings also include Node.js bindings for your pipeline.

1 Like

Hi,
Can you help me, because I can’t use this module on the browser side ?
Thanks in advance.

Here is my index.html file
index.html (3.2 KB)

Hi,

Same issue with node pipeline:

import path from 'path'
import { runPipelineNode, readImageLocalFile, writeImageLocalFile, InterfaceTypes } from 'itk-wasm'

// Assume we have input and output images as the last arguments
const fixedImageFile = 'brainweb1e1a10f20.mha'
const fixedImage = await readImageLocalFile(fixedImageFile)
const movingImageFile = 'brainweb1e1a10f20Rot10Tx13.mha'
const movingImage = await readImageLocalFile(movingImageFile)
const outputFile = 'output_result.mha'

const args = [];
// Inputs
args.push('0');
args.push('1');
// Output
args.push('0');
// To switch from filesystem to WebAssembly memory IO, pass the `--memory-io` flag.
// This is supported by all itk::wasm::Pipeline's.
args.push('--memory-io');

const inputs = [
  { type: InterfaceTypes.Image, data: fixedImage }, { type: InterfaceTypes.Image, data: movingImage }
]
const desiredOutputs = [
  { type: InterfaceTypes.Image }
]

// Path to the Emscripten WebAssembly module without extensions
const pipelinePath = path.resolve('emscripten-build-debug', 'mean-squares-versor-registration')
const { stdout, stderr, outputs } = await runPipelineNode(pipelinePath, args, desiredOutputs, inputs)

await writeImageLocalFile(outputs[0].data, outputFile)
149776
Thrown at:
    at file:///home/david/src/OA-WASM/oa-mean-squares-versor-registration/node_modules/itk-image-io/MetaImageIO-read-image.js:9:2679
    at emit (node:events:524:35)
    at node:internal/process/execution:159:25
    at loadESM (node:internal/process/esm_loader:100:31)

Node.js v19.7.0
david@EQD-DAS2:~/src/OA-WASM/oa-mean-squares-versor-registration$ npx node --trace-uncaught ./index.mjs
Exception while running pipeline:
stdout: 
stderr: 
Build module in Debug mode for exception message information.

file:///home/david/src/OA-WASM/oa-mean-squares-versor-registration/node_modules/itk-image-io/MetaImageIO-read-image.js:9

Hi,

Someone would have any idea ? Is it the fact that I have MHA files as inputs?

@matt.mccormick @dzenanz

@David_SAMSONOFF nothing jumps out from inspection of your code. Could you share the complete, minimal, reproducible example?

Hi @matt.mccormick

attached, all the project files:

CMakeLists.txt (2.1 KB)
index.html (3.2 KB)
index.mjs (1.2 KB)
mean-squares-versor-registration.cxx (21.8 KB)
package.json (1.7 KB)

Thank you @David_SAMSONOFF !

I was able to reproduce locally. With the Debug build (note: I also added -i itkwasm/emscripten:latest-debug to the debug build command – that provides debug symbols not only for the pipeline itself, but also ITK), I get the error:

image

which is likely because the input images have a uint8 component type:

image

But the pipeline is built for float.

This can be solved by using the itk::wasm::SupportInputImageTypes class.

Here is an example of usage:

1 Like

There is also a WIP tutorial section on this topic:

Alternatively, there is also a castImage function that can cast the input to float: