Split Volume by Label values

In vtk.js, I have VTI files that I’m reading in using the vtkXMLImageDataReader. The image data has a known, discrete set of label values corresponding to regions. I’d like to separate this volume into separate volumes (ultimately into separate ISO surfaces via MarchingCubes).

How could I go about separating (thresholding? filtering?) my volume data according to the labels on the voxels so I could create one marching-cube actor per label value?

I managed to come up with this based on the VolumeOutline Example. Seems to work. Have I reinvented a wheel here? Anyone see any problems with doing it like this?

getVolumeFilteredByThreshold(sourceData, thresholdMin, thresholdMax) {
  const imageData = vtkImageData.newInstance(sourceData.get("spacing", "origin", "direction"));
  imageData.setExtent(sourceData.getExtent());
  const values = sourceData
    .getPointData()
    .getScalars()
    .getData()
    .map((x) => {
      return x >= thresholdMin && x < thresholdMax ? x : 0;
    });
  const dataArray = vtkDataArray.newInstance({
    numberOfComponents: 1,
    values,
  });
  imageData.getPointData().setScalars(dataArray);

  return imageData;
}

Not surprisingly, this is pretty slow

There should be no need for thresholding at all. You can specify multiple iso-values to MarchingCubes/ContourFilter (at least in VTK proper). You need to apply smoothing to the resulting isosurfaces to remove staircase artifacts.

There are several other possible pipelines for visualizing segmentation results. For example, you can use RGBA volume rendering or multi-volume rendering instead of creating surfaces at all. It all depends on the underlying volume (imaging modality, size, kind of structures you want to visualize), whether you want to allow quick editing, etc.

1 Like

Thanks @lassoan for these suggestions. I am working in VTK.js, so I’m restricted to what’s available there. One VTK.js limitation I’ve run up against is the lack of picking for Volumes - which is why I need to convert the volumes to surfaces.

I have tried setting to the contourValue parameter for the MarchingCubes to the value of the respective labels, but it seems to have no effect - the whole volume is rendered instead of just the parts of it with the correct label values.

    let marchingCube = vtkImageMarchingCubes.newInstance({
      contourValue: myLabelValue,
      computeNormals: true,
      mergePoints: true,
    });

I may not be grasping the differences between the ISO values and the label values and how they relate to each other - I don’t have much of a background w/ medical imaging data.