pythonvoxelpyvista

Mesh to filled voxel grid


I'm trying to work with voxels. I have a closed mesh object, but here I'll use the supplied example mesh. What I would like to do is convert the mesh to a filled voxel grid.

The below code takes a mesh and turns it into a voxel grid using pyvista, however internally the voxel grid is hollow.

import numpy as np
import pyvista as pv
from pyvista import examples

# Load a surface to voxelize
surface = examples.download_foot_bones()
surface

voxels = pv.voxelize(surface, density=surface.length / 500)
voxels.plot(opacity=1.00)

Is there a way to fill the internal hollows with cells? If not I assume there would be a numpy way to fill in the array and then convert that to a filled voxel grid?


Solution

  • I believe you are misled by the representation of the voxels. Since the voxels are tightly packed in the plot, you cannot see internal surfaces even with partial opacity. In other words, the voxelisation is already dense.

    We can extract the center of each cell in the voxelised grid, and notice that it's dense in the mesh:

    voxels.cell_centers().plot(render_points_as_spheres=True)
    

    (you might have to manually activate the scalars on the mesh to also get the colourmap).

    This produces something like this when zoomed in: close-up of plotted cell centers, densely occupying the mesh outline

    If the voxel mesh were hollow, we would only see spheres along the surface of the mesh. Instead we have densely packed points filling up the entire space.


    For more concrete proof, consider a voxelised tetrahedron:

    import pyvista as pv
    
    tetra = pv.voxelize(pv.Tetrahedron(), density=0.1)
    tetra.plot(scalars='vtkOriginalCellIds')
    

    plot of voxelized tetrahedron with tightly packed voxels

    Now if we run this (slow and undocumented) internal helper called atomize on it, it will shrink each voxel, allowing us to peek through them:

    from pyvista.demos.logo import atomize  # undocumented, don't rely on it
    
    atomized = atomize(tetra, scale=0.5)
    atomized.plot()
    

    plot of voxelized tetrahedron with shrunk cells, internal cells visible

    Especially moving the mesh around in 3d makes it obvious that all the internal voxels are there, they are merely obscured by the outermost voxels.