Converting Volumes to Meshes with VTK
Introduction
- VTK provides robust tools for generating meshes from volumes, including labelmaps and raw pixel data.
- FlyingEdges3D is a highly efficient algorithm for generating iso-surfaces from volumetric data.
- VTK supports advanced options for mesh optimization, including smoothing and decimation.
Solution to run conversion code automatically
To simplify and unify solutions used in our tutorials, we use Album, a tool for capturing and sharing specific software use cases in dedicated virtual environments.
Click the solution box next to this text and follow the displayed usage instructions to run the solution either from command line or graphical interface.
Conversion of 3D pixel datasets into meshes with VTK
visualization:pixel-volumes-to-meshes-vtk:0.2.0
This solution uses vtkFlyingEdges3D to generate meshes from pixel volumes, including optional smoothing and decimation of vertices, and can optionally display the result.
Tags: bioinformatics, neuroscience, data-analysis
Conversion of 3D pixel datasets into meshes with VTK
visualization:pixel-volumes-to-meshes-vtk:0.2.0
This solution uses vtkFlyingEdges3D to generate meshes from pixel volumes, including optional smoothing and decimation of vertices, and can optionally display the result.
Tags: bioinformatics, neuroscience, data-analysis
- License: MIT
- Solution creator(s): Deborah Schmidt
album install visualization:pixel-volumes-to-meshes-vtk:0.2.0
album run visualization:pixel-volumes-to-meshes-vtk:0.2.0
--input # (file): Path to the 3D TIFF file containing region data or to a folder containing 3D masks. [Default: ] [Required: Yes]
--output # (directory): Path to the place where the calculated meshes should be stored. [Default: ] [Required: Yes]
--detect_labelmap # (boolean): Process int type images as labelmaps. [Default: 1] [Required: No]
--contour_value # (float): In case continuous datasets are provided, this value can be set to generate meshes at a specific contour value. Otherwise it will be calculated between min and max of the dataset range. [Default: ] [Required: No]
--smoothing_iterations # (integer): Smoothing iterations, usually between 10 and 50. More iterations typically lead to smoother results. Set to 0 to skip smoothing. [Default: 5] [Required: No]
--smoothing_pass_band # (float): Smoothing pass band, determines the amount of smoothing. Lower values result in more smoothing. Usually between 0.0 and 2.0. [Default: 0.5] [Required: No]
--smoothing_feature_angle # (float): The feature angle is the angle between the normals of adjacent polygons. A smaller feature angle will preserve edges. Value in degrees. [Default: 50.0] [Required: No]
--decimate_percentage # (float): How much to decimate vertices after mesh generation (0-1, 0 means do not decimate). [Default: 0.5] [Required: No]
--preserve_topology # (boolean): Preserve topology during mesh decimation. [Default: 0] [Required: No]
--show_meshes # (boolean): Whether to display the generated mesh plots or not. [Default: 0] [Required: No]
--colormap # (string): Name of the matplotlib colormap to use for coloring meshes. [Default: viridis] [Required: No]
--exclude_zero # (boolean): Exclude 0 as a label when processing the volumes. [Default: 1] [Required: No]
Cite the following resources if you use this solution:
Dependencies
314 dependencies={'environment_file': """channels:
315 - conda-forge
316dependencies:
317 - python=3.9
318 - pandas=1.5.3
319 - matplotlib-base=3.7.0
320 - numpy=1.24.2
321 - vtk=9.2.6
322 - numpy-stl=3.0.1
323 - opencv=4.8.0
324 - pip
325 - pip:
326 - vtkplotlib==2.1.0
327 - imagecodecs
328 - tifffile==2023.9.26
329"""}
Volume conversion using vtkFlyingEdges3D
- Add zero border around dataset
- Load volumetric image using
vtkImageData
- Generate meshes using
vtkFlyingEdges3D
algorithm - Set threshold between foreground and background via
GenerateValues (int numContours, double rangeStart, double rangeEnd)
72 # pad the data to get closed meshes at the border of the image
73 data = np.pad(data, ((1, 1), (1, 1), (1, 1)), 'constant', constant_values=(0,))
74
75 # numpy array to vtk array to vtkImageData
76
77 depth, height, width = data.shape
78 imageData = vtk.vtkImageData()
79 imageData.SetDimensions(width, height, depth)
80 imageData.SetSpacing((1, 1, 1))
81
82 np_dtype = data.dtype
83 vtk_dtype = vtk.VTK_UNSIGNED_CHAR
84 if np_dtype == 'float32':
85 vtk_dtype = vtk.VTK_FLOAT
86 elif np_dtype == 'float64':
87 vtk_dtype = vtk.VTK_DOUBLE
88 elif np_dtype == 'uint8':
89 vtk_dtype = vtk.VTK_UNSIGNED_CHAR
90
91 vtk_array = numpy_support.numpy_to_vtk(num_array=data.ravel(order='C'), deep=True, array_type=vtk_dtype)
92 imageData.GetPointData().SetScalars(vtk_array)
93
94 # apply flying threshold algorithm to generate mesh from volume
95 discrete = vtk.vtkFlyingEdges3D()
96 discrete.SetInputData(imageData)
97 discrete.SetValue(1, contour)
98 discrete.Update()
99
100 next_input = discrete.GetOutput()
Smoothing
- Number of iterations: Controls how many smoothing passes are applied.
- Feature Edge Smoothing: Ensures that important edges are preserved while smoothing.
- Boundary Smoothing: Smooths out the mesh along the boundaries.
103 # apply smoothing
104 smoother = vtk.vtkWindowedSincPolyDataFilter()
105 smoother.SetInputData(next_input)
106 smoother.SetNumberOfIterations(smoothing_iterations)
107 smoother.BoundarySmoothingOn()
108 smoother.FeatureEdgeSmoothingOn()
109 smoother.SetFeatureAngle(smoothing_feature_angle)
110 smoother.SetPassBand(smoothing_pass_band)
111 smoother.NonManifoldSmoothingOn()
112 smoother.NormalizeCoordinatesOn()
113 smoother.Update()
114 next_input = smoother.GetOutput()
Decimate geometry
- Target Reduction: Defines the percentage reduction in the number of polygons (e.g., 0.5 for 50% reduction).
- Preserve Topology: Ensures that the overall shape and connectivity of the mesh are maintained during decimation.
117 # apply decimation of geometry
118 decimate = vtk.vtkDecimatePro()
119 decimate.SetInputData(next_input)
120 decimate.SetTargetReduction(decimate_percentage)
121 if preserve_topology:
122 decimate.PreserveTopologyOn()
123 decimate.Update()
124
125 next_input = decimate.GetOutput()
Write STL file
The final step in this process is to write the generated mesh to an STL file. STL files are widely used for 3D printing, simulations, and visualizations in tools like Blender.
155 # write binary STL file
156 writer = vtk.vtkSTLWriter()
157 writer.SetFileName(path)
158 writer.SetInputData(next_input)
159 writer.SetFileTypeToBinary()
160 writer.Write()