# How to Create of Surface Meshes from Parallel Polygons using VTK and Python

**URL:** <https://discourse.slicer.org/t/how-to-create-of-surface-meshes-from-parallel-polygons-using-vtk-and-python/35557>\
**Category:** Support\
**Created:** [April 17, 2024, 10:44am UTC](https://discourse.slicer.org/t/how-to-create-of-surface-meshes-from-parallel-polygons-using-vtk-and-python/35557 "2024-04-17T10:44:17Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![shahrokh](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/shahrokh/32/1499_2.png) [@shahrokh](https://discourse.slicer.org/u/shahrokh)\
**Post date:** [April 17, 2024, 10:44am UTC](https://discourse.slicer.org/t/how-to-create-of-surface-meshes-from-parallel-polygons-using-vtk-and-python/35557/1 "2024-04-17T10:44:17Z")

</div>

Hello  
Dear Developers and Users

I have several polygons that are parallel to each other and spaced at certain intervals. These are of type “ **model** ” and their mesh type is **Surface Mesh (vtkPolyData)**. [This data has been placed along with CT in [Google Drive]](https://drive.google.com/file/d/1NukFEyFwvqIAhYW433xNRLWtbMVAxANK/view?usp=sharing). An image of these models is shown below.

 ![Screenshot from 2024-04-17 14-09-30](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/7/8/782f909192efb2101eb35bbba945106bb9a51850.png)

It is obvious that the Number of Points, Number of Cells, and Volume may vary between them. Now I want to create a new Surface Mesh from these Surface Meshes in a way that its boundaries consist of the initial and final polygons of this set, and its body is composed of these polygons.

Can this be implemented using the available functions in VTK and in Python?

Please guide me,  
Best regards.  
Shahrokh

---

<div class="post-metadata">

**Author:** ![cpinter](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/cpinter/32/7995_2.png) [@cpinter](https://discourse.slicer.org/u/cpinter)\
**Post date:** [April 17, 2024, 11:37am UTC](https://discourse.slicer.org/t/how-to-create-of-surface-meshes-from-parallel-polygons-using-vtk-and-python/35557/2 "2024-04-17T11:37:42Z")

</div>

My first try would be to write a Python script that does the following:

- Copy the contents of the model nodes in one `vtkPolyData` using `vtkAppendPolyDataFilter`
- Create a new segmentation node, and set the source representation to ‘Planar contour’ ([Slicer/Libs/vtkSegmentationCore/vtkSegmentationConverter.h at main · Slicer/Slicer · GitHub](https://github.com/Slicer/Slicer/blob/main/Libs/vtkSegmentationCore/vtkSegmentationConverter.h#L56))
- Set the appended polydata as the `Planar contour` representation of the segmentation node
- Call `GetClosedSurfaceRepresentation` on the segmentation node. Then the underlying conversion rule will do this interpolation for you

Note that you will need the SlicerRT extension to be installed first, because the mentioned conversion rule is provided there.

It is probably useful to check out the third figure in the page [Image Segmentation — 3D Slicer documentation](https://slicer.readthedocs.io/en/latest/user_guide/image_segmentation.html). You will see that this type of representation is often the original input when you work with radiation therapy data. This interpolator has been stable for quite a while now, so you should be able to use it safely.

---

<div class="post-metadata">

**Author:** ![shahrokh](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/shahrokh/32/1499_2.png) [@shahrokh](https://discourse.slicer.org/u/shahrokh)\
**Post date:** [April 17, 2024, 2:33pm UTC](https://discourse.slicer.org/t/how-to-create-of-surface-meshes-from-parallel-polygons-using-vtk-and-python/35557/3 "2024-04-17T14:33:24Z")

</div>

Dear Csaba Pinter

Thanks a lot for your guidance completely…

I’ve completed up to the second step of thinking, and I wasn’t successful in implementing the third step… Hopefully, I’ll be able to continue the work next week…

The following lines are my code at this point.

```auto
import vtk
import slicer
import vtkSegmentationCorePython

nodeNames = ["Model_-407.5", "Model_-405.0", "Model_-400.0", "Model_-395.0", "Model_-390.0", "Model_-385.0", "Model_-380.0", "Model_-375.0", "Model_-372.5"]

appendFilter = vtk.vtkAppendPolyData()

for nodeName in nodeNames:
    node = slicer.util.getNode(nodeName)
    if node:
        # Get the vtkPolyData from the node
        polyData = node.GetPolyData()
        if polyData:
            # Add the polyData to the appendFilter
            appendFilter.AddInputData(polyData)

appendFilter.Update()

outputPolyData = appendFilter.GetOutput()

newModelNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLModelNode", "outputPolyData")

newModelNode.SetAndObservePolyData(outputPolyData)

segmentationConverter = vtkSegmentationCorePython.vtkSegmentationConverter()
planarContourName = segmentationConverter.GetSegmentationPlanarContourRepresentationName()
print("Planar contour representation name:", planarContourName)

segmentationNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationNode")

```

Best regaeds.  
Shahrokh

---

<div class="post-metadata">

**Author:** ![shahrokh](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/shahrokh/32/1499_2.png) [@shahrokh](https://discourse.slicer.org/u/shahrokh)\
**Post date:** [April 21, 2024, 1:18pm UTC](https://discourse.slicer.org/t/how-to-create-of-surface-meshes-from-parallel-polygons-using-vtk-and-python/35557/4 "2024-04-21T13:18:34Z")

</div>

> [@cpinter](#):
>
> Set the appended polydata as the `Planar contour` representation of the segmentation node

First, I must thank Dear Csaba Pinter for the guidance provided in solving the issue I raised. In implementing this guidance, I encounter two issues:

_First Issue:_

Executing the above commands in the Python Console in 3DSlicer (repeated below) creates a node named “Segmentation”.

```auto
import vtk
import slicer
import vtkSegmentationCorePython

nodeNames = ["Model_-407.5", "Model_-405.0", "Model_-400.0", "Model_-395.0", "Model_-390.0", "Model_-385.0", "Model_-380.0", "Model_-375.0", "Model_-372.5"]

appendFilter = vtk.vtkAppendPolyData()

for nodeName in nodeNames:
    node = slicer.util.getNode(nodeName)
    if node:
        # Get the vtkPolyData from the node
        polyData = node.GetPolyData()
        if polyData:
            # Add the polyData to the appendFilter
            appendFilter.AddInputData(polyData)

appendFilter.Update()

outputPolyData = appendFilter.GetOutput()

newModelNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLModelNode", "outputPolyData")

newModelNode.SetAndObservePolyData(outputPolyData)

segmentationConverter = vtkSegmentationCorePython.vtkSegmentationConverter()
planarContourName = segmentationConverter.GetSegmentationPlanarContourRepresentationName()
print("Planar contour representation name:", planarContourName)

segmentationNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationNode")

```

As seen in the following figure, its **Representation** type is **Binary labelmap** , not **Planar contour**. I expected that by executing the above commands, the **Representation** type would be **Planar contour**.

 ![1](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/8/2/826c54dc64542efdcb2cccdf38c6f791ce223f9f.png)

How can I set the **Representation** type to **Planar contour** according to the provided guidance by Csaba Pinter?

_Second Issue_:  
In implementing the third step, Csaba Pinter told that:  
Set the appended polydata as the `Planar contour` representation of the segmentation node…

I have a problem. I can do this by setting **Planar contour** and importing outputPolyData in **Segmentations** module (not in Python Console of 3DSlicer), but I encounter the following error. How can I perform this third step?

 ![2](https://us1.discourse-cdn.com/flex002/uploads/slicer/original/3X/a/8/a868c1abef2434885dc6418aa40b9050a1f680bf.png)

Please guide me to do step #2 and #3.  
Best regards.  
Shahrokh

---

<div class="post-metadata">

**Author:** ![cpinter](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/cpinter/32/7995_2.png) [@cpinter](https://discourse.slicer.org/u/cpinter)\
**Post date:** [April 22, 2024, 1:11pm UTC](https://discourse.slicer.org/t/how-to-create-of-surface-meshes-from-parallel-polygons-using-vtk-and-python/35557/5 "2024-04-22T13:11:09Z")

</div>

The code seems so far so good, but not complete. As you said you’ll need to set the proper source representation, and then the representation itself. By the way I suggest using the latest Slicer, 5.2.2 is now years old, and the API has changed a bit since then too (e.g. “master” vs “source” representation).

```auto
segmentationNode.GetSegmentation().SetSourceRepresentationName(planarContourName)
seg = slicer.vtkSegment()
seg.SetName('NameYouWant')
seg.AddRepresentation(planarContourName, newModelNode.GetPolyData())
segmentationNode.GetSegmentation().AddSegment(seg)

```

A few comments:

- You don’t need `import vtkSegmentationCorePython`, you can simply do `slicer.vtkSegmentationConverter`. Also, you don’t need to instantiate it, so just `slicer.vtkSegmentationConverter.GetSegmentationPlanarContourRepresentationName()`
- You don’t need to create a new model node. Just have the poly data. So in the above snippet, you can replace `newModelNode.GetPolyData()` with `appendFilter.GetOutput()`

---

<div class="post-metadata">

**Author:** ![shahrokh](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/shahrokh/32/1499_2.png) [@shahrokh](https://discourse.slicer.org/u/shahrokh)\
**Post date:** [April 23, 2024, 11:44am UTC](https://discourse.slicer.org/t/how-to-create-of-surface-meshes-from-parallel-polygons-using-vtk-and-python/35557/6 "2024-04-23T11:44:26Z")

</div>

> [@cpinter](#):
>
> `GetClosedSurfaceRepresentation`

Thank you very much to Csaba Pinter for the guidance in implementing the code. As you mentioned, I made the changes in the code as follows:

```auto
import vtk
import slicer

# Step #1
nodeNames = ["Model_-407.5", "Model_-405.0", "Model_-400.0", "Model_-395.0", "Model_-390.0", "Model_-385.0", "Model_-380.0", "Model_-375.0", "Model_-372.5"]

appendFilter = vtk.vtkAppendPolyData()

for nodeName in nodeNames:
    node = slicer.util.getNode(nodeName)
    if node:
        # Get the vtkPolyData from the node
        polyData = node.GetPolyData()
        if polyData:
            # Add the polyData to the appendFilter
            appendFilter.AddInputData(polyData)

appendFilter.Update()

outputPolyData = appendFilter.GetOutput()

newModelNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLModelNode", "outputPolyData")

newModelNode.SetAndObservePolyData(outputPolyData)

# Step #2
segmentationConverter = slicer.vtkSegmentationConverter()
planarContourName = slicer.vtkSegmentationConverter.GetSegmentationPlanarContourRepresentationName()
segmentationNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationNode")

# Step #3 (the guidance of Csaba Pinter)
segmentationNode.GetSegmentation().SetSourceRepresentationName(planarContourName)
seg = slicer.vtkSegment()
seg.SetName('bolusSegment')
seg.AddRepresentation(planarContourName, appendFilter.GetOutput())
segmentationNode.GetSegmentation().AddSegment(seg)

```

Now, in the implementation of the fourth step, I encountered the following error:

```auto
# Step #4
id = segmentationNode.GetID()
segmentationNode.GetClosedSurfaceRepresentation(id, outputPolyData)

```

The output I obtained by executing the last command is as follows:

```auto
False
[VTK] GetClosedSurfaceRepresentation: Invalid segment

```

Unfortunately, I don’t understand why I encountered this error. I even used the **[CreateClosedSurfaceRepresentation()](https://apidocs.slicer.org/main/classvtkMRMLSegmentationNode.html#a981a64425627037c55d418c36981e371)** method because it was explained in relation to `GetClosedSurfaceRepresentation` that:

“Get a segment as a surface mesh. If representation does not exist yet then CreateClosedSurfaceRepresentation() must be called before this method. This function returns a copy of the segment closed surface in outputClosedSurface. Returns true on success.”

Please guide me.  
Best regards.  
Shahrokh

---

<div class="post-metadata">

**Author:** ![shahrokh](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/shahrokh/32/1499_2.png) [@shahrokh](https://discourse.slicer.org/u/shahrokh)\
**Post date:** [April 24, 2024, 12:55pm UTC](https://discourse.slicer.org/t/how-to-create-of-surface-meshes-from-parallel-polygons-using-vtk-and-python/35557/7 "2024-04-24T12:55:50Z")

</div>

> [@cpinter](#):
>
> on the segmentation node

As mentioned in the help on built-in function `GetClosedSurfaceRepresentation`:

```auto
GetClosedSurfaceRepresentation(...) method of MRMLCorePython.vtkMRMLSegmentationNode instance
GetClosedSurfaceRepresentation(self, segmentId:str,
outputClosedSurface:vtkPolyData) -> bool
C++: virtual bool GetClosedSurfaceRepresentation(
const std::string segmentId, vtkPolyData *outputClosedSurface)
Get a segment as a surface mesh. If representation does not exist
yet then CreateClosedSurfaceRepresentation() must be called
before this method. This function returns a copy of the segment
closed surface in outputClosedSurface. Returns true on success.

```

As mentioned above, If the representation does not exist, the function `CreateClosedSurfaceRepresentation` must be called before using this method. Excuse me, but I didn’t understand why Csaba Pinter mentioned that the representation type should be `Planar contour` in guidance. Anyway, I continued my efforts according to this help (although I believe this is not correct):

```auto
>>> segmentationNode.CreateClosedSurfaceRepresentation()
True

```

Then , I call `GetClosedSurfaceRepresentation` on the segmentation node.

```auto
>>> segmentationNode.GetClosedSurfaceRepresentation(segmentationNode.GetID(), outputPolyData)
False
[VTK] GetClosedSurfaceRepresentation: Invalid segment
>>> 

```

As mentioned above, the problem is related to the first argument of the `CreateClosedSurfaceRepresentation` method.  
Excuse me… How can I set the two arguments of `GetClosedSurfaceRepresentation` so that it creates and covers all contours of my models `(Model_-407.5, Model_-405.0, ..., Model_-372.5)` with a solid model?

Please guide me.  
Best regards.  
Shahrokh

---

<div class="post-metadata">

**Author:** ![shahrokh](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/shahrokh/32/1499_2.png) [@shahrokh](https://discourse.slicer.org/u/shahrokh)\
**Post date:** [April 24, 2024, 2:03pm UTC](https://discourse.slicer.org/t/how-to-create-of-surface-meshes-from-parallel-polygons-using-vtk-and-python/35557/8 "2024-04-24T14:03:11Z")

</div>

During my attempt to call `GetClosedSurfaceRepresentation`, I encountered an interesting coincidence. Upon executing the following codes, when I run the commands the section of `Step #4`, 3DSlicer suddenly **crashes and closes**.

```auto
import vtk
import slicer

# Step #1
nodeNames = ["Model_-407.5", "Model_-405.0", "Model_-400.0", "Model_-395.0", "Model_-390.0", "Model_-385.0", "Model_-380.0", "Model_-375.0", "Model_-372.5"]

appendFilter = vtk.vtkAppendPolyData()

for nodeName in nodeNames:
    node = slicer.util.getNode(nodeName)
    if node:
        # Get the vtkPolyData from the node
        polyData = node.GetPolyData()
        if polyData:
            # Add the polyData to the appendFilter
            appendFilter.AddInputData(polyData)

appendFilter.Update()

outputPolyData = appendFilter.GetOutput()

newModelNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLModelNode", "outputPolyData")

newModelNode.SetAndObservePolyData(outputPolyData)

# Step #2
segmentationConverter = slicer.vtkSegmentationConverter()
planarContourName = slicer.vtkSegmentationConverter.GetSegmentationPlanarContourRepresentationName()
segmentationNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLSegmentationNode")

# Step #3 (the guidance of Csaba Pinter)
segmentationNode.GetSegmentation().SetSourceRepresentationName(planarContourName)
seg = slicer.vtkSegment()
seg.SetName('bolusSegment')
seg.AddRepresentation(planarContourName, appendFilter.GetOutput())
segmentationNode.GetSegmentation().AddSegment(seg)

# Step #4
segmentation_node = slicer.util.getNode('Segmentation')
segment_id = segmentation_node.GetSegmentation().GetSegmentIdBySegmentName('bolusSegment')
segmentation_node.CreateClosedSurfaceRepresentation()
segmentation_node.GetClosedSurfaceRepresentation(segment_id, outputPolyData)

```

I think that I am near to implementing of the fourth step (with the minor error)  
Please guide me to solve it.  
Thanks a lot.  
Best regards.  
Shahrokh

---

<div class="post-metadata">

**Author:** ![lassoan](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/lassoan/32/13_2.png) [@lassoan](https://discourse.slicer.org/u/lassoan)\
**Post date:** [April 25, 2024, 4:41am UTC](https://discourse.slicer.org/t/how-to-create-of-surface-meshes-from-parallel-polygons-using-vtk-and-python/35557/9 "2024-04-25T04:41:17Z")

</div>

I’ve implemented something like this for OsiriX ROI importer module. You might find the code useful: [SlicerSandbox/ImportOsirixROI/ImportOsirixROI.py at master · PerkLab/SlicerSandbox · GitHub](https://github.com/PerkLab/SlicerSandbox/blob/master/ImportOsirixROI/ImportOsirixROI.py)
