VTK-点云表面重建,实测效果可以

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.总体效果

还原度还可以,如果牺牲一些性能还能更精细。

  • 13
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值