Python: using less RAM for rendering

Hi all.

I am using VTK Python in my application for point cloud visualization. I would like to be able to support rather big point clouds but, as I have noticed in my app, the high RAM usage does not make it possible. Of course, there is always some limit to what we can visualize, based on the available RAM of the PC, but I am talking about point clouds that I can freely visualize in some other software, even if not with very good performance.

I tried to make this MRE to observe the RAM usage:

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


def print_memory(stage: str):
    """Print memory usage of this process in MB."""
    process = psutil.Process(os.getpid())
    mem = process.memory_info().rss / (1024**2)
    print(f"[{stage}] RAM: {mem:.2f} MB")


def main():
    print_memory("Start")
    n_points = 100_000_000
    points = np.random.rand(n_points, 3).astype(np.float32)
    intensity = np.random.rand(n_points).astype(np.float32)
    rgb = (np.random.rand(n_points, 3) * 255).astype(np.uint8)

    print_memory("Generated NumPy arrays")

    vtk_points = vtk.vtkPoints()
    vtk_points.SetData(numpy_support.numpy_to_vtk(points, deep=False))
    vtk_intensity = numpy_support.numpy_to_vtk(intensity, deep=False)
    vtk_intensity.SetName("Intensity")
    vtk_rgb = numpy_support.numpy_to_vtk(rgb, deep=False)
    vtk_rgb.SetNumberOfComponents(3)
    vtk_rgb.SetName("RGB")

    print_memory("Converted NumPy -> VTK arrays")

    poly_data = vtk.vtkPolyData()
    poly_data.SetPoints(vtk_points)
    poly_data.GetPointData().AddArray(vtk_intensity)
    poly_data.GetPointData().SetScalars(vtk_rgb)

    print_memory("Created vtkPolyData")

    mapper = vtk.vtkOpenGLPointGaussianMapper()
    mapper.SetInputData(poly_data)
    mapper.EmissiveOff()
    mapper.SetScaleFactor(0.0)
    actor = vtk.vtkActor()
    actor.SetMapper(mapper)
    actor.GetProperty().SetPointSize(1)

    print_memory("Created mapper & actor")

    ren = vtk.vtkRenderer()
    renWin = vtk.vtkRenderWindow()
    renWin.AddRenderer(ren)
    iren = vtk.vtkRenderWindowInteractor()
    iren.SetRenderWindow(renWin)
    ren.AddActor(actor)
    ren.SetBackground(0.1, 0.1, 0.1)

    renWin.Render()
    print_memory("After first Render()")

    print("Press 'q' in render window to quit...")
    iren.Start()


if __name__ == "__main__":
    main()

So, what I see is A LOT of RAM usage for the rendering. Now, I understand that we cannot NOT use RAM at all :slight_smile: But it seems to consume more than 2x of the original data size.

  1. Is this expected?
  2. Can it be improved in any way? Am I just using VTK in some wrong way?

Thanks!

I’m definitely not the best person to answer this, since point rendering isn’t something I often do, but I’ll give it a shot.

In addition to the data in the VTK data objects, memory is also consumed by VTK mappers. This is usually in the form of shader programs and OpenGL buffer objects, i.e. data that is shared between main memory and the GPU. Sometimes these buffer objects can directly share a VTK data array with the GPU, but sometimes the data must be copied/reformatted to make it usable by OpenGL. And it isn’t possible to know exactly how a mapper is using the OpenGL buffer objects without reading and understanding the C++ code. So, for example, I can’t tell you whether vtkOpenGLGlyph3DMapper will use less memory than vtkOpenGLPointGaussianMapper.

Generally, VTK prioritizes speed over memory usage, and it can be difficult to write a VTK program that has a minimal memory footprint.