网格平滑
现代扫描技术的发展使得获取点云数据不再困难,通过曲面重建技术可以获取表面网格来表示各种复杂的实体。但是点云数据中往往存在噪声,这样得到的重建网格通常都需要进行平滑处理。网格平滑是一种调整数据集中点坐标的技术。网格平滑的目的是提高网格的外观和提高单元数据集的形状。在平滑过程中,不会改变数据集的拓扑结构,只改变几何结构。网格平滑的应用包括提高等值面的外观,或者作为移除表面噪声的模型工具。通过应用网格平滑,模型的外观能够动态地提高。下图是平滑应用到一个任意变形的分析曲面(半圆柱)的例子。
拉普拉斯平滑是一种常用的平滑算法。VTK中 的vtkSmoothPolyDataFilter类实现了网格的拉普拉斯平滑算法,原理如下面公式:
其中:Xnew表示新的坐标位置,X表示当前的坐标位置。j表示X的邻域点个数,Xi表示第i个邻域点的坐标位置。
vtkSmoothPolyDataFilter::SetNumberOfIterations()控制平滑次数,次数越大平滑越厉害,即细节损失越多。该类中还有多个变量来控制平滑过程,利用这些变化在一定程度岸上可以控制细节的损失。BoundarySmoothing控制是否对边界点平滑。FeatureEdgeSmoothing控制是否对特征边上的点的平滑。如果一条边被两个邻近的多边形公用,若这两个多边形法向量的夹角(特征角)大于定义的阈值,则说明这边为一条特征边。虽然通过特征边平滑设置可以降低一部分细节损失,并不能完全避免,且随着拉普拉斯平滑的不断迭代,模型会逐渐向网格的中心收缩。所以vtkWindowedSincPolyData是一个更好的选择,该算法使用窗口Sinc函数实现网格平滑,能够最小程度地避免收缩。
示例演示
我们演示如何利用vtkSmoothPolyDataFilter进行平滑。
/**********************************************************************
Copyright (c) Mr.Bin. All rights reserved.
For more information visit: http://blog.csdn.net/webzhuce
**********************************************************************/
#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>
int main(int argc, char *argv[])
{
vtkSmartPointer<vtkPolyDataReader> reader =
vtkSmartPointer<vtkPolyDataReader>::New();
reader->SetFileName("E:/github/Study-VTK/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("SmoothPolyData");
vtkSmartPointer<vtkRenderWindowInteractor> interactor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
interactor->SetRenderWindow(renderWindow);
renderWindow->Render();
interactor->Start();
return EXIT_SUCCESS;
}
运行结果
图左是原始网格,图右是平滑后的。可以看出平滑后,网格的部分特征信息也被丢失。
参考资料
- VTK图形图像开发进阶[M]