Search code examples
pythonvtkmitk

How to use vtk (python) to visualize a 3D CT scan?


I wanna visualize a 3D CT just like the following image. [MITK-visualization]:https://i.sstatic.net/xCuZW.png (Note that I only need the part at bottom right)

I am using python and vtk. Could anyone provide an example on it?

Suppose the variable "array" is the CT data whose shape is (512,512,3), then what should I do with it?


Solution

  • Visualising a 3D CT can be done in two different ways i) either render it into a 3D volume using an algorithm like Marching Cubes ii) either visualize the different views, i.e. sagittal, axial, coronal of the 3D scan. I assume you want the latter approach, so you need an Orthographic Slicing:

    # This example shows how to load a 3D image into VTK and then reformat
    # that image into a different orientation for viewing.  It uses
    # vtkImageReslice for reformatting the image, and uses vtkImageActor
    # and vtkInteractorStyleImage to display the image.  This InteractorStyle
    # forces the camera to stay perpendicular to the XY plane.
    
    import vtk
    from vtk.util.misc import vtkGetDataRoot
    VTK_DATA_ROOT = vtkGetDataRoot()
    
    # Start by loading some data.
    reader = vtk.vtkImageReader2()
    reader.SetFilePrefix(VTK_DATA_ROOT + "/Data/headsq/quarter")
    reader.SetDataExtent(0, 63, 0, 63, 1, 93)
    reader.SetDataSpacing(3.2, 3.2, 1.5)
    reader.SetDataOrigin(0.0, 0.0, 0.0)
    reader.SetDataScalarTypeToUnsignedShort()
    reader.UpdateWholeExtent()
    
    # Calculate the center of the volume
    reader.Update()
    (xMin, xMax, yMin, yMax, zMin, zMax) = reader.GetExecutive().GetWholeExtent(reader.GetOutputInformation(0))
    (xSpacing, ySpacing, zSpacing) = reader.GetOutput().GetSpacing()
    (x0, y0, z0) = reader.GetOutput().GetOrigin()
    
    center = [x0 + xSpacing * 0.5 * (xMin + xMax),
              y0 + ySpacing * 0.5 * (yMin + yMax),
              z0 + zSpacing * 0.5 * (zMin + zMax)]
    
    # Matrices for axial, coronal, sagittal, oblique view orientations
    axial = vtk.vtkMatrix4x4()
    axial.DeepCopy((1, 0, 0, center[0],
                    0, 1, 0, center[1],
                    0, 0, 1, center[2],
                    0, 0, 0, 1))
    
    coronal = vtk.vtkMatrix4x4()
    coronal.DeepCopy((1, 0, 0, center[0],
                      0, 0, 1, center[1],
                      0,-1, 0, center[2],
                      0, 0, 0, 1))
    
    sagittal = vtk.vtkMatrix4x4()
    sagittal.DeepCopy((0, 0,-1, center[0],
                       1, 0, 0, center[1],
                       0,-1, 0, center[2],
                       0, 0, 0, 1))
    
    oblique = vtk.vtkMatrix4x4()
    oblique.DeepCopy((1, 0, 0, center[0],
                      0, 0.866025, -0.5, center[1],
                      0, 0.5, 0.866025, center[2],
                      0, 0, 0, 1))
    
    # Extract a slice in the desired orientation
    reslice = vtk.vtkImageReslice()
    reslice.SetInputConnection(reader.GetOutputPort())
    reslice.SetOutputDimensionality(2)
    reslice.SetResliceAxes(sagittal)
    reslice.SetInterpolationModeToLinear()
    
    # Create a greyscale lookup table
    table = vtk.vtkLookupTable()
    table.SetRange(0, 2000) # image intensity range
    table.SetValueRange(0.0, 1.0) # from black to white
    table.SetSaturationRange(0.0, 0.0) # no color saturation
    table.SetRampToLinear()
    table.Build()
    
    # Map the image through the lookup table
    color = vtk.vtkImageMapToColors()
    color.SetLookupTable(table)
    color.SetInputConnection(reslice.GetOutputPort())
    
    # Display the image
    actor = vtk.vtkImageActor()
    actor.GetMapper().SetInputConnection(color.GetOutputPort())
    
    renderer = vtk.vtkRenderer()
    renderer.AddActor(actor)
    
    window = vtk.vtkRenderWindow()
    window.AddRenderer(renderer)
    
    # Set up the interaction
    interactorStyle = vtk.vtkInteractorStyleImage()
    interactor = vtk.vtkRenderWindowInteractor()
    interactor.SetInteractorStyle(interactorStyle)
    window.SetInteractor(interactor)
    window.Render()
    
    # Create callbacks for slicing the image
    actions = {}
    actions["Slicing"] = 0
    
    def ButtonCallback(obj, event):
        if event == "LeftButtonPressEvent":
            actions["Slicing"] = 1
        else:
            actions["Slicing"] = 0
    
    def MouseMoveCallback(obj, event):
        (lastX, lastY) = interactor.GetLastEventPosition()
        (mouseX, mouseY) = interactor.GetEventPosition()
        if actions["Slicing"] == 1:
            deltaY = mouseY - lastY
            reslice.Update()
            sliceSpacing = reslice.GetOutput().GetSpacing()[2]
            matrix = reslice.GetResliceAxes()
            # move the center point that we are slicing through
            center = matrix.MultiplyPoint((0, 0, sliceSpacing*deltaY, 1))
            matrix.SetElement(0, 3, center[0])
            matrix.SetElement(1, 3, center[1])
            matrix.SetElement(2, 3, center[2])
            window.Render()
        else:
            interactorStyle.OnMouseMove()
    
    
    interactorStyle.AddObserver("MouseMoveEvent", MouseMoveCallback)
    interactorStyle.AddObserver("LeftButtonPressEvent", ButtonCallback)
    interactorStyle.AddObserver("LeftButtonReleaseEvent", ButtonCallback)
    
    # Start interaction
    interactor.Start()
    

    You can also do the following:

    1. Use the numpy_support module and more specifically the numpy_support.numpy_to_vtk function

    2. You can pip install pyevtk and use pyevtk

    from pyevtk.hl import gridToVTK

    noSlices = 5
    juliaStacked = numpy.dstack([julia]*noSlices)
    
    x = numpy.arange(0, w+1)
    y = numpy.arange(0, h+1)
    z = numpy.arange(0, noSlices+1)
    
    gridToVTK("./julia", x, y, z, cellData = {'julia': juliaStacked})
    

    Please see this link for more information