1.基本图形操作意义
图形处理,比如图形平滑、多分辨率分析、特征提取等都离不开一些基本的图形操作。掌握这些基本的图形操作有助于理解和深入学习图形处理和分析方法。
VTK中提供了多种图形的基本操作,其中最简单的是点的欧氏距离计算,可以使用vtkMath进行计算,也可以直接计算向量的模。一些图元类提供了许多可以方便使用的静态函数,如
vtkLine提供了点与线间的距离计算;
vtkTriangle提供了面积、外接圆、法向量的计算,点与三角形位置关系判断等;
vtkTetra中实现了四面体体积,重心计算等。
有了这些函数,可以实现很多其他功能,如计算一个三角网格模型的表面积,只需要遍历每个三角形单元并计算其面积即可。
另外,还有一个办法是vtkMassProperties。这个类可以实现三角网格的表面积和体积计算,但是要求网格必须是封闭的三角形网格数据。网格的封闭性计算在后面会有更加详细的讨论。对于非三角形网格,需要先将网格转换为三角形网格。vtkTriangleFilter可以实现多边形网格数据向三角形网格数据转换。
2.三角网格模型面积、体积计算
利用vtkMassProperties计算三角网格模型面积、体积代码如下:
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkSmartPointer.h>
#include <vtkCubeSource.h>
#include <vtkTriangleFilter.h> //其他网格类型转换成三角网格类型
#include <vtkMassProperties.h> //计算三角网格的基本属性 面积。体积等
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
int main()
{
vtkSmartPointer<vtkCubeSource> cubeSource =
vtkSmartPointer<vtkCubeSource>::New(); //vtkPolyData类型数据
cubeSource->Update();
vtkSmartPointer<vtkTriangleFilter> triFilter =
vtkSmartPointer<vtkTriangleFilter>::New();
triFilter->SetInputData(cubeSource->GetOutput());
triFilter->Update();
vtkSmartPointer<vtkMassProperties> massProp =
vtkSmartPointer<vtkMassProperties>::New();
massProp->SetInputData(triFilter->GetOutput());
float Volume = massProp->GetVolume();
float SurfaceArea = massProp->GetSurfaceArea();
float maxArea = massProp->GetMaxCellArea();
float minArea = massProp->GetMinCellArea();
std::cout << "the Volume : " << Volume << std::endl;
std::cout << "Surface Area : " << SurfaceArea << std::endl;
std::cout << "MaxAreaofCell: " << maxArea << std::endl;
std::cout << "MinAreaofCell: " << minArea << std::endl;
///
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(triFilter->GetOutput());
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetColor(0, 0, 1);
actor->GetProperty()->SetEdgeColor(1, 0, 0);
actor->GetProperty()->SetEdgeVisibility(1);
vtkSmartPointer<vtkRenderer> render =
vtkSmartPointer<vtkRenderer>::New();
render->AddActor(actor);
render->SetBackground(0, 0, 0);
vtkSmartPointer<vtkRenderWindow> rw =
vtkSmartPointer<vtkRenderWindow>::New();
rw->AddRenderer(render);
rw->SetSize(480, 420);
rw->SetWindowName("Calculating Area and Volume of Triangle grid");
vtkSmartPointer<vtkRenderWindowInteractor> rwi =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
rwi->SetRenderWindow(rw);
rwi->Initialize();
rwi->Start();
return 0;
}
其输出结果为:
3.三维网格测地距离
对于三维网格模型来讲,测地距离也是一种重要的距离度量。与欧氏距离不同,一个三维模型上的亮点测地距离是指沿着模型表面两者之间的最短距离。测地距离通常采用Dijkstra算法类近似求解。VTK中的vtkDijkstraGraphGeodesicPath类就可以实现测地距离的求解。该类的使用如下例所示:
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkDijkstraGraphGeodesicPath.h>
#include <vtkProperty.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
int main()
{
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
sphereSource->Update();
vtkSmartPointer<vtkDijkstraGraphGeodesicPath> dijstra =
vtkSmartPointer<vtkDijkstraGraphGeodesicPath>::New();
dijstra->SetInputData(sphereSource->GetOutput());
dijstra->SetStartVertex(0);
dijstra->SetEndVertex(10);
dijstra->Update();
///
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(sphereSource->GetOutput());
vtkSmartPointer<vtkPolyDataMapper> pathMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
pathMapper->SetInputData(dijstra->GetOutput());
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
vtkSmartPointer<vtkActor> pathActor =
vtkSmartPointer<vtkActor>::New();
pathActor->SetMapper(pathMapper);
pathActor->GetProperty()->SetColor(1, 0, 0);
pathActor->GetProperty()->SetLineWidth(5);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(actor);
renderer->AddActor(pathActor);
renderer->SetBackground(0, 0, 0);
vtkSmartPointer<vtkRenderWindow> rw =
vtkSmartPointer<vtkRenderWindow>::New();
rw->AddRenderer(renderer);
rw->SetSize(640, 480);
rw->SetWindowName("Calculating Geodesic Path");
vtkSmartPointer<vtkRenderWindowInteractor> rwi =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
rwi->SetRenderWindow(rw);
rwi->Initialize();
rwi->Start();
return 0;
}
在这个例子中,我们定义了一个球形。计算测地距离时,必须指定球面两个点的索引号。SetStartVertex()设置开始点;SetEndVertex()设置结束点;计算完毕后,通过GetOutPut()函数可以得到一个vtkPolyData数据,即最短路径数据,其实质为折线段集合。最终结果,如下图所示:
3.三维图像的包围盒
包围盒是指能够包围模型的最小立方体,常常用于模型的碰撞测量中。vtkPolyData中定义了函数GetBounds()来获取包围盒的参数。即三个坐标轴方向上的最大、最小值。仅仅获取这些参数并不直观,有时候还需要显示包围盒。vtkOutlineFilter则提供了一个方便的方法来生成包围盒,其输入为一个vtkPolyData莫形数据,输出同样为一个vtkPolyData类型数据,因此非常容易进行可视化显示。
实例的参考代码如下所示:
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkProperty.h>
#include <vtkOutlineFilter.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
int main()
{
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
sphereSource->SetCenter(0.0, 0.0, 0.0);
sphereSource->SetRadius(5.0);
sphereSource->Update();
vtkPolyData* sphere = sphereSource->GetOutput();
vtkSmartPointer<vtkOutlineFilter> outline =
vtkSmartPointer<vtkOutlineFilter>::New();
outline->SetInputData(sphere);
outline->Update();//算法执行完毕,必须更新!!!
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(sphere);
vtkSmartPointer<vtkPolyDataMapper> outlineMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
outlineMapper->SetInputData(outline->GetOutput());
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
vtkSmartPointer<vtkActor> outlineActor =
vtkSmartPointer<vtkActor>::New();
outlineActor->SetMapper(outlineMapper);
outlineActor->GetProperty()->SetColor(0, 1, 0);
outlineActor->GetProperty()->SetLineWidth(3);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(actor);
renderer->AddActor(outlineActor);
renderer->SetBackground(0, 0, 0);
vtkSmartPointer<vtkRenderWindow> rw =
vtkSmartPointer<vtkRenderWindow>::New();
rw->AddRenderer(renderer);
rw->SetSize(640, 480);;
rw->SetWindowName("PolyData Bounding Box");
rw->Render();
vtkSmartPointer<vtkRenderWindowInteractor> rwi =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
rwi->SetRenderWindow(rw);
rwi->Start();
return 0;
}
其输出结果如下图所示:
4.参看资料
1.《C++ primer》
2.《The VTK User’s Guide – 11thEdition》
3. 张晓东, 罗火灵. VTK图形图像开发进阶[M]. 机械工业出版社, 2015.