Drawing Polygons on Labelmap Masks

segmentation
labelmap
segment-editor

(G Leman) #1

I’ve got a function that produces a list of vtkPolygons (that I put together into a vtkPolyData) that I’d like to “draw” on a labelmap mask. It looks like

EditorLib.LabelEffect.slicer.SegmentEditorDrawEffect.scriptedEffect.appendPolyMask(label_map, polyData, sliceWidget )

will do the trick. The problem is that when I call that I get:

MemoryError: std::bad_alloc: bad allocation

It looks like the label map I get inside my effect on an empty segment has zero dimensions:

label_map = self.scriptedEffect.maskLabelmap()

I assume that would be the case even if there were something in the segment already and I was drawing outside of the bounds of that mask?

Is there a way to create a mask that isn’t zero length from an empty segment? Or how should I be going about the task of drawing these vtkPolygons into a segment? I’d like to be able to have the system draw these in and then let the user clean them up a bit in one workflow.


(G Leman) #2

I wasn’t able to make this work but came up with a different approach. I figured I’d post this for the next person that is tearing their hair out over this.

First, get the points out of the vtkPolygons:

def get_points_from_vtk_polygon(vtk_polygon):
        return [list(vtk_polygon.GetPoints().GetPoint(i)) for i in  
               xrange(vtk_polygon.GetPoints().GetNumberOfPoints())]

Then save those points as Markups:

def save_markup_points(markup_name, points):
     markupsNode = slicer.mrmlScene.GetFirstNodeByName(markup_name)
     if markupsNode is None:
         markupsNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsFiducialNode")
         markupsNode.SetName(markup_name)
     for pt in points:
         markupsNode.AddFiducial(*pt)

Then just convert the markups to a segment:

markupsToModelNode = slicer.vtkMRMLMarkupsToModelNode()
slicer.mrmlScene.AddNode(markupsToModelNode)
fiducial_node = slicer.util.getNode(fiducial_name)
slicer.modules.markupstomodel.logic().SetMarkupsNode(fiducial_node, markupsToModelNode)
outputModelNode = slicer.vtkMRMLModelNode()
slicer.mrmlScene.AddNode(outputModelNode)
outputModelNode.SetName(model_name)
markupsToModelNode.SetAndObserveModelNodeID(outputModelNode.GetID())
markupsToModelNode.SetModelType(0)
mesh = outputModelNode.GetMesh()
color_list = [51.0, 221.0, 255.0]
segment_id = segmentation.GetSegmentIdBySegmentName(segment_name)
segmentation_node.AddSegmentFromClosedSurfaceRepresentation(mesh, segment_name, color_list, segment_id)
slicer.mrmlScene.RemoveNode(markupsToModelNode)
slicer.mrmlScene.RemoveNode(outputModelNode)

It takes a bit of time to run with large polygons, but can be sped up by just skipping some of the markup points:

save_markup_points('test', pts[0::3])

(Andras Lasso) #3

This indicates that you might have tried to use the legacy Editor module. It will be probably removed from Slicer5, so I would recommend not to rely on it anymore.

The approach that you described should work nicely for convex (or slightly concave) shapes. You don’t need to create a temporary markups module, you can use a lower level API - vtkSlicerMarkupsToModelClosedSurfaceGeneration - to generate vtkPolyData from vtkPoints.

If you need to work with concave shapes then you can save your planar contours in a polydata and set it in a segmentation node as “planar contour” representation. Segmentation infrastructure automatically converts it to all other representations (binary labelmap, closed surface, ribbon, etc.) as needed. The converters are provided by SlicerRT extension (since this planar contour representation is still quite commonly used for radiotherapy and not used much elsewhere), so you will need to install this extension.