- 利用vtkMassProperties计算三角网格模型面积、体积、最大单元面积和最小单元面积
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkSmartPointer.h>
#include <vtkPointData.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkScalarBarActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkPolyData.h>
#include <vtkCubeSource.h>
#include <vtkProperty.h>
#include <vtkTriangleFilter.h>
#include <vtkMassProperties.h>
int main(int argc, char* argv[])
{
//创建一个立方体网格数据
vtkSmartPointer<vtkCubeSource> cubeSource =
vtkSmartPointer<vtkCubeSource>::New();
cubeSource->Update();
//将数据进行三角化,转化为三角形构成的网格
vtkSmartPointer<vtkTriangleFilter> triFilter =
vtkSmartPointer<vtkTriangleFilter>::New();
triFilter->SetInputData(cubeSource->GetOutput());
triFilter->Update();
//vtkMassProperties用于计算三角化网格的质量属性 输入数据为三角化之后的数据
vtkSmartPointer<vtkMassProperties> massProp =
vtkSmartPointer<vtkMassProperties>::New();
massProp->SetInputData(triFilter->GetOutput());
//计算体积
float vol = massProp->GetVolume();
//计算表面积
float area = massProp->GetSurfaceArea();
//最大单元面积
float maxArea = massProp->GetMaxCellArea();
//最小单元面积
float minArea = massProp->GetMinCellArea();
std::cout << "Volume :" << vol << std::endl;
std::cout << "Surface Area:" << area << std::endl;
std::cout << "Max Area :" << maxArea << std::endl;
std::cout << "Min Area :" << minArea << std::endl;
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
//mapper->SetInput(cubeSource->GetOutput());
mapper->SetInputData(triFilter->GetOutput());
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->GetProperty()->SetColor(0, 1, 0);
//设置边缘的颜色 就是立方体的边
actor->GetProperty()->SetEdgeColor(1, 0, 0);
actor->GetProperty()->SetEdgeVisibility(1);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(actor);
renderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
renderWindow->SetSize(640, 480);
renderWindow->Render();
renderWindow->SetWindowName("PolyDataMassProperty");
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
测地距离:两个点沿着模型表面两者之间最短距离,使用vtkDijkstraGraphGeodesicPath类实现测地距离的计算
包围盒:vtkOutlineFilter提供一个方法来生成包围盒,输入是一个vtkPolyData模型数据,输出为vtkPolyData数据,只需要将其作为vtkPolyDataMapper的输入,建立可视化管线即可显示
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkSphereSource.h>
#include <vtkProperty.h>
#include <vtkPolyData.h>
#include <vtkSmartPointer.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkOutlineFilter.h>
#include <vtkDijkstraGraphGeodesicPath.h>
int main()
{
//定义一个球面模型,计算球面上两点的索引号
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
sphereSource->Update();
//vtkOutlineFilter的输入是一个vtkPolyData类型数据 需要转换一下
vtkPolyData* sphere = sphereSource->GetOutput();
vtkSmartPointer<vtkOutlineFilter> outline =
vtkSmartPointer<vtkOutlineFilter>::New();
outline->SetInputData(sphere);
outline->Update(); //!!!一定要更新数据,包围盒要不显示不出来
vtkSmartPointer<vtkDijkstraGraphGeodesicPath> dijkstra =
vtkSmartPointer<vtkDijkstraGraphGeodesicPath>::New();
dijkstra->SetInputData(sphereSource->GetOutput());
//设置开始点
dijkstra->SetStartVertex(0);
//结束点
dijkstra->SetEndVertex(10);
dijkstra->Update();
//建立可视化管线可以显示
vtkSmartPointer<vtkPolyDataMapper> pathMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
pathMapper->SetInputData(dijkstra->GetOutput());
vtkSmartPointer<vtkActor> pathActor =
vtkSmartPointer<vtkActor>::New();
pathActor->SetMapper(pathMapper);
pathActor->GetProperty()->SetColor(1, 0, 0);
pathActor->GetProperty()->SetLineWidth(4);
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(sphereSource->GetOutput());
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
vtkSmartPointer<vtkPolyDataMapper> spheremapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
spheremapper->SetInputData(outline->GetOutput());
vtkSmartPointer<vtkActor> sphereactor =
vtkSmartPointer<vtkActor>::New();
sphereactor->SetMapper(spheremapper);
sphereactor->GetProperty()->SetColor(1, 0, 0);
sphereactor->GetProperty()->SetLineWidth(4);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(actor);
renderer->AddActor(pathActor);
renderer->AddActor(sphereactor);
renderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
renderWindow->SetSize(640, 480);
renderWindow->Render();
renderWindow->SetWindowName("PolyDataGeodesic");
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
1.法向量计算和符号化Glyphing
- 三维平面的法向量:垂直于该平面的三维向量
- 曲面在某点P处的法向量:垂直与该点切平面的向量
- 格模型单元法向量:组成每个单元的任意两条边的叉乘向量并归一化
- 点的法向量:所有使用该点的单元法向量的平均值来表示
使用vtkPolyDataBNormals对单元为三角形或者多边形类型的vtkPolyData数据进行计算,由于法向量分为点法向量和单元法向量类型,可以通过函数SetComputeCellNormals()和SetcomputePointNormals()来设置需要计算的法向量类型,默认情况计算点法向量,关闭单元法向量
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkSmartPointer.h>
#include <vtkActor.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkPolyDataReader.h>
#include <vtkPLYReader.h>
#include <vtkFloatArray.h>
#include <vtkPointData.h>
#include <vtkPolyDataNormals.h>
#include <vtkGlyph3D.h>
#include <vtkArrowSource.h>
#include <vtkSphereSource.h>
#include <vtkMaskPoints.h>
#include <vtkProperty.h>
//测试文件:../data/fran_cut.vtk
int main(int argc, char* argv[])
{
vtkSmartPointer<vtkPolyDataReader> reader =
vtkSmartPointer<vtkPolyDataReader>::New();
reader->SetFileName("D:\\lqyWord\\VTK图形图像开发进阶随书代码\\Examples\\Chap06\\data\\fran_cut.vtk");
reader->Update();
vtkSmartPointer<vtkPolyDataNormals> normFilter =
vtkSmartPointer<vtkPolyDataNormals>::New();
normFilter->SetInputData(reader->GetOutput());
/****这里计算点法向量和单元法向量
**调用update()函数之后可生成一个vtkPolyData数据,
**生成的法向量数据存储在内部的vtkPointData和vtkCellData中*/
normFilter->SetComputePointNormals(1);
normFilter->SetComputeCellNormals(1);
/*会根据拓扑结构自动调整法向量的方向,
**确保法向量在给定表面元素中的指向正确。
**将参数设置为 1,则表示开启自动调整法向量方向*/
normFilter->SetAutoOrientNormals(1);
//关闭对锐边缘的处理 检测到锐边缘,会将其分裂,模型数据会发生变化
normFilter->SetSplitting(0);
normFilter->Update();
//保留输入数据中的点数据以及其属性
vtkSmartPointer<vtkMaskPoints> mask =
vtkSmartPointer<vtkMaskPoints>::New();
mask->SetInputData(normFilter->GetOutput());
//随机采样了300个点做显示
mask->SetMaximumNumberOfPoints(300);
mask->RandomModeOn();
mask->Update(); //!!!数据计算之后必须要进行更新,否则数据没有添加进来
//这样的效果输入数据的每一个点处会显示一个Gly图形
vtkSmartPointer<vtkArrowSource> arrow =
vtkSmartPointer<vtkArrowSource>::New();
arrow->Update();
vtkSmartPointer<vtkGlyph3D> glyph =
vtkSmartPointer<vtkGlyph3D>::New();
glyph->SetInputData(mask->GetOutput());
glyph->SetSourceData(arrow->GetOutput()); //显示效果会显示一个图形
//指定要使用法向量数据来控制Glyph图形的方向
glyph->SetVectorModeToUseNormal();
//控制Glyph图形大小
glyph->SetScaleFactor(0.01);
glyph->Update();
vtkSmartPointer<vtkPolyDataMapper> originMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
originMapper->SetInputData(reader->GetOutput());
vtkSmartPointer<vtkActor> originActor =
vtkSmartPointer<vtkActor>::New();
originActor->SetMapper(originMapper);
vtkSmartPointer<vtkPolyDataMapper> normedMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
normedMapper->SetInputData(normFilter->GetOutput());
vtkSmartPointer<vtkActor> normedActor =
vtkSmartPointer<vtkActor>::New();
normedActor->SetMapper(normedMapper);
vtkSmartPointer<vtkPolyDataMapper> glyphMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
glyphMapper->SetInputData(glyph->GetOutput());
vtkSmartPointer<vtkActor> glyphActor =
vtkSmartPointer<vtkActor>::New();
glyphActor->SetMapper(glyphMapper);
glyphActor->GetProperty()->SetColor(1., 0., 0.);
double originalViewport[4] = { 0.0, 0.0, 0.33, 1.0 };
double normViewport[4] = { 0.33, 0.0, 0.66, 1.0 };
double glphViewport[4] = { 0.66, 0.0, 1.0, 1.0 };
vtkSmartPointer<vtkRenderer> originalRenderer =
vtkSmartPointer<vtkRenderer>::New();
originalRenderer->SetViewport(originalViewport);
originalRenderer->AddActor(originActor);
originalRenderer->ResetCamera();
originalRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderer> normedRenderer =
vtkSmartPointer<vtkRenderer>::New();
normedRenderer->SetViewport(normViewport);
normedRenderer->AddActor(normedActor);
normedRenderer->ResetCamera();
normedRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderer> glyphRenderer =
vtkSmartPointer<vtkRenderer>::New();
glyphRenderer->SetViewport(glphViewport);
glyphRenderer->AddActor(glyphActor);
glyphRenderer->AddActor(normedActor);
glyphRenderer->ResetCamera();
glyphRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(originalRenderer);
renderWindow->AddRenderer(normedRenderer);
renderWindow->AddRenderer(glyphRenderer);
renderWindow->SetSize(640, 320);
renderWindow->Render();
renderWindow->SetWindowName("PolyDataNormal");
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindowInteractor->Initialize();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
实验效果:
2.曲率计算
取最大曲率和最小曲率的两条法截线为主法截线k1,k2,高斯曲率=主曲率的乘积(k1叉乘k2),平均曲率=主曲率的平均值(k1+k2)/2
vtk中vtkCurvatures类接受一个vtkPolyData数据,将计算得到的曲率数据作为网格模型的点的属性数据存入返回的vtkPolyData中
使用vtkScalarBarActor类头文件,将一个颜色映射表转换为一个Actor对象,将颜色表以图形的形式显示
头文件要加上VTK_MODULE_INIT(vtkRenderingFreeType),要不会报错
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType)
#include <vtkSmartPointer.h>
#include <vtkCurvatures.h>
#include <vtkPolyDataReader.h>
#include <vtkLookupTable.h>
#include <vtkColorTransferFunction.h>
#include <vtkColorSeries.h>
#include <vtkPointData.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkScalarBarActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <iostream>
using namespace std;
//测试文件:../data/fran_cut.vtk
int main(int argc, char* argv[])
{
//读入一个vtkPolyData数据 作为vtkCurvatures的输入
vtkSmartPointer<vtkPolyDataReader> reader =
vtkSmartPointer<vtkPolyDataReader>::New();
reader->SetFileName("D:\\lqyWord\\VTK图形图像开发进阶随书代码\\Examples\\Chap06\\data\\fran_cut.vtk");
reader->Update();
vtkSmartPointer<vtkCurvatures> curvaturesFilter =
vtkSmartPointer<vtkCurvatures>::New();
curvaturesFilter->SetInputConnection(reader->GetOutputPort());
//最小曲率
//curvaturesFilter->SetCurvatureTypeToMinimum();
//SetCurvatureTypeToMaximum计算最大曲率
curvaturesFilter->SetCurvatureTypeToMaximum();
//高斯曲率
//curvaturesFilter->SetCurvatureTypeToGaussian();
// //平均曲率
//curvaturesFilter->SetCurvatureTypeToMean();
curvaturesFilter->Update();
//将curvaturesFilter的数据存储到scalarRange数组中
double scalarRange[2];
//获取曲率的最大值和最小值
curvaturesFilter->GetOutput()->GetScalarRange(scalarRange);
vtkSmartPointer<vtkLookupTable> lut =
vtkSmartPointer<vtkLookupTable>::New();
//颜色的色调范围,从红色到黄绿色的过度
lut->SetHueRange(0.0, 0.6);
//透明度范围 设置为1 表示不透明
lut->SetAlphaRange(1.0, 1.0);
//颜色的饱和度范围 1最大值
lut->SetValueRange(1.0, 1.0);
lut->SetSaturationRange(1.0, 1.0);
//颜色表的条目数 256
lut->SetNumberOfTableValues(256);
//将数据设置为颜色表的范围
lut->SetRange(scalarRange);
lut->Build();
//将数据用颜色表显示出来
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputData(curvaturesFilter->GetOutput());
//颜色表设置
mapper->SetLookupTable(lut);
//标量范围设置为scalarRange
mapper->SetScalarRange(scalarRange);
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
//显示一个颜色表 vtkScalarBarActor将一个颜色映射表转化为一个Actor对象,将颜色表以图形的形式显示
vtkSmartPointer<vtkScalarBarActor> scalarBar =
vtkSmartPointer<vtkScalarBarActor>::New();
//设置颜色表
scalarBar->SetLookupTable(mapper->GetLookupTable());
//标量条的标题设置为数据集中数据数组的名称
scalarBar->SetTitle(
curvaturesFilter->GetOutput()->GetPointData()->GetScalars()->GetName());
//设置标量条的标签数量
scalarBar->SetNumberOfLabels(5);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(actor);
renderer->AddActor2D(scalarBar);
renderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
renderWindow->SetSize(640, 480);
renderWindow->Render();
renderWindow->SetWindowName("PolyDataCurvature");
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
3.网格平滑
拉普拉斯平滑:每个点用其邻域点的中心来代替,通过不断地迭代,凯源得到较为光滑的网格
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType)
#include <vtkSmartPointer.h>
#include <vtkPolyDataReader.h>
#include <vtkPolyData.h>
#include <vtkSmoothPolyDataFilter.h>
#include <vtkWindowedSincPolyDataFilter.h>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
//测试文件:../data/fran_cut.vtk
int main(int argc, char* argv[])
{
vtkSmartPointer<vtkPolyDataReader> reader =
vtkSmartPointer<vtkPolyDataReader>::New();
reader->SetFileName("D:\\lqyWord\\VTK图形图像开发进阶随书代码\\Examples\\Chap06\\data\\fran_cut.vtk");
reader->Update();
vtkSmartPointer<vtkSmoothPolyDataFilter> smoothFilter =
vtkSmartPointer<vtkSmoothPolyDataFilter>::New();
smoothFilter->SetInputConnection(reader->GetOutputPort());
//控制平滑次数 平滑的同时会损失一些细节信息
smoothFilter->SetNumberOfIterations(200);
smoothFilter->Update();
vtkSmartPointer<vtkPolyDataMapper> inputMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
inputMapper->SetInputConnection(reader->GetOutputPort());
vtkSmartPointer<vtkActor> inputActor =
vtkSmartPointer<vtkActor>::New();
inputActor->SetMapper(inputMapper);
vtkSmartPointer<vtkPolyDataMapper> smoothedMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
smoothedMapper->SetInputConnection(smoothFilter->GetOutputPort());
vtkSmartPointer<vtkActor> smoothedActor =
vtkSmartPointer<vtkActor>::New();
smoothedActor->SetMapper(smoothedMapper);
double leftViewport[4] = { 0.0, 0.0, 0.5, 1.0 };
double rightViewport[4] = { 0.5, 0.0, 1.0, 1.0 };
vtkSmartPointer<vtkRenderer> leftRenderer =
vtkSmartPointer<vtkRenderer>::New();
leftRenderer->SetViewport(leftViewport);
leftRenderer->AddActor(inputActor);
leftRenderer->SetBackground(0.8, 0.8, 0.8);
leftRenderer->ResetCamera();
vtkSmartPointer<vtkRenderer> rightRenderer =
vtkSmartPointer<vtkRenderer>::New();
rightRenderer->SetViewport(rightViewport);
rightRenderer->AddActor(smoothedActor);
rightRenderer->SetBackground(0.8, 0.8, 0.8);
rightRenderer->SetActiveCamera(leftRenderer->GetActiveCamera());
rightRenderer->ResetCamera();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(leftRenderer);
renderWindow->AddRenderer(rightRenderer);
renderWindow->SetSize(640, 320);
renderWindow->Render();
renderWindow->SetWindowName("PolyDataLapLasianSmooth");
vtkSmartPointer<vtkRenderWindowInteractor> interactor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow(renderWindow);
renderWindow->Render();
interactor->Start();
return EXIT_SUCCESS;
}
4. 封闭性检测
边界边:如果一条边只被一个多边形包含,那么这条边就是边界边,是否存在边界边是检测一个网络模型是否封闭的重要特征
vtkFeatureEdges类的BoundaryEdgesOn()函数提取边界边
类vtkFillHolesFilter填补空洞:首先检测出网格中所有的边界边,然后找出这些边界边中的每一个闭合回路,最后将这个闭合回路进行三角化以实现填补的目的
vtkFillHolesFilter中的SetHloeSize()控制需要修补的漏洞的面积最大值,大于该值的漏洞不需要填补处理
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkSmartPointer.h>
#include <vtkSelectionNode.h>
#include <vtkInformation.h>
#include <vtkUnstructuredGrid.h>
#include <vtkPolyData.h>
#include <vtkPolyDataNormals.h>
#include <vtkPointData.h>
#include <vtkXMLPolyDataReader.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSelection.h>
#include <vtkSelectionNode.h>
#include <vtkSphereSource.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkProperty.h>
#include <vtkIdTypeArray.h>
#include <vtkExtractSelection.h>
#include <vtkDataSetSurfaceFilter.h>
#include <vtkFeatureEdges.h>
#include <vtkFillHolesFilter.h>
//提取出原球体数据集中指定单元的表面数据集
/*设置选择节点-->选择器-->从原始数据中提取选择器中的数据-->得到表面数据
*/
void GenerateData(vtkSmartPointer<vtkPolyData> input)
{
//定义一个球面网格
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
sphereSource->Update();
vtkSmartPointer<vtkIdTypeArray> ids =
vtkSmartPointer<vtkIdTypeArray>::New();
ids->SetNumberOfComponents(1);
ids->InsertNextValue(2);
ids->InsertNextValue(10);
//指定数据集中要选择那些单元或点的数据
vtkSmartPointer<vtkSelectionNode> selectionNode =
vtkSmartPointer<vtkSelectionNode>::New();
//选择的是单元
selectionNode->SetFieldType(vtkSelectionNode::CELL);
//表示通过指定的标识符选择
selectionNode->SetContentType(vtkSelectionNode::INDICES);
//设置选择单元的标识符
selectionNode->SetSelectionList(ids);
//表示选择非指定单元
selectionNode->GetProperties()->Set(vtkSelectionNode::INVERSE(), 1);
//选择器
vtkSmartPointer<vtkSelection> selection =
vtkSmartPointer<vtkSelection>::New();
selection->AddNode(selectionNode);
vtkSmartPointer<vtkExtractSelection> extractSelection =
vtkSmartPointer<vtkExtractSelection>::New();
extractSelection->SetInputData(0, sphereSource->GetOutput());
extractSelection->SetInputData(1, selection);
extractSelection->Update();
//vtkDataSetSurfaceFilter提取数据仍然保持原始数据的结构
vtkSmartPointer<vtkDataSetSurfaceFilter> surfaceFilter =
vtkSmartPointer<vtkDataSetSurfaceFilter>::New();
surfaceFilter->SetInputConnection(extractSelection->GetOutputPort());
surfaceFilter->Update();
input->ShallowCopy(surfaceFilter->GetOutput());
}
int main(int argc, char* argv[])
{
vtkSmartPointer<vtkPolyData> input =
vtkSmartPointer<vtkPolyData>::New();
GenerateData(input);
vtkSmartPointer<vtkFeatureEdges> featureEdges =
vtkSmartPointer<vtkFeatureEdges>::New();
featureEdges->SetInputData(input);
//设置提取边界边
featureEdges->BoundaryEdgesOn();
//特征边
featureEdges->FeatureEdgesOff();
//流形边
featureEdges->ManifoldEdgesOff();
//非流形边
featureEdges->NonManifoldEdgesOff();
featureEdges->Update();
//输出一个包含边信息的vtkPolyData数据,通过判断边界边的数目来确定网格是否封闭
int numberOfOpenEdges = featureEdges->GetOutput()->GetNumberOfCells();
if (numberOfOpenEdges)
{
std::cout << "该网格模型不是封闭的..." << std::endl;
}
else
{
std::cout << "该网格模型是封闭的..." << std::endl;
return EXIT_SUCCESS;
}
//填补空洞
vtkSmartPointer<vtkFillHolesFilter> fillHolesFilter =
vtkSmartPointer<vtkFillHolesFilter>::New();
fillHolesFilter->SetInputData(input);
fillHolesFilter->Update();
//漏洞填充,模型的所有单元的点顺序不一致,使用ConsistencyOn进行调整
vtkSmartPointer<vtkPolyDataNormals> normals =
vtkSmartPointer<vtkPolyDataNormals>::New();
normals->SetInputConnection(fillHolesFilter->GetOutputPort());
normals->ConsistencyOn();
normals->SplittingOff();
normals->Update();
double leftViewport[4] = { 0.0, 0.0, 0.5, 1.0 };
double rightViewport[4] = { 0.5, 0.0, 1.0, 1.0 };
vtkSmartPointer<vtkPolyDataMapper> originalMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
originalMapper->SetInputData(input);
//设置一个属性 漫射颜色
vtkSmartPointer<vtkProperty> backfaceProp =
vtkSmartPointer<vtkProperty>::New();
backfaceProp->SetDiffuseColor(1.0, 1.0, 0.34);
vtkSmartPointer<vtkActor> originalActor =
vtkSmartPointer<vtkActor>::New();
originalActor->SetMapper(originalMapper);
//设置背面属性
originalActor->SetBackfaceProperty(backfaceProp);
//设置正面的视觉表现
originalActor->GetProperty()->SetDiffuseColor(1.0, 0.3882, 0.2784);
//边界边的显示设置
vtkSmartPointer<vtkPolyDataMapper> edgeMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
edgeMapper->SetInputData(featureEdges->GetOutput());
vtkSmartPointer<vtkActor> edgeActor =
vtkSmartPointer<vtkActor>::New();
edgeActor->SetMapper(edgeMapper);
edgeActor->GetProperty()->SetEdgeColor(0., 0., 1.0);
edgeActor->GetProperty()->SetEdgeVisibility(1);
edgeActor->GetProperty()->SetLineWidth(5);
vtkSmartPointer<vtkPolyDataMapper> filledMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
filledMapper->SetInputData(normals->GetOutput());
//填补之后的图形显示
vtkSmartPointer<vtkActor> filledActor =
vtkSmartPointer<vtkActor>::New();
filledActor->SetMapper(filledMapper);
//filledActor->GetProperty()->SetDiffuseColor(1.0, 0.3882, 0.2784);
filledActor->GetProperty()->SetDiffuseColor(1.0, 1.0, 0);
vtkSmartPointer<vtkRenderer> leftRenderer =
vtkSmartPointer<vtkRenderer>::New();
leftRenderer->SetViewport(leftViewport);
leftRenderer->AddActor(originalActor);
leftRenderer->AddActor(edgeActor);
leftRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderer> rightRenderer =
vtkSmartPointer<vtkRenderer>::New();
rightRenderer->SetViewport(rightViewport);
rightRenderer->AddActor(filledActor);
rightRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(leftRenderer);
renderWindow->AddRenderer(rightRenderer);
renderWindow->SetSize(640, 320);
renderWindow->Render();
renderWindow->SetWindowName("PolyDataClosed");
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
//设置左视图相机的位置、焦点、视线方向和视角
leftRenderer->GetActiveCamera()->SetPosition(0, -1, 0);
leftRenderer->GetActiveCamera()->SetFocalPoint(0, 0, 0);
leftRenderer->GetActiveCamera()->SetViewUp(0, 0, 1);
leftRenderer->GetActiveCamera()->Azimuth(30);
leftRenderer->GetActiveCamera()->Elevation(30);
leftRenderer->ResetCamera();
//右侧渲染器的相机设置为左侧渲染器的相机
rightRenderer->SetActiveCamera(leftRenderer->GetActiveCamera());
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
5. 连通区域分析
vtkAppendPolyData类可以实现vtkPolyData数据的合并,可以方便地构造含有多个连通区域的数据,接受两个或者多个vtkPolyData数据输入,合并结果包含输入数据的所有几何和拓扑数据
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkSmartPointer.h>
#include <vtkSphereSource.h>
#include <vtkConeSource.h>
#include <vtkPolyDataConnectivityFilter.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkProperty.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkAppendPolyData.h>
int main(int, char* [])
{
//定义一个球面数据
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
sphereSource->SetRadius(10);
//设置球面的经线和纬线的数量 ,可以控制球体的光滑程度
sphereSource->SetThetaResolution(10);
sphereSource->SetPhiResolution(10);
sphereSource->Update();
//定义一个锥形数据
vtkSmartPointer<vtkConeSource> coneSource =
vtkSmartPointer<vtkConeSource>::New();
coneSource->SetRadius(5);
coneSource->SetHeight(10);
coneSource->SetCenter(25, 0, 0);
coneSource->Update();
//将两个多边形数据合成一个多边形数据
//输入俩个数据 生成一个包含两个对象的vtkPolyData数据 每一个输入模型为一个连通区域
vtkSmartPointer<vtkAppendPolyData> appendFilter =
vtkSmartPointer<vtkAppendPolyData>::New();
appendFilter->AddInputData(sphereSource->GetOutput());
appendFilter->AddInputData(coneSource->GetOutput());
appendFilter->Update();
/*从appendFilter中提取最多点的连通区域*/
vtkSmartPointer<vtkPolyDataConnectivityFilter> connectivityFilter =
vtkSmartPointer<vtkPolyDataConnectivityFilter>::New();
connectivityFilter->SetInputData(appendFilter->GetOutput());
//SetExtractionModeToCellSeededRegions用于提取具有最多点的连通区域
//在本例中是球面数据
connectivityFilter->SetExtractionModeToCellSeededRegions();
connectivityFilter->AddSeed(100);
connectivityFilter->Update();
vtkSmartPointer<vtkPolyDataMapper> originalMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
originalMapper->SetInputConnection(appendFilter->GetOutputPort());
originalMapper->Update();
vtkSmartPointer<vtkActor> originalActor =
vtkSmartPointer<vtkActor>::New();
originalActor->SetMapper(originalMapper);
vtkSmartPointer<vtkPolyDataMapper> extractedMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
extractedMapper->SetInputConnection(connectivityFilter->GetOutputPort());
extractedMapper->Update();
vtkSmartPointer<vtkActor> extractedActor =
vtkSmartPointer<vtkActor>::New();
extractedActor->SetMapper(extractedMapper);
double leftViewport[4] = { 0.0, 0.0, 0.5, 1.0 };
double rightViewport[4] = { 0.5, 0.0, 1.0, 1.0 };
vtkSmartPointer<vtkRenderer> leftRenderer =
vtkSmartPointer<vtkRenderer>::New();
leftRenderer->SetViewport(leftViewport);
leftRenderer->AddActor(originalActor);
leftRenderer->SetBackground(0.8, 0.8, 0.8);
vtkSmartPointer<vtkRenderer> rightRenderer =
vtkSmartPointer<vtkRenderer>::New();
rightRenderer->SetViewport(rightViewport);
rightRenderer->AddActor(extractedActor);
rightRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(leftRenderer);
renderWindow->AddRenderer(rightRenderer);
renderWindow->SetSize(640, 320);
renderWindow->Render();
renderWindow->SetWindowName("PolyDataConnectedCompExtract");
leftRenderer->ResetCamera();
rightRenderer->SetActiveCamera(leftRenderer->GetActiveCamera());
vtkSmartPointer<vtkRenderWindowInteractor> interactor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow(renderWindow);
interactor->Initialize();
interactor->Start();
return EXIT_SUCCESS;
}
6 多分辨率处理
6.1 模型抽取
模型抽取:减少模型数据中的点数据和单元数据,便于模型的后续处理和交换渲染(类似图像数据的降采样)
网格细化:利用一定的细化规则,在给定的初始网格中插入新的点,从而不断细化新的网格单元,在极限细化情况下,该网格能够收敛于一个光滑曲面
vtkDecimatePro是最常用的网格提取类,利用边塌陷的方法删除点和单元,处理速度比较快,可以方便控制网格提取的幅度,得到不同级别的模型数据
需要满足四个条件:
1.vtkDecimatePro需要支持模型拓扑的改变,将PreserveTopology变量的值设置为FALSE
2.支持网格分类,即Splitting变量的值设置为TRUE
3.支持修改模型的边界,即将变量BoundaryVertexDeletion的值设置为TRUE
4.设置最大误差变量MaximumError的值为VTK_DOUBLE_MAX
网格抽取类接收的是vtkPolyData的三角网格数据,如果vtkPolyData数据为多边形网格数据,需要先通过vtkTriangleFilter将多边形网格数据转化为三角网格数据
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkPolyData.h>
#include <vtkSphereSource.h>
#include <vtkDecimatePro.h>
#include <vtkQuadricDecimation.h>
#include <vtkQuadricClustering.h>
#include <vtkSmartPointer.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkPolydataReader.h>
#include <vtkCamera.h>
//测试文件:../data/fran_cut.vtk
int main(int argc, char* argv[])
{
vtkSmartPointer<vtkPolyDataReader> reader =
vtkSmartPointer<vtkPolyDataReader>::New();
reader->SetFileName("D:\\lqyWord\\VTK图形图像开发进阶随书代码\\Examples\\Chap06\\data\\fran_cut.vtk");
reader->Update();
vtkSmartPointer<vtkPolyData> original = reader->GetOutput();
std::cout << "抽取前:" << std::endl << "------------" << std::endl;
std::cout << "模型点数为: " << original->GetNumberOfPoints() << std::endl;
std::cout << "模型面数为: " << original->GetNumberOfPolys() << std::endl;
//vtkDecimatePro接收一个单元为三角网络的vtkPolyData数据
vtkSmartPointer<vtkDecimatePro> decimate =
vtkSmartPointer<vtkDecimatePro>::New();
decimate->SetInputData(original);
//设置面片移除的比例(0-1),说明有8%的三角面片要被移除
decimate->SetTargetReduction(.80);
decimate->Update();
vtkSmartPointer<vtkPolyData> decimated = decimate->GetOutput();
std::cout << "抽取后" << std::endl << "------------" << std::endl;
std::cout << "模型点数为:" << decimated->GetNumberOfPoints() << std::endl;
std::cout << "模型面数为:" << decimated->GetNumberOfPolys() << std::endl;
vtkSmartPointer<vtkPolyDataMapper> origianlMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
origianlMapper->SetInputData(original);
vtkSmartPointer<vtkActor> origianlActor =
vtkSmartPointer<vtkActor>::New();
origianlActor->SetMapper(origianlMapper);
vtkSmartPointer<vtkPolyDataMapper> decimatedMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
decimatedMapper->SetInputData(decimated);
vtkSmartPointer<vtkActor> decimatedActor =
vtkSmartPointer<vtkActor>::New();
decimatedActor->SetMapper(decimatedMapper);
double leftViewport[4] = { 0.0, 0.0, 0.5, 1.0 };
double rightViewport[4] = { 0.5, 0.0, 1.0, 1.0 };
vtkSmartPointer<vtkRenderer> leftRenderer =
vtkSmartPointer<vtkRenderer>::New();
leftRenderer->SetViewport(leftViewport);
leftRenderer->AddActor(origianlActor);
leftRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderer> rightRenderer =
vtkSmartPointer<vtkRenderer>::New();
rightRenderer->SetViewport(rightViewport);
rightRenderer->AddActor(decimatedActor);
rightRenderer->SetBackground(1.0, 1.0, 1.0);
leftRenderer->GetActiveCamera()->SetPosition(0, -1, 0);
leftRenderer->GetActiveCamera()->SetFocalPoint(0, 0, 0);
leftRenderer->GetActiveCamera()->SetViewUp(0, 0, 1);
leftRenderer->GetActiveCamera()->Azimuth(30);
leftRenderer->GetActiveCamera()->Elevation(30);
leftRenderer->ResetCamera();
rightRenderer->SetActiveCamera(leftRenderer->GetActiveCamera());
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(leftRenderer);
renderWindow->AddRenderer(rightRenderer);
renderWindow->SetSize(640, 320);
renderWindow->Render();
renderWindow->SetWindowName("PolyDataDecimation");
vtkSmartPointer<vtkRenderWindowInteractor> interactor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow(renderWindow);
renderWindow->Render();
interactor->Start();
return EXIT_SUCCESS;
}
6.2网格细化
- 模型细化只对三角网络数据有效,在处理多边形数据时,需要通过vtkTriangleFilter将多边形数据转化为三角网格数据
- 实现网格细化的类有vtkLinearSubdivisionFilter、vtkLoopSubdivisionFilter、vtkButterflySubdivisionFilter,这三类都继承自vtkInterpolatingSubdivisionFilter。
- vtkInterpolatingSubdivisionFilter内部提供了SetNumberOfSubdivisions()函数来设置细化的次数,其中每次细化后模型的三角面片的个数将是细化前的4倍,所以,在对网络模型进行n次细分后,该模型的面片个数是原始模型面片数目的4n倍
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkSmartPointer.h>
#include <vtkCellData.h>
#include <vtkCellArray.h>
#include <vtkDoubleArray.h>
#include <vtkPoints.h>
#include <vtkTriangle.h>
#include <vtkPolyData.h>
#include <vtkPointData.h>
#include <vtkSphereSource.h>
#include <vtkTriangleFilter.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkButterflySubdivisionFilter.h>
#include <vtkLoopSubdivisionFilter.h>
#include <vtkLinearSubdivisionFilter.h>
#include <string>
int main(int argc, char* argv[])
{
vtkSmartPointer<vtkPolyData> originalMesh;
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
sphereSource->Update();
originalMesh = sphereSource->GetOutput();
double numberOfViewports = 3;
int numberOfSubdivisions = 2;
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->SetSize(200 * numberOfViewports, 200);
renderWindow->SetWindowName("Multiple ViewPorts");
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
for (unsigned i = 0; i < numberOfViewports; i++)
{
//定义一个基类指针 这样就可以将任意一个子类的指针赋值给该变量
vtkSmartPointer<vtkPolyDataAlgorithm> subdivisionFilter;
switch (i)
{
case 0:
subdivisionFilter = vtkSmartPointer<vtkLinearSubdivisionFilter>::New();
dynamic_cast<vtkLinearSubdivisionFilter*> (subdivisionFilter.GetPointer())->SetNumberOfSubdivisions(numberOfSubdivisions);
break;
case 1:
subdivisionFilter = vtkSmartPointer<vtkLoopSubdivisionFilter>::New();
dynamic_cast<vtkLoopSubdivisionFilter*> (subdivisionFilter.GetPointer())->SetNumberOfSubdivisions(numberOfSubdivisions);
break;
case 2:
subdivisionFilter = vtkSmartPointer<vtkButterflySubdivisionFilter>::New();
dynamic_cast<vtkButterflySubdivisionFilter*> (subdivisionFilter.GetPointer())->SetNumberOfSubdivisions(numberOfSubdivisions);
break;
default:
break;
}
//设置好细化次数之后 传入原始数据
subdivisionFilter->SetInputData(originalMesh);
subdivisionFilter->Update();
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderWindow->AddRenderer(renderer);
renderer->SetViewport(static_cast<double>(i) / numberOfViewports, 0, static_cast<double>(i + 1) / numberOfViewports, 1);
renderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(subdivisionFilter->GetOutputPort());
vtkSmartPointer<vtkActor> actor = vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
renderer->AddActor(actor);
renderer->ResetCamera();
}
renderWindow->SetSize(640, 320);
renderWindow->Render();
renderWindow->SetWindowName("PolyDataSubdivision");
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
7.表面重建
7.1三角剖分
Delaunay三角剖分:在所有的三角剖分中,所生成的三角形的最小角的角度最大(无论从哪个区域开始构建,最终生成的三角网格都是唯一的)
vtkDelaunay2D实现二维的三角剖分,输入为vtkPolyData点数据
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkSmartPointer.h>
#include <vtkProperty.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPointData.h>
#include <vtkDelaunay2D.h>
#include <vtkMath.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkVertexGlyphFilter.h>
#include <vtkPolyDataReader.h>
int main(int, char* [])
{
unsigned int gridSize = 10;
vtkSmartPointer<vtkPoints> points =
vtkSmartPointer<vtkPoints>::New();
for (unsigned int x = 0; x < gridSize; x++)
{
for (unsigned int y = 0; y < gridSize; y++)
{
points->InsertNextPoint(x, y, vtkMath::Random(0.0, 3.0));
}
}
//定义一个点集
vtkSmartPointer<vtkPolyData> polydata =
vtkSmartPointer<vtkPolyData>::New();
polydata->SetPoints(points);
vtkSmartPointer<vtkDelaunay2D> delaunay =
vtkSmartPointer<vtkDelaunay2D>::New();
delaunay->SetInputData(polydata);
delaunay->Update();
//在点数据上生成图元数据 就是将点数据显示出来
vtkSmartPointer<vtkVertexGlyphFilter> glyphFilter =
vtkSmartPointer<vtkVertexGlyphFilter>::New();
glyphFilter->SetInputData(polydata);
glyphFilter->Update();
vtkSmartPointer<vtkPolyDataMapper> pointsMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
pointsMapper->SetInputData(glyphFilter->GetOutput());
vtkSmartPointer<vtkActor> pointsActor =
vtkSmartPointer<vtkActor>::New();
pointsActor->SetMapper(pointsMapper);
pointsActor->GetProperty()->SetPointSize(3);
pointsActor->GetProperty()->SetColor(1, 0, 0);
vtkSmartPointer<vtkPolyDataMapper> triangulatedMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
triangulatedMapper->SetInputData(delaunay->GetOutput());
vtkSmartPointer<vtkActor> triangulatedActor =
vtkSmartPointer<vtkActor>::New();
triangulatedActor->SetMapper(triangulatedMapper);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
//renderer->AddActor(pointsActor);
renderer->AddActor(triangulatedActor);
renderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindow->SetSize(640, 320);
renderWindow->Render();
renderWindow->SetWindowName("PolyDataDelaunay2D");
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
vtkDelaunay2D还支持加入边界限制。用户可以设置另一个vtkPolyData数据,其内部的线段、闭合或者非闭合的线段集合将作为边界条件控制三角剖分的过程,其中组成这些边界的点的索引必须与原始点集数据一致
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkSmartPointer.h>
#include <vtkProperty.h>
#include <vtkPolygon.h>
#include <vtkCellArray.h>
#include <vtkPoints.h>
#include <vtkPolyData.h>
#include <vtkPointData.h>
#include <vtkDelaunay2D.h>
#include <vtkMath.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkVertexGlyphFilter.h>
int main(int, char* [])
{
vtkSmartPointer<vtkPoints> points =
vtkSmartPointer<vtkPoints>::New();
unsigned int gridSize = 10;
for (unsigned int x = 0; x < gridSize; x++)
{
for (unsigned int y = 0; y < gridSize; y++)
{
points->InsertNextPoint(x, y, vtkMath::Random(0.0, 3.0));
}
}
vtkSmartPointer<vtkPolyData> polydata =
vtkSmartPointer<vtkPolyData>::New();
polydata->SetPoints(points);
vtkSmartPointer<vtkPolygon> poly =
vtkSmartPointer<vtkPolygon>::New();
poly->GetPointIds()->InsertNextId(22);
poly->GetPointIds()->InsertNextId(23);
poly->GetPointIds()->InsertNextId(24);
poly->GetPointIds()->InsertNextId(25);
poly->GetPointIds()->InsertNextId(35);
poly->GetPointIds()->InsertNextId(45);
poly->GetPointIds()->InsertNextId(44);
poly->GetPointIds()->InsertNextId(43);
poly->GetPointIds()->InsertNextId(42);
poly->GetPointIds()->InsertNextId(32);
/*poly->GetPointIds()->InsertNextId(32);
poly->GetPointIds()->InsertNextId(42);
poly->GetPointIds()->InsertNextId(43);
poly->GetPointIds()->InsertNextId(44);
poly->GetPointIds()->InsertNextId(45);
poly->GetPointIds()->InsertNextId(35);
poly->GetPointIds()->InsertNextId(25);
poly->GetPointIds()->InsertNextId(24);
poly->GetPointIds()->InsertNextId(23);
poly->GetPointIds()->InsertNextId(22);*/
vtkSmartPointer<vtkCellArray> cell =
vtkSmartPointer<vtkCellArray>::New();
cell->InsertNextCell(poly);
//加入一个多边形边界来限制三角剖分
vtkSmartPointer<vtkPolyData> boundary =
vtkSmartPointer<vtkPolyData>::New();
boundary->SetPoints(points);
boundary->SetPolys(cell);
vtkSmartPointer<vtkDelaunay2D> delaunay =
vtkSmartPointer<vtkDelaunay2D>::New();
delaunay->SetInputData(polydata);
//设置边界数据
delaunay->SetSourceData(boundary);
delaunay->Update();
vtkSmartPointer<vtkVertexGlyphFilter> glyphFilter =
vtkSmartPointer<vtkVertexGlyphFilter>::New();
glyphFilter->SetInputData(polydata);
glyphFilter->Update();
vtkSmartPointer<vtkPolyDataMapper> pointsMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
pointsMapper->SetInputData(glyphFilter->GetOutput());
vtkSmartPointer<vtkActor> pointsActor =
vtkSmartPointer<vtkActor>::New();
pointsActor->SetMapper(pointsMapper);
pointsActor->GetProperty()->SetPointSize(3);
pointsActor->GetProperty()->SetColor(1, 0, 0);
vtkSmartPointer<vtkPolyDataMapper> triangulatedMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
triangulatedMapper->SetInputData(delaunay->GetOutput());
vtkSmartPointer<vtkActor> triangulatedActor =
vtkSmartPointer<vtkActor>::New();
triangulatedActor->SetMapper(triangulatedMapper);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(pointsActor);
renderer->AddActor(triangulatedActor);
renderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindow->SetSize(640, 480);
renderWindow->Render();
renderWindow->SetWindowName("PolyDataConstrainedDelaunay2D");
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
7.2 等值面提取
vtkImageMarchingCubes主要处理三维图像处理
vtkMarchingCubes主要针对规则体数据生成等值面
vtkMarchingSquares针对二维规格网格数据生成等值线
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkSmartPointer.h>
#include <vtkMarchingCubes.h>
#include <vtkContourFilter.h>
#include <vtkVoxelModeller.h>
#include <vtkSphereSource.h>
#include <vtkImageData.h>
#include <vtkMetaImageReader.h>
#include <vtkInteractorStyleImage.h>
#include <vtkActor.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkImageActor.h>
#include <vtkProperty.h>
//测试:../data/HeadMRVolume.mhd 200
int main(int argc, char* argv[])
{
vtkSmartPointer<vtkMetaImageReader> reader =
vtkSmartPointer<vtkMetaImageReader>::New();
reader->SetFileName("D:\\lqyWord\\VTK图形图像开发进阶随书代码\\Examples\\Chap06\\data\\brain.mhd");
reader->Update();
double isoValue = 200;
/*vtkSmartPointer<vtkMarchingCubes> surface =
vtkSmartPointer<vtkMarchingCubes>::New();
surface->SetInputData(reader->GetOutput());
surface->ComputeNormalsOn();
//设置等值面的值 第一个参数是等值面的序号
//因此可以设置多个等值面数值来提取多个等值面
surface->SetValue(0, isoValue);*/
//surface->GenerateValues(5, 150,200);
vtkSmartPointer<vtkContourFilter> surface =
vtkSmartPointer<vtkContourFilter>::New();
surface->SetInputData(reader->GetOutput());
//计算等值面的法向量
surface->ComputeNormalsOn();
surface->SetValue(1, isoValue);
vtkSmartPointer<vtkPolyDataMapper> surfMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
surfMapper->SetInputConnection(surface->GetOutputPort());
surfMapper->ScalarVisibilityOn();
vtkSmartPointer<vtkActor> surfActor =
vtkSmartPointer<vtkActor>::New();
surfActor->SetMapper(surfMapper);
surfActor->GetProperty()->SetColor(1.0, 0.0, 0.0);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(surfActor);
renderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
renderWindow->SetSize(640, 480);
renderWindow->Render();
renderWindow->SetWindowName("PolyDataMarchingCubes");
renderWindow->Render();
vtkSmartPointer<vtkRenderWindowInteractor> interactor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow(renderWindow);
renderWindow->Render();
interactor->Start();
return EXIT_SUCCESS;
}
7.3 点云重建
Delaunay三角剖分算法可以实现网格曲面重建,但是主要运用在二维剖分,在三维空间网格生成中遇到问题,不仅基于最大最小角判断的对角线交换准则不在成立,而且基于外接圆判断的Delaunay三角化也不能保证网格质量
vtkSurfaceReconstructionFilter实现一种隐式曲面重建的方法
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
#include <vtkSmartPointer.h>
#include <vtkSurfaceReconstructionFilter.h>
#include <vtkProgrammableSource.h>
#include <vtkContourFilter.h>
#include <vtkReverseSense.h>
#include <vtkPolyDataMapper.h>
#include <vtkProperty.h>
#include <vtkPolyData.h>
#include <vtkCamera.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkCamera.h>
#include <vtkPolydataReader.h>
#include <vtkVertexGlyphFilter.h>
#include <vtkLookupTable.h>
//测试文件:../data/fran_cut.vtk
int main(int argc, char* argv[])
{
vtkSmartPointer<vtkPolyDataReader> reader =
vtkSmartPointer<vtkPolyDataReader>::New();
reader->SetFileName("through_cloud_filtered.vtk");
reader->Update();
vtkSmartPointer<vtkPolyData> points =
vtkSmartPointer<vtkPolyData>::New();
points->SetPoints(reader->GetOutput()->GetPoints());
vtkSmartPointer<vtkSurfaceReconstructionFilter> surf =
vtkSmartPointer<vtkSurfaceReconstructionFilter>::New();
surf->SetInputData(points);
//SetNeighborhoodSize用于设置邻域点的个数,而这些邻域点用于估计每个点的局部切平面
//个数设置越大,计算时间越长,当点分布不均匀时,可以增加该值
surf->SetNeighborhoodSize(35);
//SetSampleSpacing()用于设置划分网格的网格间距,间距越小,网格越密集
surf->SetSampleSpacing(1.5);
surf->Update();
vtkSmartPointer<vtkContourFilter> contour =
vtkSmartPointer<vtkContourFilter>::New();
contour->SetInputConnection(surf->GetOutputPort());
contour->SetValue(0, 0.0);
contour->Update();
double leftViewport[4] = { 0.0, 0.0, 0.5, 1.0 };
double rightViewport[4] = { 0.5, 0.0, 1.0, 1.0 };
vtkSmartPointer<vtkVertexGlyphFilter> vertexGlyphFilter =
vtkSmartPointer<vtkVertexGlyphFilter>::New();
vertexGlyphFilter->AddInputData(points);
vertexGlyphFilter->Update();
vtkSmartPointer<vtkPolyDataMapper> vertexMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
vertexMapper->SetInputData(vertexGlyphFilter->GetOutput());
vertexMapper->ScalarVisibilityOff();
vtkSmartPointer<vtkActor> vertexActor =
vtkSmartPointer<vtkActor>::New();
vertexActor->SetMapper(vertexMapper);
vertexActor->GetProperty()->SetColor(0.625, 0.625, 0.625);
vertexActor->GetProperty()->SetPointSize(4);
vtkSmartPointer<vtkRenderer> vertexRenderer =
vtkSmartPointer<vtkRenderer>::New();
vertexRenderer->AddActor(vertexActor);
vertexRenderer->SetViewport(leftViewport);
vertexRenderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkPolyDataMapper> surfMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
surfMapper->SetInputData(contour->GetOutput());
surfMapper->ScalarVisibilityOff();
vtkSmartPointer<vtkActor> surfActor =
vtkSmartPointer<vtkActor>::New();
surfActor->SetMapper(surfMapper);
surfActor->GetProperty()->SetColor(0.625, 0.625, 0.625);
vtkSmartPointer<vtkRenderer> surfRenderer =
vtkSmartPointer<vtkRenderer>::New();
surfRenderer->AddActor(surfActor);
surfRenderer->SetViewport(rightViewport);
surfRenderer->SetBackground(1.0, 1.0, 1.0);
//surfRenderer->SetActiveCamera(vertexRenderer->GetActiveCamera());
vtkSmartPointer<vtkRenderWindow> renWin =
vtkSmartPointer<vtkRenderWindow>::New();
renWin->AddRenderer(surfRenderer);
renWin->AddRenderer(vertexRenderer);
renWin->SetSize(640, 320);
renWin->Render();
renWin->SetWindowName("PolyDataSurfaceReconstruction");
vtkSmartPointer<vtkRenderWindowInteractor> iren =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
iren->SetRenderWindow(renWin);
renWin->Render();
iren->Start();
return EXIT_SUCCESS;
}
8.点云配准
点云配准:对测量点云数据进行局部配准和整合得到完整的模型数据,对一组源点云数据应用一个空间变换,使得变换后的数据与目标点云能够一一映射,使得两组数据之间的平均距离误差最小
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
#include <vtkPoints.h>
#include <vtkSmartPointer.h>
#include <vtkLandmarkTransform.h>
#include <vtkMatrix4x4.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkTransformPolyDataFilter.h>
#include <vtkVertexGlyphFilter.h>
#include <vtkAxesActor.h>
int main(int, char* [])
{
//定义源标记点集
vtkSmartPointer<vtkPoints> sourcePoints =
vtkSmartPointer<vtkPoints>::New();
double sourcePoint1[3] = { 0.5, 0.0, 0.0 };
sourcePoints->InsertNextPoint(sourcePoint1);
double sourcePoint2[3] = { 0.0, 0.5, 0.0 };
sourcePoints->InsertNextPoint(sourcePoint2);
double sourcePoint3[3] = { 0.0, 0.0, 0.5 };
sourcePoints->InsertNextPoint(sourcePoint3);
//定义目标标记点集
vtkSmartPointer<vtkPoints> targetPoints =
vtkSmartPointer<vtkPoints>::New();
double targetPoint1[3] = { 0.0, 0.0, 0.55 };
targetPoints->InsertNextPoint(targetPoint1);
double targetPoint2[3] = { 0.0, 0.55, 0.0 };
targetPoints->InsertNextPoint(targetPoint2);
double targetPoint3[3] = { -0.55, 0.0, 0.0 };
targetPoints->InsertNextPoint(targetPoint3);
vtkSmartPointer<vtkLandmarkTransform> landmarkTransform =
vtkSmartPointer<vtkLandmarkTransform>::New();
landmarkTransform->SetSourceLandmarks(sourcePoints);
landmarkTransform->SetTargetLandmarks(targetPoints);
//设置匹配变换的类型为刚体变换,旋转和平移
landmarkTransform->SetModeToRigidBody();
//SetModeToSimilarity()相似变换,旋转平移和放缩变换
//SetModeToAffine()放射变换
landmarkTransform->Update();
vtkSmartPointer<vtkPolyData> source =
vtkSmartPointer<vtkPolyData>::New();
source->SetPoints(sourcePoints);
vtkSmartPointer<vtkPolyData> target =
vtkSmartPointer<vtkPolyData>::New();
target->SetPoints(targetPoints);
vtkSmartPointer<vtkVertexGlyphFilter> sourceGlyphFilter =
vtkSmartPointer<vtkVertexGlyphFilter>::New();
sourceGlyphFilter->SetInputData(source);
sourceGlyphFilter->Update();
vtkSmartPointer<vtkVertexGlyphFilter> targetGlyphFilter =
vtkSmartPointer<vtkVertexGlyphFilter>::New();
targetGlyphFilter->SetInputData(target);
targetGlyphFilter->Update();
//vtkTransformPolyDataFilter对源标记点进行变换来显示配准后的点集
vtkSmartPointer<vtkTransformPolyDataFilter> transformFilter =
vtkSmartPointer<vtkTransformPolyDataFilter>::New();
transformFilter->SetInputData(sourceGlyphFilter->GetOutput());
//设置变换的结果
transformFilter->SetTransform(landmarkTransform);
transformFilter->Update();
vtkSmartPointer<vtkPolyDataMapper> sourceMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
sourceMapper->SetInputConnection(sourceGlyphFilter->GetOutputPort());
vtkSmartPointer<vtkActor> sourceActor =
vtkSmartPointer<vtkActor>::New();
sourceActor->SetMapper(sourceMapper);
sourceActor->GetProperty()->SetColor(1, 1, 0);
sourceActor->GetProperty()->SetPointSize(5);
vtkSmartPointer<vtkPolyDataMapper> targetMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
targetMapper->SetInputConnection(targetGlyphFilter->GetOutputPort());
vtkSmartPointer<vtkActor> targetActor =
vtkSmartPointer<vtkActor>::New();
targetActor->SetMapper(targetMapper);
targetActor->GetProperty()->SetColor(1, 0, 0);
targetActor->GetProperty()->SetPointSize(5);
vtkSmartPointer<vtkPolyDataMapper> solutionMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
solutionMapper->SetInputConnection(transformFilter->GetOutputPort());
vtkSmartPointer<vtkActor> solutionActor =
vtkSmartPointer<vtkActor>::New();
solutionActor->SetMapper(solutionMapper);
solutionActor->GetProperty()->SetColor(0, 0, 1);
solutionActor->GetProperty()->SetPointSize(5);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
renderer->AddActor(sourceActor);
renderer->AddActor(targetActor);
renderer->AddActor(solutionActor);
//设置坐标系
vtkSmartPointer<vtkAxesActor> axes =
vtkSmartPointer<vtkAxesActor>::New();
axes->SetScale(30);
renderer->AddActor(axes);
renderer->SetBackground(.3, .6, .3);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindow->SetSize(640, 480);
renderWindow->Render();
renderWindow->SetWindowName("PolyDataLandmarkReg");
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
ICP算法是一个迭代的过程,每次迭代 中对于源数据点P找到目标点集Q中的最近点,然后基于最小二乘原理求解当前的变换T。通过不断迭代直至收敛,就完成点集的配准
和上边配准区别:vtkIterativeClosestPointTransform类中设置源点集和目标点集的函数是SetSource()、SetTarget()其中输入的数据类型为vtkDataSet,上边配准中vtkLandmarkTransform的输入数据类型为vtkPoints
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
#include <vtkPoints.h>
#include <vtkSmartPointer.h>
#include <vtkLandmarkTransform.h>
#include <vtkMatrix4x4.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkProperty.h>
#include <vtkTransformPolyDataFilter.h>
#include <vtkVertexGlyphFilter.h>
#include <vtkIterativeClosestPointTransform.h>
#include <vtkPolyDataReader.h>
#include <vtkTransform.h>
//测试文件:../data/fran_cut.vtk
int main(int argc, char* argv[])
{
vtkSmartPointer<vtkPolyDataReader> reader =
vtkSmartPointer<vtkPolyDataReader>::New();
reader->SetFileName("D:\\lqyWord\\VTK图形图像开发进阶随书代码\\Examples\\Chap06\\data\\fran_cut.vtk");
reader->Update();
vtkSmartPointer<vtkPolyData> original = reader->GetOutput();
//对原始数据做了一个平移和旋转 这里只是设置变换矩阵
vtkSmartPointer<vtkTransform> translation =
vtkSmartPointer<vtkTransform>::New();
//x轴方向平移量0.2
translation->Translate(0.2, 0.0, 0.0);
//旋转绕X轴旋转30°
translation->RotateX(30);
//进行旋转平移变换
vtkSmartPointer<vtkTransformPolyDataFilter> transformFilter1 =
vtkSmartPointer<vtkTransformPolyDataFilter>::New();
//设置原始数据
transformFilter1->SetInputData(reader->GetOutput());
//设置变换矩阵
transformFilter1->SetTransform(translation);
transformFilter1->Update();
vtkSmartPointer<vtkPolyData> source =
vtkSmartPointer<vtkPolyData>::New();
source->SetPoints(original->GetPoints());
vtkSmartPointer<vtkPolyData> target =
vtkSmartPointer<vtkPolyData>::New();
target->SetPoints(transformFilter1->GetOutput()->GetPoints());
//vtkVertexGlyphFilter根据输入数据集的几何信息生成相应的点数据集
//将原始数据转化为点数据集,可以实现一些基于点的渲染技术,如点渲染、使用点大小表示某些属性
vtkSmartPointer<vtkVertexGlyphFilter> sourceGlyphFilter =
vtkSmartPointer<vtkVertexGlyphFilter>::New();
sourceGlyphFilter->SetInputData(source);
sourceGlyphFilter->Update();
vtkSmartPointer<vtkVertexGlyphFilter> targetGlyphFilter =
vtkSmartPointer<vtkVertexGlyphFilter>::New();
targetGlyphFilter->SetInputData(target);
targetGlyphFilter->Update();
//设置点云配准的原点云和目标点云 相当于是计算变换矩阵
vtkSmartPointer<vtkIterativeClosestPointTransform> icpTransform =
vtkSmartPointer<vtkIterativeClosestPointTransform>::New();
icpTransform->SetSource(sourceGlyphFilter->GetOutput());
icpTransform->SetTarget(targetGlyphFilter->GetOutput());
//刚体变换
icpTransform->GetLandmarkTransform()->SetModeToRigidBody();
//设置迭代次数
icpTransform->SetMaximumNumberOfIterations(20);
//设置配准之前先计算两个点集重心,并平移源点集使得两者重心重合
icpTransform->StartByMatchingCentroidsOn();
icpTransform->Modified();
icpTransform->Update();
//对源点集进行空间变换
vtkSmartPointer<vtkTransformPolyDataFilter> transformFilter2 =
vtkSmartPointer<vtkTransformPolyDataFilter>::New();
transformFilter2->SetInputData(sourceGlyphFilter->GetOutput());
transformFilter2->SetTransform(icpTransform);
transformFilter2->Update();
vtkSmartPointer<vtkPolyDataMapper> sourceMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
sourceMapper->SetInputConnection(sourceGlyphFilter->GetOutputPort());
vtkSmartPointer<vtkActor> sourceActor =
vtkSmartPointer<vtkActor>::New();
sourceActor->SetMapper(sourceMapper);
sourceActor->GetProperty()->SetColor(0, 1, 0);
sourceActor->GetProperty()->SetPointSize(3);
vtkSmartPointer<vtkPolyDataMapper> targetMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
targetMapper->SetInputConnection(targetGlyphFilter->GetOutputPort());
vtkSmartPointer<vtkActor> targetActor =
vtkSmartPointer<vtkActor>::New();
targetActor->SetMapper(targetMapper);
targetActor->GetProperty()->SetColor(1, 0, 0);
targetActor->GetProperty()->SetPointSize(3);
vtkSmartPointer<vtkPolyDataMapper> solutionMapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
solutionMapper->SetInputConnection(transformFilter2->GetOutputPort());
vtkSmartPointer<vtkActor> solutionActor =
vtkSmartPointer<vtkActor>::New();
solutionActor->SetMapper(solutionMapper);
solutionActor->GetProperty()->SetColor(0, 0, 1);
solutionActor->GetProperty()->SetPointSize(3);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
renderer->AddActor(sourceActor);
renderer->AddActor(targetActor);
renderer->AddActor(solutionActor);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderWindow->SetSize(640, 480);
renderWindow->Render();
renderWindow->SetWindowName("PolyDataICP");
renderWindow->Render();
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
绿色源点集,红色目标点集,蓝色为配准后的点集
9.纹理映射
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
#include <vtkSmartPointer.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkActor.h>
#include <vtkPolyDataMapper.h>
#include <vtkTransformTextureCoords.h>
#include <vtkTexture.h>
#include <vtkTextureMapToSphere.h>
#include <vtkTextureMapToCylinder.h>
#include <vtkBMPReader.h>
#include <vtkTexturedSphereSource.h>
#include <vtkXMLPolyDataReader.h>
//测试:../data/masonry.bmp ../data/cow.vtp
int main(int argc, char* argv[])
{
vtkSmartPointer<vtkBMPReader> texReader =
vtkSmartPointer<vtkBMPReader>::New();
texReader->SetFileName("D:\\lqyWord\\VTK图形图像开发进阶随书代码\\Examples\\Chap06\\data\\masonry.bmp");
//加载纹理图像
vtkSmartPointer<vtkTexture> texture =
vtkSmartPointer<vtkTexture>::New();
texture->SetInputConnection(texReader->GetOutputPort());
vtkSmartPointer<vtkXMLPolyDataReader> modelReader =
vtkSmartPointer<vtkXMLPolyDataReader>::New();
modelReader->SetFileName("D:\\lqyWord\\VTK图形图像开发进阶随书代码\\Examples\\Chap06\\data\\cow.vtp");
//通过球面建立映射关系 将二维的纹理映射到三维的圆柱体表面
vtkSmartPointer<vtkTextureMapToCylinder> texturemap =
vtkSmartPointer<vtkTextureMapToCylinder>::New();
texturemap->SetInputConnection(modelReader->GetOutputPort());
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(texturemap->GetOutputPort());
//渲染的收加上纹理
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
actor->SetTexture(texture);
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
renderer->AddActor(actor);
renderer->SetBackground(1.0, 1.0, 1.0);
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renWinInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renWinInteractor->SetRenderWindow(renderWindow);
renderWindow->SetSize(640, 480);
renderWindow->Render();
renderWindow->SetWindowName("TextureMap");
renderWindow->Render();
renderWindow->Render();
renWinInteractor->Start();
return EXIT_SUCCESS;
}