I have generated a center line for a sample of hepatic vessel tree in form of vertices and edges. I converted the vertices and edges to a vtkGraph and then used vtkGraphToPolyData() to convert it into vtkPolyData.
I want to convert this PolyData to binary mask in Nifti or mhd format. I tried using vtkPolyDataToImageStencil() but the output image is empty. I would really appreciate any help. I used the following code to convert the polydata to Nifti file.
If you still have the original polydata that VMTK generated then you can use it as input of a vtkTubeFilter. You can even use the radius scalar values to set the radius of the tube. Once you have the tube, you can use vtkPolyDataToImageStencil to create the binary image. Note that VMTK also has example Python scripts for all these operations.
One potential root cause of the issue is that you have forgot to enable capping in the tube filter, so the stencil cannot know what is inside and what is outside near the end of the tubes.
Artifacts are also expected at sharp edges or branching points due to self-intersection. vtkTubeBender might handle sharp edges better. For clean branching points you may need to use a modeling filter, such as those in VMTK (for example, vtkvmtkPolyBallLine should be able to provide a perfect, artifact-free labelmap for every centerline with varying radius and arbitrary branching).
I enabled capping and that got rid of sections emerging from the ends of branches, but there are still artifacts like missing branches of the tree. vtkTubeBender didn’t seem to help, I also tried smoothing the tube output but the end branches are still missing.
Now, I am trying to use the vtkvmtkPolyBallModeller() by following the vmtkcenterlinemodeller, but the output does not seem reasonable and the script takes around 25 mins to run. The intensity values in the output nifti file ranges from 19k to 99k. I am using the following code:
import vtk
from vmtk import vtkvmtk
from vtk.util import numpy_support
import numpy as np
def main():
main_dir = "/home/roman/Downloads/test3/2/"
reference_image_path = main_dir + "seg.nii.gz" # To get output image size
vtk_path = main_dir + "centerline_model.vtk" # path to VMTK output
# Read image
nifti_reader = vtk.vtkNIFTIImageReader()
nifti_reader.SetFileName(reference_image_path)
nifti_reader.Update()
nifti_image = nifti_reader.GetOutput()
# Read VMTK output as polydata
reader = vtk.vtkPolyDataReader()
reader.SetFileName(vtk_path)
reader.Update()
centerline_polydata = reader.GetOutput()
radii_n = np.ones(centerline_polydata.GetNumberOfPoints())
radii_vtk = numpy_support.numpy_to_vtk(num_array=radii_n.ravel(), deep=True, array_type=vtk.VTK_DOUBLE)
radii_vtk.SetName("UnitRadius")
centerline_polydata.GetPointData().AddArray(radii_vtk) # Adding additional array for fixed radius
modeller = vtkvmtk.vtkvmtkPolyBallModeller()
modeller.SetInputData(centerline_polydata)
modeller.SetRadiusArrayName('UnitRadius')
modeller.SetReferenceImage(nifti_image)
modeller.UsePolyBallLineOn()
modeller.SetNegateFunction(0)
modeller.Update()
# Save image as nifty file
writer = vtk.vtkNIFTIImageWriter()
writer.SetFileName(main_dir + "centerline_tube.nii.gz")
writer.SetInputConnection(modeller.GetOutputPort())
writer.Write()
if __name__ == '__main__':
main()
Although it won’t be very fast, you can try vtkImplicitPolyDataDistance. Use the vessel tree as input. Feed the output into vtkImplicitFunctionToImageStencil. Use SetThreshold(2.0) to select a 2 mm radius for binarization. Also use ReverseStencilOn() when you apply vtkImageStencil to get the image.
Actually vtkImplicitModeller might be able to do this more efficiently than vtkImplicitPolyDataDistance. There are quite a few examples, none specific to vessels, but there doesn’t seem to be any reason why it wouldn’t work.
The built-in VTK modelers should work well, but I think they only support uniform radius. VMTK can generate the centerline with varying radius. @mau_igna_06 has just used VMTK for this recently. I think he ended up using vtkvmtkPolyBallLine.
Hi, I have a similar converting problem: I have a Left atrium (LA) in a VTK format. LA is part of a heart. I have a heart MRI scan (a dicom series), and the size is hwz. I want to convert the VTK file of LA to a 3D binary mask that can map MRIs exactly. But I am sure how to set up the origins, spacings, etc. Since there are three coordinate systems: patient, Dicom, and VTk system. Am I right? Could you help me with this problem? Thank you so much!
Hi Hui, it is better if you open a new topic for your question. Because even though it is related, it does not fit the description “Convert vessel centerline from vtkPolyData to a Nifti binary mask”.