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