基于vtkPolydata的多高程温度分布切片绘制优化
问题描述
我有一份vtkPolydata数据,包含网格顶点的3D坐标,以及存储为点场数据的各点Temperature值。我想要绘制不同高程处的温度分布,已经构建了处理管线并获取到了所需切片,但渲染后显示的是散点图(放大后存在空白区域)。我觉得需要通过插值或创建等高线来解决,但查了很久资料都没头绪,求帮助。
用户提供的原始代码:
import vtk from vtk.util import numpy_support import numpy as np # Load vtkPolydata function def loadvtp(fname): reader = vtk.vtkXMLPolyDataReader() reader.SetFileName(fname) reader.Update() data=reader.GetOutput() return data # Load vtkPolydata polydata=loadvtp("TestPolydata.vtp") # Set the elevation at which data need to be plotted ele=12 # %% Clip polydata based on the elevation # Create plane in +Z to cut the polydata below elevation plane = vtk.vtkPlane() plane.SetOrigin(0, 0, ele) plane.SetNormal(0, 0, 1) # create polydata clipper clipper = vtk.vtkClipPolyData() clipper.SetInputData(polydata) clipper.SetClipFunction(plane) clipper.Update() out_data=clipper.GetOutput() # Create plane in -Z to cut the polydata above elevation plane = vtk.vtkPlane() plane.SetOrigin(0, 0, ele+0.5) plane.SetNormal(0, 0, -1) clipper = vtk.vtkClipPolyData() clipper.SetInputData(out_data) clipper.SetClipFunction(plane) clipper.Update() # Cliped polydata sampled_data=clipper.GetOutput() # Get the "Temperature" Array from the polydata point_scalars = sampled_data.GetPointData().GetArray("Temperature") # Create a lookup table to map the point field data to colors lut = vtk.vtkLookupTable() lut.SetNumberOfTableValues(2) lut.SetTableValue(0, 1, 0, 0, 1) # red lut.SetTableValue(1, 0, 1, 0, 1) # green lut.Build() # Create a mapper and actor to display the cliped plane mapper = vtk.vtkPolyDataMapper() mapper.SetInputConnection(clipper.GetOutputPort()) mapper.SetScalarModeToUsePointFieldData() mapper.ScalarVisibilityOn() mapper.SetColorModeToMapScalars() mapper.SelectColorArray(0) mapper.SetLookupTable(lut) mapper.SetScalarRange(point_scalars.GetRange()) actor = vtk.vtkActor() actor.SetMapper(mapper) # Create the RenderWindow, Renderer colors = vtk.vtkNamedColors() ren1 = vtk.vtkRenderer() renWin = vtk.vtkRenderWindow() renWin.AddRenderer(ren1) iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(renWin) ren1.AddActor(actor) ren1.SetBackground(colors.GetColor3d('Gainsboro')) renWin.SetSize(650, 650) renWin.SetWindowName('Test') style = vtk.vtkInteractorStyleTrackballCamera() iren.SetInteractorStyle(style) ren1.TwoSidedLightingOff() ren1.ResetCamera() renWin.Render() iren.Start()
解决方案
问题核心是:直接渲染剪切后的离散点集,没有构建连续的网格面,导致呈现散点状。以下是两种可行的解决方法:
方案一:生成等高线(适合展示温度沿轮廓的分布)
直接基于原始数据在指定高程生成等高线,同时保留温度值映射:
import vtk from vtk.util import numpy_support import numpy as np def loadvtp(fname): reader = vtk.vtkXMLPolyDataReader() reader.SetFileName(fname) reader.Update() return reader.GetOutput() polydata = loadvtp("TestPolydata.vtp") ele = 12 # 生成指定高程的等高线(等值面) contour_filter = vtk.vtkContourFilter() contour_filter.SetInputData(polydata) contour_filter.SetValue(0, ele) # 0为索引,ele是目标Z轴高程 contour_filter.Update() # 获取等高线数据,自动继承原始点的Temperature字段 contour_data = contour_filter.GetOutput() # 创建渐变颜色映射表 lut = vtk.vtkLookupTable() lut.SetHueRange(0.0, 0.3) # 红到绿的渐变范围 lut.SetSaturationRange(1.0, 1.0) lut.SetValueRange(1.0, 1.0) lut.Build() # 设置映射器 mapper = vtk.vtkPolyDataMapper() mapper.SetInputData(contour_data) mapper.SetScalarModeToUsePointFieldData() mapper.SelectColorArray("Temperature") # 明确指定温度字段 mapper.SetLookupTable(lut) mapper.SetScalarRange(contour_data.GetPointData().GetArray("Temperature").GetRange()) actor = vtk.vtkActor() actor.SetMapper(mapper) # 渲染窗口配置 colors = vtk.vtkNamedColors() ren1 = vtk.vtkRenderer() renWin = vtk.vtkRenderWindow() renWin.AddRenderer(ren1) iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(renWin) ren1.AddActor(actor) ren1.SetBackground(colors.GetColor3d('Gainsboro')) renWin.SetSize(650, 650) renWin.SetWindowName(f'Temperature Contour at Z={ele}') style = vtk.vtkInteractorStyleTrackballCamera() iren.SetInteractorStyle(style) ren1.ResetCamera() renWin.Render() iren.Start()
方案二:构建插值曲面(解决空白区域,展示连续温度分布)
将切片点投影到XY平面,构建结构化网格后进行插值填充:
import vtk from vtk.util import numpy_support import numpy as np def loadvtp(fname): reader = vtk.vtkXMLPolyDataReader() reader.SetFileName(fname) reader.Update() return reader.GetOutput() polydata = loadvtp("TestPolydata.vtp") ele = 12 # 提取指定高程附近的点 plane = vtk.vtkPlane() plane.SetOrigin(0, 0, ele) plane.SetNormal(0, 0, 1) clipper = vtk.vtkClipPolyData() clipper.SetInputData(polydata) clipper.SetClipFunction(plane) clipper.Update() plane2 = vtk.vtkPlane() plane2.SetOrigin(0, 0, ele+0.5) plane2.SetNormal(0, 0, -1) clipper2 = vtk.vtkClipPolyData() clipper2.SetInputData(clipper.GetOutput()) clipper2.Update() sampled_data = clipper2.GetOutput() # 提取点坐标和温度数据 points = numpy_support.vtk_to_numpy(sampled_data.GetPoints().GetData()) temps = numpy_support.vtk_to_numpy(sampled_data.GetPointData().GetArray("Temperature")) # 构建XY平面的规则结构化网格 x_min, x_max = points[:,0].min(), points[:,0].max() y_min, y_max = points[:,1].min(), points[:,1].max() x_steps = 50 y_steps = 50 grid_x, grid_y = np.meshgrid(np.linspace(x_min, x_max, x_steps), np.linspace(y_min, y_max, y_steps)) grid_points = np.column_stack((grid_x.flatten(), grid_y.flatten(), np.full(x_steps*y_steps, ele))) # 创建vtk格式的网格点 vtk_grid_points = vtk.vtkPoints() vtk_grid_points.SetData(numpy_support.numpy_to_vtk(grid_points, deep=True)) # 构建结构化网格 structured_grid = vtk.vtkStructuredGrid() structured_grid.SetDimensions(x_steps, y_steps, 1) structured_grid.SetPoints(vtk_grid_points) # 线性插值填充温度数据 interpolator = vtk.vtkPointInterpolator() interpolator.SetInputData(structured_grid) interpolator.SetSourceData(sampled_data) interpolator.SetKernel(vtk.vtkLinearKernel()) interpolator.Update() # 设置颜色映射与渲染 lut = vtk.vtkLookupTable() lut.SetHueRange(0.0, 0.3) lut.Build() mapper = vtk.vtkStructuredGridMapper() mapper.SetInputData(interpolator.GetOutput()) mapper.SetScalarModeToUsePointFieldData() mapper.SelectColorArray("Temperature") mapper.SetLookupTable(lut) mapper.SetScalarRange(interpolator.GetOutput().GetPointData().GetArray("Temperature").GetRange()) actor = vtk.vtkActor() actor.SetMapper(mapper) # 渲染窗口配置 colors = vtk.vtkNamedColors() ren1 = vtk.vtkRenderer() renWin = vtk.vtkRenderWindow() renWin.AddRenderer(ren1) iren = vtk.vtkRenderWindowInteractor() iren.SetRenderWindow(renWin) ren1.AddActor(actor) ren1.SetBackground(colors.GetColor3d('Gainsboro')) renWin.SetSize(650, 650) renWin.SetWindowName(f'Interpolated Temperature Surface at Z={ele}') style = vtk.vtkInteractorStyleTrackballCamera() iren.SetInteractorStyle(style) ren1.ResetCamera() renWin.Render() iren.Start()
关键说明
- 方案一直接基于原始网格生成等高线,保留数据精度,适合展示温度沿轮廓的变化;
- 方案二通过插值生成连续曲面,彻底解决空白区域问题,适合查看整个切片的温度渐变;
- 两种方案都明确指定了
SelectColorArray("Temperature"),避免索引错误,同时优化了颜色映射表,让温度渐变更自然。
内容的提问来源于stack exchange,提问作者Jish
相关产品推荐
相关产品推荐

