简体   繁体   中英

How to volume render 3D numpy array using VTK (MarchingCubes) in Python?

I have a 3D numpy array and I am trying to volume render it using VTK. However, I get a completely different volume rendering when I visualise it. I suspect it has something to do with my conversion of numpy array to the VTK image format but I can't seem to figure out where I am going wrong. I have uploaded the numpy array here .

Can someone help me figure out where I'm going wrong?

This is my code:

#!/usr/bin/env python

import os
import numpy as np
# noinspection PyUnresolvedReferences
import vtkmodules.vtkInteractionStyle
# noinspection PyUnresolvedReferences
import vtkmodules.vtkRenderingOpenGL2
from vtkmodules.vtkIOImage import vtkImageImport

from vtkmodules.vtkCommonColor import vtkNamedColors
from vtkmodules.vtkCommonCore import (
    VTK_VERSION_NUMBER,
    vtkVersion
)
from vtkmodules.vtkCommonDataModel import vtkImageData
from vtkmodules.vtkFiltersCore import (
    vtkFlyingEdges3D,
    vtkMarchingCubes
)
from vtkmodules.vtkFiltersSources import vtkSphereSource
from vtkmodules.vtkIOImage import vtkDICOMImageReader
from vtkmodules.vtkImagingHybrid import vtkVoxelModeller
from vtkmodules.vtkRenderingCore import (
    vtkActor,
    vtkPolyDataMapper,
    vtkRenderWindow,
    vtkRenderWindowInteractor,
    vtkRenderer
)

ArrayDicom = np.load('test3.npy')
data_matrix = ArrayDicom
w, d, h = ArrayDicom.shape


colors = vtkNamedColors()
iso_value = 200

reader = vtkImageImport()
data_string = data_matrix.tobytes()
reader.CopyImportVoidPointer(data_string, len(data_string))
reader.SetDataScalarTypeToUnsignedChar()
reader.SetNumberOfScalarComponents(1)
reader.SetDataExtent(0, w-1, 0, d-1, 0, h-1)
reader.SetWholeExtent(0, w-1, 0, d-1, 0, h-1)
reader.Update()

volume = vtkImageData()
volume.DeepCopy(reader.GetOutput())

surface = vtkMarchingCubes()
surface.SetInputData(volume)
surface.ComputeNormalsOn()
surface.SetValue(0, iso_value)

renderer = vtkRenderer()
renderer.SetBackground(colors.GetColor3d('DarkSlateGray'))

render_window = vtkRenderWindow()
render_window.AddRenderer(renderer)
render_window.SetWindowName('MarchingCubes')

interactor = vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)

mapper = vtkPolyDataMapper()
mapper.SetInputConnection(surface.GetOutputPort())
mapper.ScalarVisibilityOff()

actor = vtkActor()
actor.SetMapper(mapper)
actor.GetProperty().SetColor(colors.GetColor3d('MistyRose'))

renderer.AddActor(actor)

render_window.Render()
interactor.Start()

This is my volume rendering:

在此处输入图片说明

This is my expected volume rendering:

在此处输入图片说明

Edit: My array is originally from a DICOM file but I get an error when I try to read it using VTK which is why I'm reading it using pydicom into a numpy array and then converting it to a VTK Image object. Could it be that I lose some spacing information when I do this? Any help would be appreciated.

Numpy uses a different array ordering than VTK. You should be able to re-order w, h and d to get the right thing.

This is how you want it:

h, d, w = ArrayDicom.shape

OK, here's a conversion script that I used to convert to a VTK file:

import numpy as np
import SimpleITK as sitk

x = np.load("test3.npy")
y = sitk.GetImageFromArray(x)
sitk.WriteImage(y, "test3.vtk")

It's not as nice as correctly getting the VTK image import to work, but, well, I'm a SimpleITK guy, and I know that converting numpy works in SimpleITK.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM