VMTK vessel centerline network extraction in Slicer

The page you referred to documentats usage of VMTK’s special “pypes” scripts. These scripts are not Python classes that you import and use, but scripts that you can use via command line. They are very thin wrappers over Python classes, which are useful for people who prefer to work using command-line. For example, you can have a look at vmtknetworkextraction script and how it calls uses vtkvmtkPolyDataNetworkExtraction class. I would recommend to use the VTK classes directly instead of going through the extra layer of pypes scripts.

1 Like

@lassoan
Thank you very much for the clarification. I’m sorry about the confusion, I am really new to all of this.

Sure, I’d like to know how to process the branchids and the ids of endpoints associated with each branch.
For instance, I could do the following on polyData obtained after networkextraction.

edgeNode0 = edge.GetPointId(0)
edgeNode1 = edge.GetPointId(1)

This will give information on the topology.

What would like to compute exactly as end result? Average vessel radius over the entire tree? Average vessel segment length over the entire tree?

@lassoan
Yes, I would like to compute the average vessel segment length and average vessel segment radius
of all the branches in a tree.
Please check sample

I’ve added computation of branch length, average radius, curvature, torsion, and tortuosity to the centerline computation module. All you need to do to compute these metrics is to select a node for “Centerline properties”. This feature will be available in tomorrow’s Slicer Preview Release.

@lassoan Excellent! I am super happy to know about this new feature. Thanks a ton. I look forward to use this.

From what I understand, CellId refers to the branchid. It will be super helpful if you could also add
4 more columns branchNode0 and branchNode1, xyz_branchNode0, xyz_branchNode1.

branchNode0 = branch.GetPointId(0) # nodeid of the one end of a branch
branchNode1 = branch.GetPointId(1) # nodeid of the other end of a branch

and xyz_branchNode0, xyz_branchNode1 are the corresponding coordinates.

I had obtained the above in the following manner (code).

 for branchId in range(cleanedGraph.GetNumberOfCells()):
        branch = cleanedGraph.GetCell(branchId )  # this will be a vtkLine, which only has two points

    branchNode0 = branch .GetPointId(0)
    branchNode1 = branch .GetPointId(1)

output.
Deepa

You can cross-reference the displayed curve with the computed properties in the table based on the CellId displayed in parentheses in the widget’s node name, so you can find out quite easily which numbers are for which vessel segment.

Anyway, I have now added branch start and end point positions to the properties table.

1 Like

@lassoan

Thank you very much. This is extremely helpful.

If my understanding is right, the cellId displayed in parentheses are the numbers assigned to the vessel segments/ branches.
In my previous response, nodeid of the one end of a branch - I was referring to the ids of
StartPointPosition and EndPointPosition.

For instance, if I manually map the positions to ids for this simple input structure
CellId StartPointId EndPointId
0 0 1
1 1 2
2 2 3
3 2 4

and so on …

Can we retrieve these ids from the polyData? I think these can be mapped to the indices of the array
that stores these positions.

Thanks a lot again for these extensions!

Deepa

Parent/child relationships are the easiest to get from the curve hierarchy (you can get list of all immediate or all children nodes, etc.), but of course it is very easy to add any additional columns to the table, too. Could you describe what do you plan to compute and how?

Yes, that will be really helpful.

I plan to use this as an input for CFD studies where the endpoint ids will be useful for setting up external inputs.

What software do you plan to use and how? For CFD analysis, you probably need a couple of more things, such as:

  • use the original surface mesh instead of just centerline&radius (e.g., to model non-circular vessel geometry or aneurysms more accurately)
  • use a volumetric mesh
  • add straight extensions so that you can prescribe known boundary conditions at the end of those segments

These are all perfectly doable and have all the tools in Slicer and VMTK, but probably it would be better to implement these in a script first. Once you have a working script, it can be easily converted to a scripted module so that it is easier to use (you can select input/output nodes, parameters using a convenient GUI).

Let me know what exactly you would like to do and I’ll help with creating the script, and then with the conversion to scripted module.

Hi @lassoan

Thank you very much for offering to build scripted modules in Slicer for this study. This will be tremendously helpful for researchers working in this field.

For now, I’ve written my own code that models the underlying physics for performing the CFD analysis. I will be using the centerline properties obtained from Slicer as input. I would be super happy to share more details for developing a scripted module in Slicer in another 1-2 months. From my experience so far, Slicer will serve as a great platform since most of the tools are readily avaiable.

Kindly let me know after the ids of StartPointPosition EndPointPosition are appended to the centerline properties table. I look forward to use this feature.

@lassoan

This is a polite reminder about the inclusion of StartPointPosition EndPointPosition in the centerline properties table. I would like to know if this will be included.

Also, after the CenterlineComputationModel is created can we delete certain branches using the nodes defined in tree? I prefer to delete the branches with free ends, I want to retain only two free ends. Can we do this programmatically? If we can obtain the ids of all the free nodes from the network that is generated during computation of centerlines , the user can select the free ends to be retained and the branches that are connected to the other free ends can be deleted. The use case would be in CFD simulations where the boundary conditions can be defined. Defining boundary condition gets complicated when there are a lot of boundaries .

If this deletion cannot be directly done in Slicer, I would like to request for a export option that will allow the user to export the generated centerline network. The free ends can be deleted in an external tool by the user. This will be really helpful.

Branch deleting is now implemented, see:

1 Like

Hi @lassoan

Branch deleting works well for updating centerlines (i.e removal of branch in centerline model) when an endpoint is deleted. But the network branch doesn’t get removed. I’d like to know if it is possible to enable removal of the branches in network model too.

Network extraction gets all branches. To search a path between two points in a network, you can use the method described here:

Thanks a lot for the response. I would like to know if there is a way to remove a branch in the network model by selecting an endpoint and deleting it .

If you choose the curve hierarchy representation of the network then you have full control over each point of each branch: you can edit each individual point or remove each branch.

What would you like to achieve?

Endpoint(glyph) in one of the branches is removed using Delete point. Deleting this endpoin has updated the centerline model automatically after hitting apply but the network model has not been updated. I will like to achieve an updated network model(and results displayed in quantification table) as well.

Thank you.
I could use the hierarchy representation to remove individual branches in the network model. But this doesn’t help in obtaining the corresponding update (i.e deletion of the values in the table) in the quantification results.

You could write a small script that removes rows from the table that don’t have corresponding markup curve. You can get list of children nodes from the subject hierarchy node and the node has the cell index in a custom attribute. You could collect all the indices and create a new properties table, where you would only include those rows that have its index in the list.

1 Like