PCL+VTK 无序点集三角化及可视化

6 篇文章 0 订阅

PCL+VTK 无序点集三角化及可视化

无序点集三角化及可视化。

项目构建

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)

project(greedy_projection)

find_package(PCL 1.2 REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_executable (greedy_projection greedy_projection.cpp)
target_link_libraries (greedy_projection ${PCL_LIBRARIES})

Code

/*
 * @Description: 无序点云的快速三角化  
 * @FilePath: greedy_projection.cpp
 */

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/kdtree/kdtree.h>
#include <pcl/features/normal_3d.h>
#include <pcl/surface/gp3.h>      //贪婪投影三角化算法

#include <pcl/io/vtk_lib_io.h>
#include <pcl/surface/vtk_smoothing/vtk_utils.h>

#include <vtkActor.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkPolyDataMapper.h>
#include <vtkTriangleFilter.h>
#include <vtkProperty.h>
#include <vtkPolyDataNormals.h>

#include <vtkAutoInit.h>         //vtk可视化初始化
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);

int main (int argc, char** argv)
{
  // 将一个XYZ点类型的PCD文件打开并存储到对象中
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
  pcl::PCLPointCloud2 cloud_blob;
  pcl::io::loadPCDFile ("../bun0.pcd", cloud_blob);
  pcl::fromPCLPointCloud2 (cloud_blob, *cloud);
  //* the data should be available in cloud

  // Normal estimation*
  pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> n;      //法线估计对象
  pcl::PointCloud<pcl::Normal>::Ptr normals (new pcl::PointCloud<pcl::Normal>);   //存储估计的法线
  pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);  //定义kd树指针
  tree->setInputCloud (cloud); //用cloud构建tree对象
  n.setInputCloud (cloud);
  n.setSearchMethod (tree);
  n.setKSearch (20);
  n.compute (*normals); //估计法线存储到其中
  //* normals should not contain the point normals + surface curvatures

  // Concatenate the XYZ and normal fields*
  pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals (new pcl::PointCloud<pcl::PointNormal>);
  pcl::concatenateFields (*cloud, *normals, *cloud_with_normals);    //连接字段
  //* cloud_with_normals = cloud + normals

  //定义搜索树对象
  pcl::search::KdTree<pcl::PointNormal>::Ptr tree2 (new pcl::search::KdTree<pcl::PointNormal>);
  tree2->setInputCloud (cloud_with_normals);   //点云构建搜索树

  // Initialize objects
  pcl::GreedyProjectionTriangulation<pcl::PointNormal> gp3;   //定义三角化对象
  pcl::PolygonMesh triangles;                //存储最终三角化的网络模型
 
  // Set the maximum distance between connected points (maximum edge length)
  gp3.setSearchRadius (0.025);  //设置连接点之间的最大距离,(即是三角形最大边长)

  // 设置各参数值
  gp3.setMu (2.5);  //设置被样本点搜索其近邻点的最远距离为2.5,为了使用点云密度的变化
  gp3.setMaximumNearestNeighbors (100);    //设置样本点可搜索的邻域个数
  gp3.setMaximumSurfaceAngle(M_PI/4); // 设置某点法线方向偏离样本点法线的最大角度45
  gp3.setMinimumAngle(M_PI/18); // 设置三角化后得到的三角形内角的最小的角度为10
  gp3.setMaximumAngle(2*M_PI/3); // 设置三角化后得到的三角形内角的最大角度为120
  gp3.setNormalConsistency(false);  //设置该参数保证法线朝向一致

  // Get result
  gp3.setInputCloud (cloud_with_normals);     //设置输入点云为有向点云
  gp3.setSearchMethod (tree2);   //设置搜索方式
  gp3.reconstruct (triangles);  //重建提取三角化

  // 附加顶点信息
  std::vector<int> parts = gp3.getPartIDs();
  std::vector<int> states = gp3.getPointStates();

  vtkSmartPointer<vtkPoints> points = vtkSmartPointer<vtkPoints>::New();
  vtkSmartPointer<vtkCellArray> vertices = vtkSmartPointer<vtkCellArray>::New();

  for (int i = 0; i < cloud->size(); i++)
  {
	  vtkIdType pid[1];
	  pid[0] = points->InsertNextPoint(cloud->at(i).x, cloud->at(i).y, cloud->at(i).z);
	  vertices->InsertNextCell(1, pid);
  }
 
  vtkPolyData* polyDataCloud = vtkPolyData::New();
  polyDataCloud->SetPoints(points);
  polyDataCloud->SetVerts(vertices);

  vtkPolyDataMapper* mapperCloud = vtkPolyDataMapper::New();
  mapperCloud->SetInputData(polyDataCloud);

  vtkActor* actorCloud = vtkActor::New();
  actorCloud->SetMapper(mapperCloud);
  actorCloud->GetProperty()->SetColor(1.0, 0.0, 0.0);
  actorCloud->GetProperty()->SetPointSize(3);
  

  vtkSmartPointer<vtkPolyData> poly_data = vtkSmartPointer<vtkPolyData>::New();
  //方法1 需加头文件#include <pcl/io/vtk_lib_io.h>
  int num=pcl::io::mesh2vtk(triangles, poly_data);
  std::cout << num << std::endl;
  //方法2 需加头文件#include <pcl/surface/vtk_smoothing/vtk_utils.h>
  //pcl::VTKUtils::convertToVTK(triangles, poly_data);

  vtkSmartPointer<vtkTriangleFilter> triangleFilter = vtkSmartPointer<vtkTriangleFilter>::New();
  triangleFilter->SetInputData(poly_data);
  triangleFilter->Update();

  // Make the triangle winding order consistent
  vtkSmartPointer<vtkPolyDataNormals> vtknormals =
	vtkSmartPointer<vtkPolyDataNormals>::New();
  vtknormals->SetInputData(triangleFilter->GetOutput());
  vtknormals->ConsistencyOn();
  vtknormals->SplittingOff();
  vtknormals->Update();
  
 
  vtkSmartPointer<vtkPolyDataMapper> mapper = vtkSmartPointer<vtkPolyDataMapper>::New();
  mapper->SetInputConnection(vtknormals->GetOutputPort());
  
  vtkSmartPointer<vtkActor> actorPolygon = vtkSmartPointer<vtkActor>::New();
  actorPolygon->SetMapper(mapper);

  auto renderer0 = vtkSmartPointer<vtkRenderer>::New();
  auto renderer1 = vtkSmartPointer<vtkRenderer>::New();

  auto renWin = vtkSmartPointer<vtkRenderWindow>::New();
  renWin->AddRenderer(renderer0);
  renWin->AddRenderer(renderer1);

  auto iren =vtkSmartPointer<vtkRenderWindowInteractor>::New();
  iren->SetRenderWindow(renWin);

  
  renderer0->AddActor(actorCloud);
  renderer1->AddActor(actorPolygon);
  renderer0->SetViewport(0, 0, 0.5, 1);
  renderer1->SetViewport(0.5, 0, 1, 1);

  renWin->SetSize(512,512);
  renWin->Render();
  iren->Start();

  // Finish
  return 0;
}

Compile & Run

cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=D:\vcpkg\scripts\buildsystems\vcpkg.cmake

cmake --build build --config Release

Result

在这里插入图片描述

参考

1、https://blog.csdn.net/m0_67254672/article/details/135819041
2、https://blog.csdn.net/mrbaolong/article/details/106900333

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值