1.激光扫描仪取点
扫描生成纯粹的点云文件,带法向量。也可以生成带有拓扑结构的Mesh文件。此处使用纯粹点云文件,领悟过程。
2.写代码,看注释
#include"vtkModelInit.h"
#include"vtkGloble.h"
#include"mySWInteractorStyle.h"
#include<vtkPLYReader.h>
#include<vtkVertexGlyphFilter.h>
#include<vtkCleanPolyData.h>
#include<vtkPCANormalEstimation.h>
#include<vtkSignedDistance.h>
#include<vtkExtractSurface.h>
#include<vtkActor.h>
#include<vtkRenderer.h>
#include<vtkRenderWindow.h>
#include<vtkPolyDataMapper.h>
#include<vtkRenderWindowInteractor.h>
int main()
{
//读取点云文件,使用激光扫描仪生成
Create(vtkPLYReader, reader);
reader->SetFileName("F:/Temp/vtkTest/fuse.ply");
//为每个点生成vertex拓扑结构,否则后没法采样
Create(vtkVertexGlyphFilter, glyph);
glyph->SetInputConnection(reader->GetOutputPort());
//对前面的数据采样,原始点超过240000个,重采样后8000多个
//点太多计算实在太慢了
Create(vtkCleanPolyData, clean);
clean->SetInputConnection(glyph->GetOutputPort());
//容差0.01表示1%,整个点云能放进一个包围盒,包围盒的对角线长度L
//容差的绝对值 LX0.01,这个尺寸构成一个小空间球,球内不会有点
//相当于把点云稀释了
clean->SetTolerance(0.01);
//计算每个点的方向量
Create(vtkPCANormalEstimation, normals);
normals->SetInputConnection(clean->GetOutputPort());
//某个点的向量由周围10个点参与计算,默认是25,点多了计算比较慢
normals->SetSampleSize(10);
//允许翻转法线方向
normals->SetFlipNormals(true);
//相邻连接点的图上对点进行完全遍历计算法线,比较慢,效果好
normals->SetNormalOrientationToGraphTraversal();
//这里一定要updata,因为前面都是使用管道连接,此时其实没有数据
normals->Update();
//获取点云的包围框,如果前面不进行updata,这里得不到数据
double bounds[6] = {0};
reader->GetOutput()->GetBounds(bounds);
//计算有向距离,具体算法太深奥
Create(vtkSignedDistance, distance);
distance->SetInputConnection(normals->GetOutputPort());
//在空间中设置/获取要进行采样的区域。
//如果未指定,将自动计算。
distance->SetBounds(bounds);
//每个点的影响半径,值小计算快,太小没结果
distance->SetRadius(4);
//设置/获取用于计算距离函数的i-j-k维度。
distance->SetDimensions(
bounds[1] - bounds[0],
bounds[3] - bounds[2],
bounds[5] - bounds[4]);
//算法看不懂
//从vtkSignedDistance生成过零等值面
Create(vtkExtractSurface, surface);
surface->SetInputConnection(distance->GetOutputPort());
surface->SetRadius(distance->GetRadius());
//普通的渲染流程
Create(vtkPolyDataMapper, vertextMapper);
Create(vtkPolyDataMapper, surfaceMapper);
vertextMapper->SetInputConnection(glyph->GetOutputPort());
surfaceMapper->SetInputConnection(surface->GetOutputPort());
Create(vtkActor, vertextActor);
Create(vtkActor, surfaceActor);
vertextActor->SetMapper(vertextMapper);
surfaceActor->SetMapper(surfaceMapper);
Create(vtkRenderer, vertextRender);
Create(vtkRenderer, surfaceRender);
vertextRender->AddActor(vertextActor);
vertextRender->SetViewport(0, 0, 0.5, 1);
vertextRender->SetBackground(0.9, 0.8, 0.7);
vertextRender->ResetCamera();
surfaceRender->AddActor(surfaceActor);
surfaceRender->SetViewport(0.5, 0, 1, 1);
surfaceRender->SetBackground(0.7, 0.8, 0.9);
surfaceRender->ResetCamera();
Create(vtkRenderWindow, window);
window->AddRenderer(vertextRender);
window->AddRenderer(surfaceRender);
Create(vtkRenderWindowInteractor, interActor);
interActor->SetRenderWindow(window);
//自己实现的交互样式,操作习惯仿照SolidWorks
Create(mySWInteractorStyle, style);
interActor->SetInteractorStyle(style);
interActor->Start();
return 0;
}
如果使用带法向量的点云文件,可以跳过这一段
//计算每个点的方向量
Create(vtkPCANormalEstimation, normals);
normals->SetInputConnection(clean->GetOutputPort());
//某个点的向量由周围10个点参与计算,默认是25,点多了计算比较慢
normals->SetSampleSize(10);
//允许翻转法线方向
normals->SetFlipNormals(true);
//相邻连接点的图上对点进行完全遍历计算法线,比较慢,效果好
normals->SetNormalOrientationToGraphTraversal();
//这里一定要updata,因为前面都是使用管道连接,此时其实没有数据
normals->Update();
3.原始点云
可以看到点云,没有单元结构
4.提取的表面
已经有了单元结构
5.总体效果
还原度还可以,如果牺牲一些性能还能更精细。