Load segmentation and export surface mesh as model .ply

Hello,
I’m new to creating modules and my programming skills are rather basic, so I encountered problems in loading segmentation from subdirectories, and in exporting and saving the mesh models.
The first issue looks like following: I want to load segmentations named ‘_repair.seg.nrrd’ from multiple subdirectories. What I got so far is:

  def onExportButtonClicked(self):
    dir_path = qt.QFileDialog.getExistingDirectory(None, 'Open folder', '/home/', qt.QFileDialog.ShowDirsOnly)
    dir_path = dir_path.replace("\\", "/")
    for filename in os.listdir(dir_path):
      self.exportMesh(dir_path, filename)
    print("Finished.")
    
  def exportMesh(self, dir_path, filename):
    whichOP= "preop"
	# Load segmentation (repair .seg.nrrd)
    file_complete = dir_path + "/" + filename + "/" + whichOP + "/CT/" + filename + "_" + whichOP + "_repair.seg.nrrd"
    print("Loading {}".format(file_complete))
    slicer.app.processEvents()
    MasterModelNode = slicer.util.loadNodeFromFile(file_complete, "_repair.seg.nrrd", {}, returnNode=True)
    modelNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLModelHierarchyNode')
    slicer.modules.segmentations.logic().ExportAllSegmentsToModelHierarchy(MasterModelNode, modelNode) 

I can’t get further, because I get an error:

TypeError: ExportAllSegmentsToModelHierarchy argument 1: method requires a VTK object. 

I would be really grateful for your help, as I lack knowledge to fix this (probably really trivial) problem. I have a next piece of code that looks as below. However, I don’t even know if it works, because of the previous error I mentioned.

    # Make sure surface mesh cells are consistently oriented
    surfaceMesh = MasterModelNode.GetClosedSurfaceRepresentation(segmentID)
    normals = vtk.vtkPolyDataNormals()
    normals.AutoOrientNormalsOn()
    normals.ConsistencyOn()
    normals.SetInputData(surfaceMesh)
    normals.Update()
    surfaceMesh = normals.GetOutput()
    # Save as PLY file
    writer = vtk.vtkSTLWriter()
    writer.SetInputData(surfaceMesh)
    #### name should be: name of segmentation .ply
    file_new = dir_path + "/" + filename + "/" + whichOP + "/CT/" + filename + segmentName + ".ply"
    writer.SetFileName(file_new) # set file name
    writer.Update()
    # Clean up
    segmentEditorWidget = None
    slicer.mrmlScene.RemoveNode(file_complete)
    slicer.mrmlScene.RemoveNode(segmentEditorNode)

Best regards!

Probably this line is not working as you expect leading to the error message about needing a vtk object. Try printing out the result to debug.

Yes, that line is incorrect. If returnNode=True is specified then slicer.util.loadNodeFromFile returns (success, MasterModelNode) pair and not just MasterModelNode.

Hello again,
Thank you so much for your reply. So after debug the code seems to work until it reaches:

slicer.modules.segmentations.logic().ExportAllSegmentsToModelHierarchy(MasterModelNode, modelNode)

Can there be a problem with my file type, namely what I wrote as: “_repair.seg.nrrd” in

MasterModelNode = slicer.util.loadNodeFromFile(file_complete, “_repair.seg.nrrd”, {}, returnNode=True) ?

I tried also “.seg.nrrd” and separately “.seg” or “.nrrd” but it makes no difference at all. It still shows the same error.

Best

You can use slicer.util.loadSegmentation for loading a segmentation from file.

Note that in recent nightly versions of Slicer, you can export segmentation directly to stl or obj files. See Save segmentation directly to STL or OBJ files post for details and API documentation for description how it can be used from script.

So I used slicer.util.loadSegmentation(filename, returnNode=False) as you suggested but the error remains - ‘method requires a VTK object’.
Also I need to export the mesh surface as .ply file.
Is it possible that I miss a line about a node, like getNode(‘Segmentation’)?
Best!

What error, where? What command do you type exactly?

If you need .ply export you cannot use the direct export feature but you need to use VTK writers. You can add a feature request to the Slicer issue tracker to implement .ply format export.

This is my piece of code until it works:

  def onExportButtonClicked(self):
    qt.QFileDialog.ShowDirsOnly)
    filename = qt.QFileDialog.getOpenFileName(self.parent, 'Open file', 'D:\\SlicerTest\\THA\\001\\preop\\CT', "All Files (*.nrrd)")
    print filename
    self.exportMesh(filename)
    print("Finished.")
    
  def exportMesh(self, filename):
    # Load segmentation (repair.seg.nrrd)
    slicer.app.processEvents()
    MasterModelNode = slicer.util.loadSegmentation(filename, returnNode=False)
    modelNode = slicer.mrmlScene.AddNewNodeByClass('vtkMRMLModelHierarchyNode')
    slicer.modules.segmentations.logic().ExportAllSegmentsToModelHierarchy(MasterModelNode, modelNode)  

The error I get in Python Interactor in Slicer is as follows:

Best

In cases like this you need to confirm line-by-line that you are getting the data you expect from the API, for example by adding print statements or executing the calls in the python console.

Here, you have the returnNode=False argument to the loadSegmentation call, but then try to use the MasterModelNode as a node, when it’s a boolean.

HTH,
Steve

This code snippet should do what you need:

def onExportButtonClicked(self):
  filename = qt.QFileDialog.getOpenFileName(self.parent, 'Open file', 'D:\\SlicerTest\\THA\\001\\preop\\CT', "All Files (*.nrrd)")
  self.exportMesh(filename)

def exportMesh(self, filename):
  [success, segmentationNode] = slicer.util.loadSegmentation(filename, returnNode=True)
  segmentationNode.CreateClosedSurfaceRepresentation()
  segmentation=segmentationNode.GetSegmentation()
  for segmentIndex in range(segmentation.GetNumberOfSegments()):
    segmentID = segmentation.GetNthSegmentID(segmentIndex)
    polydata = segmentationNode.GetClosedSurfaceRepresentation(segmentID)
    writer = vtk.vtkPLYWriter()
    writer.SetInputData(polydata)
    writer.SetFileName(os.path.split(filename)[0]+"/"+segmentationNode.GetName()+"_"+segmentID)
    writer.Update()
1 Like

Thank you so much for your help @lassoan ! Of course everything works perfectly now.
Best regards

1 Like