Calculating distance using Maurer distance map

Hi everyone,

I’m trying to use Maurer 3D distance map to calculate the difference in size of a tumor before and after procedure (to estimate margin). I applied the signedmaurerdistancemap filter to the pre-procedure tumor, but how do I superimpose the post-procedure tumor onto this map and pull out the difference in distance of the tumor before and after procedure? Thank you

You can use Segment Comparison module and I think ChangeTracker can do some quantifications like this, too.

Of course you can compute the distance map and do your custom visualization, too. Just choose the overlay as foreground volume and go to Volumes module to threshold the distance map and customize colormap and window width/level.

1 Like

Thank you for replying!

I can’t seem to figure out how to use the Volume module to calculate the distance. I set the post-procedure tumor volume as the back ground, the pre-procedure tumor with 3D map as the foreground. The active volume is also set as the pre-procedure tumor volume with 3D map. However, the Histogram section of the volume module doesn’t show any numbers (I presumed that this is where the histogram of distance data would show). Did I get anything wrong? (I also tried to switch the background and foreground but still no results in histogram section…)

What exact would you like to compute? If you only need tumor volumes then you can get it from Segment Statistics module (after you segmented the tumor using Segment Editor).

I would like to compute the difference in distance between the pre procedure volume and the post procedure volume (to see if the procedure achieved adequate margin). I had some results using the Segment Comparison as you suggested (thank you!). I was just trying to learn how to compute the margin using the Maurer distance map.

Distance is computed by Segment Comparison module. It computes metrics like maximum, 95th percentile, and median of the distance distribution.

1 Like

Thank you for your suggestion, I will learn more about the Segment Comparison module!

2 Likes

I have been able to use Segment Comparison and got the maximum, 95th, and median distance just like you described. However, is there a way to extract all the distances between the two segments instead of just the three metrics above? I want to assess if the treatment zone has achieved enough margin around the pre-treatment tumor, so the minimum distance between these two segments is more important for this assessment.

I’ve been searching for awhile, and I found a link on github
[https://github.com/SlicerRt/SlicerRT/blob/master/SegmentComparison/Logic/vtkPolyDataDistanceHistogramFilter.cxx]
It seems like Segment Comparison module does calculate all the distances but only the max, 95th, and median are shown in Slicer. I have only been using Slicer for a couple weeks but I’m very much interested to learn more. Would you point me in the direction of extracting the distance histogram or just the minimum distance value?

@cpinter Could you give advice on how to get the complete histogram?

1 Like

Note that you can also export segments to model nodes and use Model to Model Distance extension to get a model that has the computed distances for each point. You can display this model as a colored surface, you can export distances to numpy and compute basic stats, histogram, etc. and you can also save results into a table (.csv file) and plotting.

For example, you can get this:

By performing the steps described above and copy-pasting this script into the Python console:

modelNode = getNode('VTK Output File')
distanceArrayName = "Signed"

# Get distances from point data
import numpy as np
distances = vtk.util.numpy_support.vtk_to_numpy(modelNode.GetPolyData().GetPointData().GetArray(distanceArrayName))

# Print basic stats
print("Minimum distance: %f" % min(distances))
print("Maximum distance: %f" % max(distances))
print("Mean distance: %f" % np.mean(distances))

# Compute histogram
histogram = np.histogram(distances, bins=100)

# Save results to a new table node
tableNode=slicer.mrmlScene.AddNewNodeByClass("vtkMRMLTableNode", modelNode.GetName() + " histogram")
updateTableFromArray(tableNode, histogram)
tableNode.GetTable().GetColumn(0).SetName("Count")
tableNode.GetTable().GetColumn(1).SetName("Intensity")

# Create plot

plotDataNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLPlotDataNode")
plotDataNode.SetAndObserveTableNodeID(tableNode.GetID())
plotDataNode.SetXColumnName("Intensity")
plotDataNode.SetYColumnName("Count")

plotChartNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLPlotChartNode")
plotChartNode.AddAndObservePlotDataNodeID(plotDataNode.GetID())
plotChartNode.SetAttribute("Type", "Bar") # delete this line for line plot

# Show plot in layout

layoutManager = slicer.app.layoutManager()
layoutManager.setLayout(slicer.vtkMRMLLayoutNode.SlicerLayoutFourUpPlotView)
plotWidget = layoutManager.plotWidget(0)

plotViewNode = plotWidget.mrmlPlotViewNode()
plotViewNode.SetPlotChartNodeID(plotChartNode.GetID())
1 Like

There’s a class that can get the histogram of the model distances called vtkPolyDataDistanceHistogramFilter. There is no user interface for that so python scripting is necessary. If you use Segment Editor then you can get the poly data from the segments, feed them to this class, and get the output as vtkTable, so tables and plots can be shown in Slicer. Let me know if you’d like me to provide actual code.

1 Like

Yay! Thank you so much! I will try this and will update to let you know!

Hi Csaba,
Yes please I would like the code if it’s not too much trouble, thanks so much for reply!

Here you go:

import vtkSlicerSegmentComparisonModuleLogicPython
polHist = vtkSlicerSegmentComparisonModuleLogicPython.vtkPolyDataDistanceHistogramFilter()
segNode = slicer.util.getNode('vtkMRMLSegmentationNode1')
poly1 = segNode.GetSegmentation().GetSegment('Segment_1').GetRepresentation(slicer.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName())
poly2 = segNode.GetSegmentation().GetSegment('Segment_2').GetRepresentation(slicer.vtkSegmentationConverter.GetSegmentationClosedSurfaceRepresentationName())
polHist.SetInputReferencePolyData(poly1)
polHist.SetInputComparePolyData(poly2)
polHist.Update()
histTable = polHist.GetOutputHistogram()
tableNode = slicer.vtkMRMLTableNode()
tableNode.SetAndObserveTable(histTable)
slicer.mrmlScene.AddNode(tableNode)

Then you can save the table to csv with Save data dialog, or oyu can make a plot with it from Tables module.

Oh, and you need to install the SlicerRT extension first to have the Segment Comparison module if you haven’t.

Thank you so much for this, it works like magic!!! Now I will try to learn more about the method from Csaba

Hi Csaba,
I calculated the Hausdorff distance and I put the code in the python console. But when I get to the fourth line, I get the below message (and when I paste the whole script in, slicer would crash).

The problem is that incorrect segmentation node name is specified for slicer.util.getNode.

I think the issue is not the segmentation node but the segment, because otherwise the error message would be “AttributeError: ‘NoneType’ object has no attribute ‘GetSegmentation’”. But in any case, any string literals in sample code should be double checked for your use case, because every Slicer scene is different. You can get the segment IDs like this:

segmentIds = vtk.vtkStringArray()
segNode.GetSegmentation().GetSegmentIDs(segmentIds)
for i in xrange(segmentIds.GetNumberOfValues()):
  print segmentIds.GetValue(i)
1 Like

ah I see, thanks so much Csaba!

What are the units that you have in the histogram? 1100 (pixels, mm, microns?) difference in the models

Thank you!