使用vtkPolyDataEdgeConnectivityFilter时,如何直接获取区域生长后的边界边?
如何高效获取VTK区域增长后的边界边
问题描述
使用vtkPolyDataEdgeConnectivityFilter基于选定边分割网格,执行vtkSmallRegionGrow后,需要获取新区域的边界边以继续执行vtkLargeRegionGrow。目前通过Python手动遍历单元格和邻居提取边界边,执行时间过长,询问VTK是否有内置过滤器直接返回这些边。
环境:Python 3.12 + pyvista 0.44.1 + vtk 9.3.1
当前低效代码:
feature_edges = PolyData(mesh.points, lines=edges.reshape(-1)) f = vtkPolyDataEdgeConnectivityFilter() f.SetExtractionModeToAllRegions() f.SetColorRegions(True) f.SetInputData(mesh) f.BarrierEdgesOn() f.SetBarrierEdges(True) f.SetSourceData(feature_edges) f.Update() f.SetLargeRegionThreshold(sml_thr) f.GrowSmallRegionsOn() f.Update() # 手动提取边界边,效率低下 f.SetSourceData(newborders(mesh)) f.SetLargeRegionThreshold(lrg_thr) f.GrowLargeRegionsOn() f.Update() def newborders(mesh): edges = [] for i in range(mesh.n_cells): for j in range(len(mesh.cell_neighbors(i,'edges'))): if mesh['RegionId'][i] != mesh['RegionId'][mesh.cell_neighbors(i,'edges')[j]]: edge = np.intersect1d(mesh.get_cell(i).point_ids,mesh.get_cell(mesh.cell_neighbors(i,'edges')[j]).point_ids) edges.append([2 , edge[0], edge[1]]) return np.array(edges)
解决方案
可以使用VTK内置的vtkEdgeFlagFilter过滤器,它能基于单元格标量数组(此处为RegionId)高效标记并提取不同区域之间的边界边,完全替代手动遍历的低效逻辑。
优化步骤
- 执行完
vtkSmallRegionGrow后,获取包含更新后RegionId的输出网格。 - 用
vtkEdgeFlagFilter标记相邻单元格RegionId不同的边。 - 提取标记后的边界边,转换为PolyData格式作为后续操作的输入。
优化后的代码
import vtk import pyvista as pv import numpy as np # 原有分割与小区域增长逻辑 feature_edges = pv.PolyData(mesh.points, lines=edges.reshape(-1)) f = vtk.vtkPolyDataEdgeConnectivityFilter() f.SetExtractionModeToAllRegions() f.SetColorRegions(True) f.SetInputData(mesh) f.BarrierEdgesOn() f.SetBarrierEdges(True) f.SetSourceData(feature_edges) f.Update() f.SetLargeRegionThreshold(sml_thr) f.GrowSmallRegionsOn() f.Update() # 获取小区域增长后的网格 grown_mesh = pv.wrap(f.GetOutput()) # 用vtkEdgeFlagFilter标记区域边界边 edge_filter = vtk.vtkEdgeFlagFilter() edge_filter.SetInputData(grown_mesh) # 指定用于判断区域的单元格标量数组 edge_filter.SetInputArrayToProcess(0, 0, 0, vtk.vtkDataObject.FIELD_ASSOCIATION_CELLS, "RegionId") edge_filter.SetBoundaryEdges(True) edge_filter.Update() # 筛选并提取边界边 edge_output = edge_filter.GetOutput() edge_flags = edge_output.GetCellData().GetArray("EdgeFlags") border_edge_ids = [i for i in range(edge_output.GetNumberOfCells()) if edge_flags.GetValue(i) == 1] extractor = vtk.vtkExtractCells() extractor.SetInputData(edge_output) extractor.SetCellIds(vtk.vtkIdList.FromList(border_edge_ids)) extractor.Update() border_edges_polydata = pv.wrap(extractor.GetOutput()) # 继续执行大区域增长 f.SetSourceData(border_edges_polydata) f.SetLargeRegionThreshold(lrg_thr) f.GrowLargeRegionsOn() f.Update()
关键说明
vtkEdgeFlagFilter基于C++底层实现边的标记与筛选,避免了Python循环的性能开销,在处理大规模网格时效率提升显著。- 该过滤器会自动给边添加
EdgeFlags数组,值为1的边即为不同区域之间的边界边,直接提取即可。
内容的提问来源于stack exchange,提问作者Pietro Furlan
相关产品推荐
相关产品推荐

