How do I get Slicer to calculate the distance between two segments in 3d space? By fiddling with the ruler endpoints I cannot be sure that I’m acually measuring the minimum distance between the segments, and it is also quite inconvenient. Does Slicer have some way to automatically determining the minimum distance between two segments?
I believe the minimum Hausdorff distance is exactly the distance you’re trying to get. Use Segment Comparison module in the SlicerRT extension to calculate that.
Thanks, but I don’t think that is what I’m after. I just tried it and it returns something called “Maximum” “Average” and “95%” distances. All the values are far larger than the value I expect to get in the case I’m working on right now.
According to Wikipedia, Hausdorff distance is “the greatest of all the distances from a point in one set to the closest point in the other set”, which is not what I’m after.
What I want is the smallest possible distance that can be obtained by choosing one point in each segment. I.e. what I think is the most common definition of the distance between two subsets in a metric space.
We compute statistics for the distances between all points of both surfaces. We typically report mean, 95th percentile, and maximum, because the segments usually overlap and so minimum distance is always 0.
Are your segments intersecting or they are at a distance from each other?
Yes this is why I wrote that you’ll need the minimum Hausdorff, which will be the distance between the two closest points. As @lassoan says it’s usually 0 because usually we compare two segments representing the same objects (so they overlap). So this is why it’s not shown in Segment Statistics UI (I thought for some reason that it was). I’m not aware of any method for getting this number on the UI, but this is some python code that will get it for you:
s=getNode('vtkMRMLSegmentationNode1') # Whatever your input is
p1=s.GetClosedSurfaceRepresentation('Segment_1') # Again, depends on your input. If it's not a segmentation then you'll need to access the model nodes
@lassoan My segments are nonintersecting, and I think that will be the case every time I need to do distance measurements in Slicer.
@cpinter Thanks! At first I didn’t catch your point about the minimum distance since it wasn’t in the graphical interface. Your code works perfectly, so I can use that.
It would be very nice to get this distance measure into the Segment Comparison graphical interface.
I’m glad you managed to make use of the code! I know it’s not the most convenient way, but if you don’t need it in a workflow that you repeat many times, then it should do the trick for you. Let us know otherwise.
Yes, thanks. I will be measuring quite a lot of such distances. I’m working on a study where we are measuring the minimal distance between a drilled volume in bone and the surrounding anatomical structures. Would it be a lot of work for you to include this distance among the other ones in the Segment Comparison module? It would be very convenient to be able to just select the segment name in the GUI and have it do the calculation.
I would love to propose a patch for this myself, but the only part of Slicer I have tried to work on is the Screen Capture module which seems easier because everything seems to be written in Python there, and this doesn’t seem to be the case with this module. I guess it is in the source for the libvtkSlicerSegmentComparisonModule*.so-files in this case?
Yes it’s that module, see source here. I’m wondering if we should include it there or not. Currently we use Plastimatch’ Hausdorff implementation and not the filter that I used in the python snippet above. If we just add a new option to specify percentile for Hausdorff (that’s what I’d do), then we need to calculate it twice, once in Plastimatch and once in the VTK filter. If this overhead is fine then the change will be quite easy to make. We could also replace the Plastimatch one with the VTK one completely, but then it has to be validated again.
I never considered this before, but it seems useful. It would be easy to modify to compute this without running the filter twice.
What would be the preferred implementation? Min distance from boundary to boundary or set to set? (Or both?)
Can you see a scenario where the min distance between set to set won’t be the same as the boundary to boundary? The boundary is always the outside shell of the set right?
Actually I found a ticket about adding surface-based Hausdorff comparison: https://github.com/SlicerRt/SlicerRT/issues/67
Since the two Hausdorff algorithms are quite different in what data type they work on (Plastimatch: labelmap, custom VTK filter: poly data), it could make sense to add it as a third option somehow in the module. It would be then very easy to add a custom percentile option.
Yes, vertex-based HD would be a nice addition.
Custom percent could be added to labelmap too. There is already a function for this:
/*! \brief Set the fraction of voxels to include when computing
the percent hausdorff distance. The input value should be
a number between 0 and 1. The default value is 0.95. */
void set_hausdorff_distance_fraction (
I did add some code for minimum as well. (But not yet tested.)
/*! \brief Return the minimum Hausdorff distance */
float get_min_min_hausdorff ();
/*! \brief Return the minimum boundary Hausdorff distance */
float get_min_min_boundary_hausdorff ();
The boundary value differs from the set value when one segment is completely contained within the other, where the set distance is zero but the boundary distance is non-zero.
In this case the best would probably be to add the custom percentage option, and decide to use between the two logic classes run-time based on the master representation.
Hi, I’m new to coding and wondering if someone can help me with the above-mentioned Python code to calculate minimum Hausdorff distance between two segmentations. I have installed the SlicerRT extension and have access to the “Segment Comparison” module.
If I am working with the above pictured scene, should the code be input as:
s=getNode('Left Excised Volume')
p1=s.GetClosedSurfaceRepresentation('Left Excised Volume')
Using this, Slicer crashes after “pdf.SetInputReferencePolyData(p1).”