vtk.js - How to serialize and deserialize vtkDataSet for Rest APIs

Hi guys,

I’m playing with vtk.js in order to better understand it, however I’m currently facing some issues and I certainly can benefit from your help. I would like to do something along the file of:

  • A vtkDataset is loaded in A. The user wants to apply a certain operation on it
  • A sends a request to a given endpoint in backend B via HTTP, along with the vtkDataset that needs to be manipulated
  • Backend B applies the transformation of interest to the dataset
  • Final vtkDataset is sent back to A, so that it can be shown to the user

In order to do that easily I created a small backend in node.js and I’m using as frontend A paraview-glance just to avoid reimplementing everything from scratch.

In particular I tried to make an HTTP request once the user click on the “Blur image” button, that can be seen in Tools > Median filter after loading an image (I’m currently using the Covid-19 demo data for this test).
Once the button is clicked, the function runBlur()(from line 146) is called and ideally I would like to move most of its logic in a backend.
However I’m facing problems with the serialization of the vtkDataset, as it returns a nearly empty object, as PointData, CellData and FieldData all have an empty array.

This is how I am serializing the dataset, before sending it to the backend:

// Get the vtkDataset
const ds = this.targetImage.getDataset();
// Serialize data
const serializer = vtkSerializer.getSerializer(ds);
const arrayHandler = vtkSerializer.vtkArraySerializer.newInstance();
const serializedImg = serializer.serialize(ds, arrayHandler);
//just for debugging
console.log(serializedImg);

I also tried to deserialize the serializedImg and logging it fter serializing it, just to exclude issues in the communication between frontend and backend, using the following code:

const deserializer = vtkSerializer.getDeserializer(serializedImg);
const deserializedImg = deserializer.deserialize(serializedImg, arrayHandler);

This leads to an error as I get that deserializer is undefined. If I understood correctly this is due to the fact that vtk.js is unable to infer the actual deserializer that is needed based on serializedImg value.

If I try to circumvent this error by using the following code:

const deserializedImg = serializer.deserialize(serializedImg, arrayHandler);

I get as error:

Cannot create vtkDataArray object without: size > 0, values

In case you were wondering I tried to actually see the pointData array, using the following instruction:

const pointData = ds.getPointData().getScalars().getData();

and in the console I can see the actual data, so that the problem seems to be in how data is converted from vtkDataset to JSON.

I have developed in the past some Rest APIs using Python and Java, however this is the first time I’m doing it in Javascript, using vtk.js for manipulating data, so I do not know how to move forward.
Do you have any how to accomplish my initial goal of passing vtkDataset from A to B (and viceversa) using Rest APIs? Is the use of serialize and deserialize correct or is there a better way to move data using classing HTTP requests?

Thanks in advance, I wish you all a nice day!

An alternative is to just call dataset.getState(). That will return a JSON-serialized version of your dataset.

1 Like

Thanks a lot Forrest, you saved my day and week! Using getState() was helpful in moving data from paraview-glance to node.js backend. In case someone was wondering, the complete code for serializing an image (VTKImageData) is the following:

const serImg = JSON.stringify(img.getState());

while the following code is used for deserializing the json image into VTK format:

// var serializedImg = req.body.img; //In case this is done on a backend created with express()
import vtk from 'vtk.js/Sources/vtk';
const deserializedImg = vtk(JSON.parse(serializedImg));

As a note I would say that using JSON.parse and JSON.stringify on huge images may lead to issues: JSONStream, based on what I read in this StackOverflow page, seems a better alternative even though I didn’t try it at the moment of writing this post.

For vtkImageData getting only the data that you need should be straight forward has very little info is actually needed.

My guess would be:

  • imageData.get(‘dimensions’, ‘origin’, ‘spacing’, ‘orientation’) => JSON
  • imageData.getPointData().getScalars().getData() => TypedArray(binary buffer)

Then on the way back

const receivedImageData = vtkImageData.newInstance();
receivedImageData.set(JSON.parse(...));
receivedImageData.getPointData().setScalars(vtkDataArray.newInstance({
   values: yourTypedArrayFromBinary,
}));
1 Like

Ideally to be more inlined with the real data stored, use extent instead of dimensions.

1 Like

Thanks for the tip Sebastien, I will also try your approach.

Considering the expected image size in my use case, reducing the actual payload that is moved between the various software stacks will be super useful for improving the overall performances.

dimensions = 3 x int 
extents = 6 x int

So not much difference. But if your extent start with 0, then dimensions is all you need.