PCL學習筆記——點雲讀取、濾波、下采樣、三角化、展示

直接上代碼裏面有註釋

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:

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章