直接上代碼裏面有註釋
code:
// Triangulation.cpp : 此文件包含 "main" 函數。程序執行將在此處開始並結束。
//
#include "pch.h"
#include <iostream>
#include<pcl/point_types.h>
#include<pcl/io/pcd_io.h>
#include<pcl/io/ply_io.h>
#include<pcl/kdtree/kdtree_flann.h>
#include<pcl/features/normal_3d.h>
#include<pcl/surface/gp3.h>
#include<pcl/visualization/pcl_visualizer.h>
#include<boost/math/special_functions/round.hpp>
#include<fstream>
#include<pcl/filters/voxel_grid.h>
#include<pcl/filters/extract_indices.h>
#include<pcl/filters/radius_outlier_removal.h>
#include<pcl/surface/mls.h>
using namespace std;
//文件讀取
pcl::PointCloud<pcl::PointXYZ> readFile() {
ifstream filePath;
filePath.open("all_overlap.txt", ios::in);
//求點雲總數目
int rows = -1; //eof會多讀一個
char buf[150];
while (!filePath.eof()) {
rows++;
filePath.getline(buf, sizeof(buf));
}
filePath.clear();
filePath.seekg(0, ios::beg); //移到最開始的位置
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
cloud->width = rows;
cloud->height = 1;
cloud->is_dense = false;
cloud->points.resize(cloud->width*cloud->height);
double tem[3];
for (size_t i = 0; i < rows; i++) {
filePath >> tem[0];
filePath >> tem[1];
filePath >> tem[2];
cloud->points[i].x = tem[0];
cloud->points[i].y = tem[1];
cloud->points[i].z = tem[2];
}
return *cloud;
}
//點雲簡化(濾波+精簡)
pcl::PointCloud<pcl::PointXYZ> cloudSimplication(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) {
// Scheme1:半徑濾波(無法分割大塊背景點雲效果,可以去除整體點雲附加的一些離羣點)
pcl::RadiusOutlierRemoval<pcl::PointXYZ> outrem;
outrem.setInputCloud(cloud);
outrem.setRadiusSearch(3); //搜索鄰近點的範圍大小
outrem.setMinNeighborsInRadius(70); //設置查詢點的鄰近點集數小於X的刪除
pcl::PointCloud<pcl::PointXYZ>::Ptr filter_radius(new pcl::PointCloud<pcl::PointXYZ>);
outrem.filter(*filter_radius);
//下采樣
pcl::VoxelGrid<pcl::PointXYZ> vg;
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_down(new pcl::PointCloud<pcl::PointXYZ>);
vg.setInputCloud(filter_radius);
vg.setLeafSize(1.0f, 1.0f, 1.0f); //使用Xcm長的葉子節點大小進行下采樣
vg.filter(*cloud_down);
//pcl::io::savePCDFile("cloud_down.pcd", *cloud_down);
//// 顯示結果圖
//pcl::visualization::PCLVisualizer viewer("viewer1");
//viewer.addPointCloud(cloud_down);
//viewer.spin();
return *cloud_down;
}
//三角化
void triangulationPoint(pcl::PointCloud<pcl::PointXYZ>::Ptr 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>);
tree->setInputCloud(cloud);
n.setInputCloud(cloud);
n.setSearchMethod(tree);
n.setKSearch(30);
n.compute(*normals); //估計法線存儲位置
//Concatenate the XYZ and normal field
pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>);
pcl::concatenateFields(*cloud, *normals, *cloud_with_normals); //連接字段
//point_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; //定義最終三角化的網絡模型
gp3.setSearchRadius(2.5); //設置連接點之間的最大距離(即爲三角形的最大邊長)
//設置各參數值
gp3.setMu(3); //設置被樣本點搜索其最近鄰點的最遠距離,爲了使用點雲密度的變化
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); //重建提取三角化
pcl::io::savePLYFile("triangulation.ply", triangles);
// 顯示結果圖
pcl::visualization::PCLVisualizer viewer("viewer");
viewer.addPolygonMesh(triangles);
viewer.spin();
}
int main()
{
pcl::PointCloud<pcl::PointXYZ>cloud,cloud_down;
cloud = readFile();
cloud_down=cloudSimplication(cloud.makeShared());
triangulationPoint(cloud_down.makeShared());
}
result: