How to build ImageRegistration8 example with ITK-WASM?

This is what I get in the docker logs:

If your ITK build is a trimmed-down version, does it still work? That was my original question.

WIth ITKGroup_Core disabled ?

Yes, with ITK_BUILD_DEFAULT_MODULES and ITKGroup_Core turned off. Group options show up after you disable default modules.

Hi, here is the result:
By disabling ITK_BUILD_DEFAULT_MODULE and ITKGroup_Core, the imageRegistration8 sample does not work.
To make it work, it was necessary to activate the following modules:
-ITKGroup_IO
-ITKGroup_Registration

Build OK:

On the other hand, I modified the CMakeLists.txt to remove all the dependent modules and add the path of ITK-build so that it works.

image

1/ Cool, everything works with cmake locally, but now what should be done to make it work with ITK-WASM?
2/ Is it possible to modify the optional modules in itkwasm/wasi docker container itk-build?
3/ Are the examples provided in the kit all supposed to work?

Thx in advance

The proper solution is to list ALL the dependent modules in the list. When compiling programs for the web, we should be careful about not including unnecessary libraries.

Enabling entire groups in your ITK build is not overly helpful in identifying the exact dependent module. WhatModulesITK.py script should be helpful with that. Also take a look at this thread.

Hi dzenanz,

Here is the result of the python script:

I copied these modules into my CMakeLists.txt and still got the same errors. I do not know what to think :frowning:

If you build ITK with only these modules turned on, does the example with against it? I would like to eliminate this variable before needing to look into the wasi build process.

Hi @David_SAMSONOFF ,

You are not doing anything wrong – improvements are required to make the Metricsv4 code used in ImageRegistration8.cxx work with the WASI toolchain :slight_smile:

There is a bit of documentation on how to build / test / contribute to the WASI toolchain in the Docs → Development → Hacking itk-wasm section of the itk-wasm documentation.

I created an example from ImageRegistration8, called it mean-squares-versor-registration, addressed the associated build issues, and added it to our CI testing in this PR.

The example will build / run / produce the same output as a native build, although it is currently not the fastest (we will add multi-threading) and there is a backtrace that occurs on exit – we will work on these.

1 Like

Thx Matt for your help :slight_smile: ,

This example works very well, the difference comes from the docker image used?

2 Likes

Yes, the Docker image itkwasm/wasi:20230315-07caf9ca or later is needed.

Hi matt and dzenanz,

Are there good practices that we must respect to make a web assembly dev? For example, I see the mean-squares-versor-registration example has different code than ImageRegistration8.
Can an example that works in server side always work in web assembly?
I am asking because currently if running the wasi build on ImageRegistration8 from the kit then I am getting errors.

Hi @David_SAMSONOFF ,

For WASI builds, nearly all the IO’s are supported but HDF5 ImageIO is currently not supported. I see GDCM related errors, although we do have GDCM WASI ImageIO.

I general, it is best to not build support for all the ImageIO code into wasm executable – it bloats their size. If possible build support for only the IO’s needed. Or, use the dedicated IO modules, built with,

npm run build:wasi

and found in dist/wasi-image-io/. Eventually these will be distributed in a registry (once it is available :slight_smile: ).

Convert the images from their original format to .iwi.cbor, which is supported by all WebAssemblyInterface modules.

1 Like

Hi, thx you for your help :slight_smile:

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