前言

  • vtkPolyData数据是一种广泛使用的vtk数据结构,可以用来表示很多常用的数据结构,如点云数据、面片模型等。本文章先分析vtkPolyData数据的基本组成,创建方法和显示管线,结果介绍了一些基本操作,如距离、面积、包围盒、法向量以及符号化等。这些都是高级图像图像处理,此外还着中分析了图形平滑、封闭性检测、连通性分析、多分辨率处理、表面重建、点云配准、纹理映射等内容。掌握这些内容便可以解决许多实际性的工程问题。

  • 详细内容参见《VTK 图形图像开发进阶》第六章。该书得下载地址如下:

    链接:https://pan.baidu.com/s/1hG9js6eZkTqL6Fh-b_C-Dg
    提取码:cod8

    vtkPolyData数据生成与显示

  • vtkPolyData数据由几何结构数据、拓扑结构数据和属性数据组成。几何结构数据主要是组成模型的点集,拓扑结构数据是点按一定关系组成的单元数据,属性数据与几何结构数据和拓扑结构数据想关联,可以标量、向量、张量,可以用来间接表示图像的颜色。

    • GetNumberOfPoints()GetNumberOfCells()可以分别获取图形的点数和单元数目;
    • vtkPolyData数据显示时需要定义vtkPolyDataMapper对象,用来接受vtkPolyData数据以实现图形数据到渲染图元的转换。

      VTK常见的vtkPolyData数据源类

      VTK常见的vtkPolyData数据源类

      vtkPolyData数据的创建

  • 需要先定义一个点集和一个单元集合,单元的类型可以是点、三角形、矩形、多边形等基本图形。只有定义了单元数据才能显示该图形数据。

  • 具体创建代码见6.1.2节。

    vtkPolyData属性数据

  • 图形的颜色与vtkPolyData属性数据息息相关,可为点数据和单元数据分别指定属性数据。

  • 点和单元属性数据分别存储咋vtkPointDatavtkCellData中,可以通过调用GetCellData()函数获取一个vtkCellData类型单元数据指针,在通过SetScalars()函数设置颜色数据。

  • 由于可以同时设置点和单元设置属性,那么怎么用点和单元来控制颜色呢?这就需要使用vtkPolyDataMapper类的方法。

    • SetScalarModeToDefault(),默认设置,该设置下首先使用点的标量数据控制颜色,若点标量数据不可用时,则使用单元数据。
    • SetScalarModeToUsePointData(),使用点的标量数据控制颜色,若点标量数据不可用也不会使用其他数据。
    • SetScalarModeToUseCellData(),使用单元的标量数据控制颜色,若单元标量数据不可用也不会使用其他数据。
    • SetScalarModeToUsePointFieldData()/SetScalarModeToUseCellFieldData(),点数据和标量数据都不会用来着色,而是使用属性数据中场数据数组。可以通过名字来指定进行颜色渲染的数据。
  • 在某些情况下,需要对点属性数据和单元属性数据进行转换,这需要用到两个类vtkCellDataToPointDatavtkPointDataToCellData转换原理是:当由带属性向单元属性转换时,每个单元属性数据为组成该单元的点对应的属性的平均值;当单元属性数据向点属性数据转换时,点属性为使用该点的单元的属性平均值。

基本图形操作

  • VTK提供了多种基本图形操作:

    • vtkLine提供了点与线、线与线间的距离计算;
    • vtkTriangle提供了面积、外接圆、法向量的计算,点与三角形位置关系的判断;
    • vtkPolygen提供了法向量、重心、面积的计算、点与多边形位置的判断、点与多边形、多边形与多边形相交判断;
    • vtkTetra实现了四面体体积计算、重心计算;
    • vtkMassProperties实现三角网格的表面积和体积计算,但要求网格必须时封闭的三角网格;
    • vtkTriangleFilter可以实现多边形网格向三角网格转换。
  • 测地距离:三维模型上两个点的测地距离是指沿着模型表面两者之间的最短距离,通常采用Dijkstra算法近似求解,VTK中的vtkDijkstraGraphGeodesicPath类可实现测地距离求解。通过GetGeodesicLenght()函数可以获取当前计算的两点测地距离的数值。

  • 包围盒是指能够包围模型的最小立方体,常用于模型的碰撞检测中。vtkOutlineFilter提供一个方便的方法来生成包围盒。

法向量计算

  • 三维平面的法向量是指垂直该平面的向量。某点的法向量为垂直该点切平面的法向量。
  • 在计算网格法向量时,单元法向量可以通过组成每个单元的任意两条边的叉乘向量归并化来表示;二点的法向量则是由使用该点的单元单元法向量的平均值表示。
  • VTK中计算法向量的类为vtkPolyDataNormals,可以通过SetComputeCellNormals()SetComputePointNormals()来设置需要计算的法向量类型,默认计算点法向量。
  • 计算单元法向量时,要保持单元法向量一致才能得到合理的法向量。SetConsistency()可以自动调整单元点的顺序;SetAutoOrientNormals()可以自动调整法向量方向。
  • vtkPolyDataNormals自动开启对锐边缘处理,如果检测到锐边缘,会将其分裂,使图形更加平滑,可通过SetSplitting()函数关闭该功能。

    符号化Glyphing

  • 通过符号化(Glyphing)技术将法向量图形化显示。VTK中使用vtkGlyph3D类实现该功能,并支持图形缩放、着色、设置空间姿态等,需要接受两个输入:几何数据点集合、Glyph图形数据(vtkPolyData数据)。几何数据点集合来自求完法向量的图像,Glyph图形数据用于在点集合处显示法向量。

    曲率计算

  • 曲率时曲面弯曲程度的一种度量,是几何体的一种重要局部特征。计算曲面M点曲率,考虑经过M的法线的一个平面与曲面相交,可得到一条二维曲线,经过M的法线的平面可以有很多,与曲面相交时可得到多条曲线,取曲率最大和最小的曲线,若其对应曲率为k1和k2,称为主曲率,而该点的高斯曲率为k1*k2,平均曲率为:(k1+k2)/2。
  • VTK中vtkCurvatures类实现了4种网格模型曲率计算方法:
    • SetCurvatureTypeToMaximum():计算最大主曲率;
    • SetCurvatureTypeToMinimum():计算最小主曲率;
    • SetCurvatureTypeToGaussian():计算高斯曲率;
    • SetCurvatureTypeToMean():计算平均曲率。

网格平滑

  • 拉普拉斯平滑是一种网格平滑算法,将每个点用其邻域点的中心来代替,通过不断迭代,得到较为光滑的网格。
  • vtkSmoothPolyDataFilter类,实现了拉普拉斯平滑算法,用SetNumberOfIterations()控制平滑次数,次数越大,平滑越厉害。
    • BoundarySmoothing控制是否对边界点平滑;
    • FeatureEdgeSmoothing控制是否对特征边上的点平滑,通过调用SetFeatureAngle()函数设置特征角阈值。
  • vtkSmoothPolyDataFilter类通过拉普拉斯不断迭代,模型会不断向网格中心收缩。
  • vtkWindowedSincPolyDataFilter类,使用窗口函数Sinc实现网格平滑,能够最下程度避免收缩,使用方法与vtkSmoothPolyDataFilter类相同。

封闭性检测与填补漏洞

  • 如果一条边只被一个多边形包含,那这条边就是边界边,是否存在边界边是检测网格模型是否封闭的重要特征。

  • vtkFeatureEdges类能够提取多边形网格模型中4种类型的边:

    • 边界边;
    • 非流形边;
    • 特征边;
    • 流形边;
  • 可以通过判断边界边的数目来网格是否封闭。

  • 检测出网格是否封闭之后可以通过类vtkFillHoleFilter将漏洞填补起来。

连通区域分析

  • vtkAppendPolyData类可以实现vtkPolyData的合并,使用该类可以方便地构造含有多个连通区域的数据。
  • vtkPolyDataConnectivityFilter类用于实现连通区域分析
    • SetExtractionModeToLargestRegion():用于提取具有最多点的连通区域;
    • SetExtractionModeToAllRegion():用于连通区域标记,配合函数ColorRegionsOn()一起使用;
    • SetExtractionModeToSpecifiedRegion():用于提取一个或多个连通区域,需要通过AddSpecifiedRegion()来添加需要提取的边界号;

多分辨率处理

网格抽取

  • 抽取的作用是减少模型数据中的点数据和单元数据,便于后续处理和交互渲染。
  • VTK中有3种网格抽取类:
    • vtkDecimatePro:用一种塌陷的方法删除点和单元,处理速度快、可以方便的控制网格抽取幅度,得到不同级别的模型数据;
    • vtkQuadricDecimation:最终简化率并非严格等于程序中设置的简化率;
    • vtkQuadricClustering:3种模型中抽取速度最快的一种,能够处理大数据模型;

网格细化

  • 网格细化是利用一定的细化规则,在给定的初始网格中插入新的点,从而不断细化处新的网格单元,在极限细化情况下,该网格能够收敛于一个光滑的平面。

  • VTK中有3种网格细化类,如下,它们都继承自类vtkInterpolatingSubdivisionFilter,它内部提供了SetnumberOfSubdivisions()函数来设置细化次数,其中每次细化后模型的三角面片的个数将是细化前的4倍。

    • vtkLinearSubdivisionFilter:实现了一种线性细分算法;
    • vtkLoopSubdivisionFilter:实现了Loop细分算法,能够生成光滑连续曲面;
    • vtkButterSubdivisionFilter:实现了蝶形细分算法;
  • vtkLoopSubdivisionFiltervtkButterSubdivisionFilter结果优于vtkLinearSubdivisionFilter

表面重建

  • 利用表面重建技术将点云数据重建为面模型。

    三角剖分

  • 三角剖分将一些散乱的点云数据剖分为一系列三角网格,最常用的三角剖分技术是Delaunay三角剖分,主要用于二维三角剖分,三维数据通常使用点云重建。
  • vtkDelaunay2D类实现了2维三角剖分。
  • vtkDelaunay3D类实现了3维三角剖分。得到的结果并非三角网格,而是四面体网格,因此,其输出数据类型为vtkUnstructuredGrid.

等值面提取

  • 类似与面绘制,通过等值面提取提取技术,仅提取感兴趣的一个或者几个组织轮廓,并生成网格模型以供后续处理和显示。

  • 等值面提取算法多基于Marching Cubes算法实现:

    • vtkImageMarchingCubes主要处理三维图像数据;
    • vtkMarchingCubes主要针对规则体数据生成等值面;
    • vtkMarchingSquares针对二维规则网格数据生成等值线。
  • 通常需要搭配图形平滑、抽取等操作来对等值面数据进行后处理。

点云重建

  • vtkSurfaceReconstructionFilter实现了一种隐式曲面重建方法,该方法需要对点云数据进行网格划分,然后估算每个点的切平面方向,并以每个点与最近的切平面距离来近似表面距离。用vtkContourFilter来提取面距离来近似表面距离。

点云配准

  • 点云配准即是对一组原点云数据应用一个空间变换,使得变换后的数据与目标点云数据能够一一映射,使两组数据之间的平均距离误差最小。

  • vtkLandmarkTransform类实现了标记点配准算法,使得两个点集在配准后平均距离误差最小。通过SetSourceLandmarks()SetTargetLandmarks()函数分别设置源标记点集和目标标记点集。

    • SetModeToRigidBody():函数用于设置其配准变换的类型为刚体变换;
    • SetModeToAffine():设置其配准变换的类型为放射变换;
    • SetModeToSimilarity():设置相似变换,即平移、旋转和放缩变换。
  • vtkVertexGlyphFilter类显示点集;

  • vtkTransformPolyDataFilter用来对面源标记点进行变换来显示配准后的点集。

  • 点云数据配准最经典的方法是迭代最近点算法(ICP):每次迭代中对于源数据点P找到目标点集Q中的最近点,然后基于最小二乘原理求解当前的变换T。通过不断迭代直至收敛,即完成了点集的配准。

    • vtkIterativeClosesPointTransform类中内部定义了一个vtkLandmarkTransform指针,用于就算ICP迭代中最佳匹配点集,可以通过GetLandmarkTransform()函数获取,并通过vtkLandmarkTransform指针设置相应的变换类型。SetMaximumNumberOfIterations()函数用于设置ICP算法迭代次数,StartByMatchingCentroidsOn()函数则用于设置配准之前先计算两个点集重心,并平移源点集使得两者重心重合。配置完毕可以通过GetMatrix()函数来获取相应的变换矩阵。

纹理映射

  • 纹理映射是将纹理空间中的纹理像素映射到屏幕空间中的过程。主要是建立纹理空间与模型空间、模型空间与屏幕空间之间的映射关系。
  • VTK中定义了许多个类实现纹理空间到模型空间的映射:
    • vtkTextureMapToPlane:通过一个平面建立纹理空间到模型空间的映射关系;
    • vtkTextureMapToCylinder:通过圆柱面建立映射关系;
    • vtkTextureMapToSphere:通过球面建立映射关系;
    • vtkTexture:实现加载纹理;
    • vtkTransformTextureCoords:实现纹理坐标的平移和缩放;

推荐阅读: