Numpy uint8_t数组到vtkImageData

时间:2017-07-30 00:28:20

标签: python numpy vtk

我正在尝试拍摄一个或三个通道的2D图像,并使用vtkImageActor在VTK中显示它们。据我了解,可以通过在SetImageData上调用vtkImageActor并提供vtkImageData的实例来更新要显示的当前帧。

我已经设置了我的可视化工具,如下所示。但是,我不确定如何从numpy数组构建vtkImageData对象(这将在updateFrames方法中)。我的numpy数组的类型是np.uint8_t

我正在使用VTK8.0,Python 3.6和Numpy 1.13.1

class VTKStreamVisualiser:
    def __init__(self, displayRGB):
        self.__displayRGB = displayRGB
        self.__started = False

        #Setup window.
        self.__renderWindow = vtk.vtkRenderWindow()
        self.__renderWindowInteractor = vtk.vtkRenderWindowInteractor()
        self.__renderWindowInteractor.SetRenderWindow(self.__renderWindow)

        #To store renderers and actors.
        self.__renderers = []
        self.__actors = []

        #Initialise to None to check if ready when invoking start()
        self.__depthImageData = None
        self.__rgbImageData = None

        #Determine viewport ranges for depth and setup renderer.
        xMinDepth = 0.0
        xMaxDepth = 0.5 if displayRGB else 1.0
        yMin = 0.0
        yMax = 1.0
        self.__setupRenderer(xMinDepth, yMin, xMaxDepth, yMax)

        #Determine viewport ranges for rgb and setup renderer.
        if self.__displayRGB:
            xMinRGB = xMaxDepth
            xMaxRGB = 2.0 * xMinRGB
            self.__setupRenderer(xMinRGB, yMin, xMaxRGB, yMax)

    def __setupRenderer(self, xMin, yMin, xMax, yMax):
        #Setup renderer.
        self.__renderers.append(vtk.vtkRenderer())
        idx = len(self.__renderers) - 1
        self.__renderWindow.AddRenderer(self.__renderers[idx])
        self.__renderers[idx].SetViewport(xMin, yMin, xMax, yMax)
        self.__actors.append(vtk.vtkImageActor())
        self.__renderers[idx].AddActor(self.__actors[idx])
        self.__renderers[idx].ResetCamera()

    def start(self):
        self.__depthImageData is None or (self.__rgbImageData is None and self.__displayRGB):
            return None

        if self.__started:
            return

        self.__renderWindowInteractor.Initialize()
        self.__renderWindow.Render()
        self.__renderWindowInteractor.Start()
        self.__started = True

    def stop(self):
        if not self.__started:
            return

        self.__renderWindowInteractor.Stop()
        self.__renderWindow.Finalize()
        self.__renderWindowInteractor.TerminateApp()
        self.__started = False

    def updateFrames(self, depthFrame, rgbFrame=None):
        #Build vtkImageData here from the given numpy uint8_t arrays.
        pass

编辑:我意识到我可以手动复制数据,如演示here,使用Cython不会坏(假设我能够使用{在Cython中{1}},但最好直接使用numpy数组。

2 个答案:

答案 0 :(得分:3)

使用numpy_support库可以将numpy数组转换为vtk数据数组

from vtk.util import numpy_support

def updateFrames(self, depthFrame, rgbFrame=None):
   #Build vtkImageData here from the given numpy uint8_t arrays.
   self.__depthImageData = vtk.vtkImageData()
   depthArray = numpy_support.numpy_to_vtk(depthFrame.ravel(), deep=True, array_type=vtk.VTK_UNSIGNED_CHAR) 
   # .transpose(2, 0, 1) may be required depending on numpy array order see - https://github.com/quentan/Test_ImageData/blob/master/TestImageData.py

   __depthImageData.SetDimensions(depthFrame.shape)
  #assume 0,0 origin and 1,1 spacing.
   __depthImageData.SetSpacing([1,1])
   __depthImageData.SetOrigin([0,0])
   __depthImageData.GetPointData().SetScalars(depthArray)

应提供如何生成depthFrame作为起点的工作示例

答案 1 :(得分:2)

更完整的答案(概括为1-3个通道,不同的数据类型)。

import vtk
import numpy as np
from vtk.util import numpy_support

def numpy_array_as_vtk_image_data(source_numpy_array):
    """
    :param source_numpy_array: source array with 2-3 dimensions. If used, the third dimension represents the channel count.
    Note: Channels are flipped, i.e. source is assumed to be BGR instead of RGB (which works if you're using cv2.imread function to read three-channel images)
    Note: Assumes array value at [0,0] represents the upper-left pixel.
    :type source_numpy_array: np.ndarray
    :return: vtk-compatible image, if conversion is successful. Raises exception otherwise
    :rtype vtk.vtkImageData
    """

    if len(source_numpy_array.shape) > 2:
        channel_count = source_numpy_array.shape[2]
    else:
        channel_count = 1

    output_vtk_image = vtk.vtkImageData()
    output_vtk_image.SetDimensions(source_numpy_array.shape[1], source_numpy_array.shape[0], channel_count)

    vtk_type_by_numpy_type = {
        np.uint8: vtk.VTK_UNSIGNED_CHAR,
        np.uint16: vtk.VTK_UNSIGNED_SHORT,
        np.uint32: vtk.VTK_UNSIGNED_INT,
        np.uint64: vtk.VTK_UNSIGNED_LONG if vtk.VTK_SIZEOF_LONG == 64 else vtk.VTK_UNSIGNED_LONG_LONG,
        np.int8: vtk.VTK_CHAR,
        np.int16: vtk.VTK_SHORT,
        np.int32: vtk.VTK_INT,
        np.int64: vtk.VTK_LONG if vtk.VTK_SIZEOF_LONG == 64 else vtk.VTK_LONG_LONG,
        np.float32: vtk.VTK_FLOAT,
        np.float64: vtk.VTK_DOUBLE
    }
    vtk_datatype = vtk_type_by_numpy_type[source_numpy_array.dtype.type]

    source_numpy_array = np.flipud(source_numpy_array)

    # Note: don't flip (take out next two lines) if input is RGB.
    # Likewise, BGRA->RGBA would require a different reordering here.
    if channel_count > 1:
        source_numpy_array = np.flip(source_numpy_array, 2)

    depth_array = numpy_support.numpy_to_vtk(source_numpy_array.ravel(), deep=True, array_type = vtk_datatype)
    depth_array.SetNumberOfComponents(channel_count)
    output_vtk_image.SetSpacing([1, 1, 1])
    output_vtk_image.SetOrigin([-1, -1, -1])
    output_vtk_image.GetPointData().SetScalars(depth_array)

    output_vtk_image.Modified()
    return output_vtk_image