# Automatic centerline

**URL:** <https://discourse.slicer.org/t/automatic-centerline/14829>\
**Category:** VMTK\
**Created:** [December 1, 2020, 3:55pm UTC](https://discourse.slicer.org/t/automatic-centerline/14829 "2020-12-01T15:55:01Z")\
**Posts on this page:** 12\
**Page:** 2

<div class="post-metadata">

**Author:** ![jeffc](https://avatars.discourse-cdn.com/v4/letter/j/ed8c4c/32.png) [@jeffc](https://discourse.slicer.org/u/jeffc)\
**Post date:** [October 22, 2021, 9:28am UTC](https://discourse.slicer.org/t/automatic-centerline/14829/21 "2021-10-22T09:28:17Z")

</div>

Thanks Andras. For now I’m trying to use it from the Slicer python interactor and that line worked. It now works as expected with:

```auto
logic = ExtractCenterlineLogic()

```

But, once I enter:

```auto
logic.run(inputVolume, outputVolume, threshold, True)

```

I now get:

```auto
AttributeError: 'ExtractCenterlineLogic' object has no attribute 'run'

```

Any ideas?  
Apologies, I feel very feeble and don’t like having to ask for so much help but am otherwise completely lost and unable to make progress! My end goal is to simply feed in an already level set thresholded .vtp model and use the auto detect endpoints function to compute the centreline.  
Thanks

---

<div class="post-metadata">

**Author:** ![jeffc](https://avatars.discourse-cdn.com/v4/letter/j/ed8c4c/32.png) [@jeffc](https://discourse.slicer.org/u/jeffc)\
**Post date:** [October 28, 2021, 2:07pm UTC](https://discourse.slicer.org/t/automatic-centerline/14829/22 "2021-10-28T14:07:16Z")

</div>

Hi Andras, do you have any ideas for how to solve this current issue? I am hoping that what I want to do is quite simple but I’m struggling with the programmatic implementation.  
As before my end goal is to feed in an already level set thresholded .vtp model and use the auto detect endpoints function to find the endpoints then compute the centreline.  
I am able to feed in the .vtp model but I’m struggling with programming of the auto detect endpoints function.  
Any assistance you’re able to provide would be very much appreciated.

---

<div class="post-metadata">

**Author:** ![mikebind](https://avatars.discourse-cdn.com/v4/letter/m/71e660/32.png) [@mikebind](https://discourse.slicer.org/u/mikebind)\
**Post date:** [October 28, 2021, 6:52pm UTC](https://discourse.slicer.org/t/automatic-centerline/14829/23 "2021-10-28T18:52:14Z")

</div>

It looks like the tests have not been updated since an earlier version of the module; the error message is correct that there is no run() method in ExtractCenterlineLogic. There is an extractCenterline() method which takes as inputs surfacePolyData, endPointsMarkupsNode, and a curveSamplingDistance. Here is what I think you need:

```auto
segmentationName = 'MySegmentationName' # replace with the name of your segmentation
segmentName = 'MySegmentName' # replace with the name of the segment you want to find the centerline of
segmentationNode = slicer.util.getNode(segmentationName)
segmentID = segmentationNode.GetSegmentation().GetSegmentIdBySegmentName(segmentName)

import ExtractCenterline
extractLogic = ExtractCenterline.ExtractCenterlineLogic()

# Preprocess the surface
inputSurfacePolyData = extractLogic.polyDataFromNode(segmentationNode, segmentID)
targetNumberOfPoints = 5000.0
decimationAggressiveness = 4 # I had to lower this to 3.5 in at least one case to get it to work, 4 is the default in the module
subdivideInputSurface = False
preprocessedPolyData = extractLogic.preprocess(inputSurfacePolyData, targetNumberOfPoints, decimationAggressiveness, subdivideInputSurface)

# Auto-detect the endpoints
endPointsMarkupsNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsFiducialNode", "Centerline endpoints")
networkPolyData = extractLogic.extractNetwork(preprocessedPolyData, endPointsMarkupsNode)
startPointPosition=None
endpointPositions = extractLogic.getEndPoints(networkPolyData, startPointPosition)
endPointsMarkupsNode.RemoveAllMarkups()
for position in endpointPositions:
  endPointsMarkupsNode.AddControlPoint(vtk.vtkVector3d(position))

# Extract the centerline
centerlineCurveNode = slicer.mrmlScene.AddNewNodeByClass("vtkMRMLMarkupsCurveNode", "Centerline curve")
centerlinePolyData, voronoiDiagramPolyData = extractLogic.extractCenterline(preprocessedPolyData, endPointsMarkupsNode)
centerlinePropertiesTableNode = None
extractLogic.createCurveTreeFromCenterline(centerlinePolyData, centerlineCurveNode, centerlinePropertiesTableNode)

```

After you run this, the centerline should be in `centerlineCurveNode`, and the auto-detected endpoints should be in `endPointsMarkupsNode`. I don’t know if the preprocessing step is strictly necessary (it seems like you may know more about the inner workings of VMTK than I do), but it seems recommended. To get this code snippet, I tried to pull the relevant lines out of a few functions in the ExtractCenterlineLogic class ([SlicerExtension-VMTK/ExtractCenterline.py at 3787ea4a300da28ec5f0824f0715f2713b631155 · vmtk/SlicerExtension-VMTK · GitHub](https://github.com/vmtk/SlicerExtension-VMTK/blob/3787ea4a300da28ec5f0824f0715f2713b631155/ExtractCenterline/ExtractCenterline.py#L378)). I have not tried running the auto-detect endpoints this way, but I have done the centerline extraction with supplied endpoints using VMTK using the above methods in one of my own python modules.

---

<div class="post-metadata">

**Author:** ![jeffc](https://avatars.discourse-cdn.com/v4/letter/j/ed8c4c/32.png) [@jeffc](https://discourse.slicer.org/u/jeffc)\
**Post date:** [October 29, 2021, 2:36pm UTC](https://discourse.slicer.org/t/automatic-centerline/14829/24 "2021-10-29T14:36:20Z")

</div>

Mike, thank you so much!  
I’m having a few hiccups getting this to completely work but it is a very useful starting point and I’m much further along than I was before, so thank you. I’m working to get it all ironed out now and hopefully have my first automated centerlines produced soon 🙂  
Thanks again

---

<div class="post-metadata">

**Author:** ![kayarre](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/kayarre/32/3606_2.png) [@kayarre](https://discourse.slicer.org/u/kayarre)\
**Post date:** [November 4, 2021, 8:57pm UTC](https://discourse.slicer.org/t/automatic-centerline/14829/25 "2021-11-04T20:57:12Z")

</div>

Another approach I have used is with a surface mesh that is open at each place I would like there to be centerline seed. vmtk can detect the centroid of each open region and provide the seed location.

---

<div class="post-metadata">

**Author:** ![Jebsta](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/jebsta/32/67179_2.png) [@Jebsta](https://discourse.slicer.org/u/Jebsta)\
**Post date:** [August 15, 2023, 12:38pm UTC](https://discourse.slicer.org/t/automatic-centerline/14829/26 "2023-08-15T12:38:20Z")

</div>

This discussion was quiet helpful for me.  
But i get stuck at the part where teh slicer environment is used.  
I already have a quiet sufisticated virtual environment for a project and i also need the automatic centerline extraction.

Is there a way to get “slicer” into a already existing venv, or just use parts of the extionsion?

or is it possible to pass the pype the point coordinates manually?

---

<div class="post-metadata">

**Author:** ![pieper](https://sea2.discourse-cdn.com/flex002/user_avatar/discourse.slicer.org/pieper/32/8_2.png) [@pieper](https://discourse.slicer.org/u/pieper)\
**Post date:** [August 15, 2023, 1:38pm UTC](https://discourse.slicer.org/t/automatic-centerline/14829/27 "2023-08-15T13:38:29Z")

</div>

You can’t directly use Slicer’s python modules in another python interpreter, but it should be easy to move data back and forth through files or other methods.

---

<div class="post-metadata">

**Author:** ![MuckYu](https://avatars.discourse-cdn.com/v4/letter/m/d6d6ee/32.png) [@MuckYu](https://discourse.slicer.org/u/MuckYu)\
**Post date:** [February 20, 2024, 6:44pm UTC](https://discourse.slicer.org/t/automatic-centerline/14829/28 "2024-02-20T18:44:39Z")

</div>

Thanks! This is working quite well on my end.

I have one issue though.

In some test models - when I am using the “manual” centerline method with the Slicer UI. When I click the Auto-detect button for the points. The first time it will put the points at not so great locations. But when I press the button again it puts the endpoints at the correct locations.  
(And when I press again a few times - always the same location as the second one)

Now when I use the script - it puts the endpoints at the location as when I clicked the button the first time. How can I “repeat” the endpoint selection so that it puts them like the second button click?

I already tried to just repeat the code but that did not work.

---

<div class="post-metadata">

**Author:** ![mikebind](https://avatars.discourse-cdn.com/v4/letter/m/71e660/32.png) [@mikebind](https://discourse.slicer.org/u/mikebind)\
**Post date:** [February 26, 2024, 7:33pm UTC](https://discourse.slicer.org/t/automatic-centerline/14829/29 "2024-02-26T19:33:41Z")

</div>

Sorry, I’m not sure why this happens. I guess maybe the first time the endpoints are located on a non-preprocessed surface, and the pre-processed surface is also generated, then maybe for the second click the endpoints are located using the preprocessed surface? If that were the case, then you might be able to get the result you want by doing the pre-processing step before finding the endpoints, and then making sure to include the pre-processed surface as an input. If that’s not what is going on, then I don’t really have any other ideas about what might cause that behavior.

---

<div class="post-metadata">

**Author:** ![MuckYu](https://avatars.discourse-cdn.com/v4/letter/m/d6d6ee/32.png) [@MuckYu](https://discourse.slicer.org/u/MuckYu)\
**Post date:** [February 29, 2024, 12:19pm UTC](https://discourse.slicer.org/t/automatic-centerline/14829/30 "2024-02-29T12:19:28Z")

</div>

Okay understood - I will try around a bit more.

One other question - right now the script is using the autodetect points feature.  
How can I specify my own point coordinates in there?  
Do they need to be in a specific format?

---

<div class="post-metadata">

**Author:** ![MuckYu](https://avatars.discourse-cdn.com/v4/letter/m/d6d6ee/32.png) [@MuckYu](https://discourse.slicer.org/u/MuckYu)\
**Post date:** [February 29, 2024, 5:21pm UTC](https://discourse.slicer.org/t/automatic-centerline/14829/31 "2024-02-29T17:21:43Z")

</div>

I was able to place the endpoints like this now:

> endpoint1 = [16.676, 40.6308, 68.4079]  
> endpoint2 = [-17.6128, -45.0295, -65.3733]
> 
> selected\_endpointPositions = [endpoint1, endpoint2]
> 
> selectedEndPointsNode = slicer.mrmlScene.AddNewNodeByClass(“vtkMRMLMarkupsFiducialNode”, “Selected Endpoints”)
> 
> selectedEndPointsNode.RemoveAllControlPoints()  
> for position in selected\_endpointPositions:  
> selectedEndPointsNode.AddControlPoint(vtk.vtkVector3d(position))
> 
> centerlinePolyData, voronoiDiagramPolyData = extractLogic.extractCenterline(preprocessedPolyData, selectedEndPointsNode)

But I am getting the following error:

> [VTK] Warning: In vtkvmtkSteepestDescentLineTracer.cxx, line 213
> 
> [VTK] vtkvmtkSteepestDescentLineTracer (00000201FB689510): Can’t find a steepest descent edge. Target not reached.

When I select points manually from the dropdown in the UI it works just fine.  
Is there something I am missing?

EDIT: Actually it seems it can only detect the network curve when I try it manually?  
(how can I do it with python?)

But not the “Tree curve”?

---

<div class="post-metadata">

**Author:** ![mikebind](https://avatars.discourse-cdn.com/v4/letter/m/71e660/32.png) [@mikebind](https://discourse.slicer.org/u/mikebind)\
**Post date:** [February 29, 2024, 7:33pm UTC](https://discourse.slicer.org/t/automatic-centerline/14829/32 "2024-02-29T19:33:11Z")

</div>

I would recommend that you take a look at exactly how it is done in ExtractCenterline.py. I know that the final centerline endpoints lie on the voronoi medial surface even when the input endpoints are not on this surface; perhaps there is a preprocessing step which finds the closest points on the voronoi medial surface to your selected endpoints and substitutes those before passing to extractLogic.extractCenterline(). All the steps in the processing that you can achieve via the GUI are definitely possible to achieve using python, because the module the GUI is running is a python scripted module. I don’t have time to dig into the code at the moment, so these are just suggestions from memory which I hope can be helpful to you. I think the most productive path will be for you to examine ExtractCenterline.py in detail. Good luck!

[Previous page](https://discourse.slicer.org/t/automatic-centerline/14829.md?page=1)
