点云定义(还是点云指针定义?一直搞不懂)
//常用
typedef pcl::PointXYZRGBA PointT;
pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
//两个一起定义:pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>), cloud_f(new pcl::PointCloud<PointT>);
pcl::PointCloud<pcl::PointNormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointNormal>);//带法线的点云
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);//法线
1. 读取和保存点云
这两种方法不知道有什么区别,先记下来吧
法一:
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
typedef pcl::PointXYZRGBA PointT;
pcl::PCDReader reader;
pcl::PLYReader reader1;
reader.read("tree3.pcd", *cloud);
reader1.read("cow_final1_RORFed.ply", *cloud);
pcl::PCDWriter writer;
pcl::PLYWriter writer1;
writer.write<PointT> ("tree3.pcd", *every_cluster, false);
writer1.write<PointT> ("tree3.pcd", *every_cluster, false);
法二:
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); // 创建点云(指针)
if (pcl::io::loadPLYFile<pcl::PointXYZ>("2020- 6- 9-10-0passthrough.ply", *cloud) <0) //* 读入PLY格式的文件,如果文件不存在,返回-1
{
PCL_ERROR("Couldn't read file test_pcd.pcd \n"); //文件不存在时,返回错误,终止程序。
getchar();
return (-1);
}
pcl::io::savePLYFile("test.ply", *cloud, true);
批量存取时文件名写法
string和stringstream区别:string和stringstream用法总结
//简单版批量存储
//(在for循环里面)
std::stringstream ss, ss1;
ss << "tree3_cluster_" << j << ".pcd";
ss1<< "tree3_cluster_" << j << ".ply";
writer.write<PointT> (ss.str (), *every_cluster, false);
writer1.write<PointT> (ss1.str(), *every_cluster, false);
j++;
结合结构体以及字符串对点云进行批量存取:
//复杂版批量读取点云和存储点云
#include <string>
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
string num2str(int i)
{
stringstream ss;
ss << i;
return ss.str();
}
//定义结构体,用于处理点云
struct PLY
{
std::string f_name; //文件名
pcl::PointCloud<pcl::PointNormal>::Ptr cloudWithNormal;//存储估计的法线的指针
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud;//存储点云
//构造函数
PLY() : cloud(new pcl::PointCloud<pcl::PointXYZ>),cloudWithNormal(new pcl::PointCloud<pcl::PointNormal>){}; //初始化
};
int main()
{
const int numberOfViews = 6;//文件数量
std::vector<PLY, Eigen::aligned_allocator<PCD> > data; //点云数据
std::vector<PLY, Eigen::aligned_allocator<PCD> > data1; //点云数据
std::string prefix("cow1");
std::string extension("_withNormal_boundary.ply"); //声明并初始化string类型变量extension,表示文件后缀名
// 通过遍历文件名,读取ply文件
for (int i = 0; i < numberOfViews; i++) //遍历所有的文件名
{
std::string fname = prefix + num2str(i) + extension;
// 读取点云,并保存到models
PLY m;
m.f_name = fname;
if (pcl::io::loadPLYFile(fname, *m.cloud) == -1) //* 读入PCD格式的文件,如果文件不存在,返回-1
{
cout << "Couldn't read file " + fname + "." << endl; //文件不存在时,返回错误,终止程序。
return (-1);
}
data.push_back(m);
}
//这样之后data[i].cloud就代表一个点云,共六个
//批量存储点云
for (int i = 0; i < numberOfViews; ++i)
{
std::string fname = prefix + num2str(i) + "_rotate" + extension;
pcl::io::savePLYFile(fname, *data[i].cloudWithNormal, true);
}
return 0;
}
还可以批量进行其他操作,比如离群点滤波
//-----------------------去除离群点------------------------
std::vector<PCD, Eigen::aligned_allocator<PCD> > data1; //这里新定义了一个算是数组?好像滤波之后的点云不能重复赋值到这个数组里
pcl::RadiusOutlierRemoval<pcl::PointXYZ> outrem;
outrem.setRadiusSearch(0.01);
outrem.setMinNeighborsInRadius(5);
for (int i = 0; i < numberOfViews; ++i)
{
PLY a;//这里新定义了一个结构体
outrem.setInputCloud(data[i].cloud);
outrem.filter(*a.cloud);
data1.push_back(a);
}
注意!
批量处理点云时会出现定义新点云以及赋值的问题,这里一定要注意在赋值时先给他一个空间,否则如果只是一个指针的话很容易报错,什么指针溢出啥的,最后处理完成一定要设置好点云的长宽来保存点云
2. 定义一个新的点云
*cloud是已知的点云
*newcloud是新点云
pcl::PointCloud<pcl::PointXYZRGB>::Ptr newcloud(new pcl::PointCloud<pcl::PointXYZRGB>); // 创建点云(指针)
newcloud->height = cloud->height;//或者直接这个newcloud->height = 1;一般好像点云这个都是1
newcloud->width = cloud->width;//*cloud是已知的点云
newcloud->is_dense = false;
也可以直接复制点云
pcl::PointCloud<pcl::PointXYZRGB>::Ptr newcloud(new pcl::PointCloud<pcl::PointXYZRGB>); // 创建点云(指针)
pcl::copyPointCloud(*cloud, *newcloud);//把cloud复制给newcloud(然后就可以直接用newcloud了,里面就有相应点的坐标了,相当于把指针赋值了吧)注意一定要加这个,否则没法给新点云的点赋值啥的
//一顿操作之后newcloud里面一些点被修改,需要保存起来,如下:
newcloud->height = 1;
newcloud->width = newcloud->points.size();
newcloud->is_dense = false;
创建新点云并且给它赋值:
pcl::PointCloud<pcl::PointXYZ>::Ptr centorid_points(new pcl::PointCloud<pcl::PointXYZ>);
for (int i = 0; i < numberOfViews; i++)
{
pcl::PointXYZ point;
Eigen::Vector4f centroid; // 质心
pcl::compute3DCentroid(*data1[i].cloud, centroid); // 齐次坐标,(c0,c1,c2,1)
point.x = centroid(0); //这里直接给点云赋值(centorid_points->points[i].x=centroid(0);)是不行的,要先给点赋值,然后再把点push_back到点云中
point.y = centroid(1);
point.z = centroid(2);
//cout << centroid(0)<<endl;
centorid_points->points.push_back(point);
}
centorid_points->height = 1;
centorid_points->width = numberOfViews;
centorid_points->is_dense = false;
有序点云的保存
pcl::PointCloud<pcl::PointXYZ> newcloud;
newcloud.width = 424;
newcloud.height = 512;
newcloud.points.resize(newcloud.width*newcloud.height);//要加这个,否则会报错
newcloud.is_dense = false;//点云中有NAN值,若没有则true,或者说数值是有限则是true
for (int i = 0; i < cloud->size(); i++)
{
newcloud.points[i].x = cloud->points[i].x;
newcloud.points[i].y = cloud->points[i].y;
newcloud.points[i].z = cloud->points[i].z;
/*std::cout << i << endl;*/
}
pcl::io::savePLYFile("newcloud.ply", newcloud);
3. 去除NAN点
#include <pcl/filters/extract_indices.h>
#include <pcl/filters/filter.h> //这两个任意一个头文件好像就可以
//去除NAN点
std::vector<int> mapping;
pcl::removeNaNFromPointCloud(*pcloud, *pcloud, mapping);
std::cout << "原始点云去除NaN点后数量: " << pcloud->points.size() << std::endl;
注意这里如果是复制的指针,去除之前一定要先保存点云,否则没啥效果
pcl::copyPointCloud(*source_key_Neigh, *source_key_Neighbors);
for (int n = 0; n < source_key_Neigh->size(); n++)
{
for (int m = 0; m < source_key_Neigh->size(); m++)
{
if ((source_key_Neigh->points[n].x == source_key_Neighbors->points[m].x) && (source_key_Neigh->points[n].y == source_key_Neighbors->points[m].y) && (source_key_Neigh->points[n].z == source_key_Neighbors->points[m].z) && (m != n))
{
source_key_Neighbors->points[m].x = NAN;
source_key_Neighbors->points[m].y = NAN;
source_key_Neighbors->points[m].z = NAN;
}
}
}
// 设置并保存点云***********保存这里很重要
source_key_Neighbors->height = 1;
source_key_Neighbors->width = source_key_Neighbors->points.size();
source_key_Neighbors->is_dense = false;
//去除NAN点
std::vector<int> mapping;
pcl::removeNaNFromPointCloud(*source_key_Neighbors, *source_key_Neighbors, mapping);
4. 遍历点云
C++里,是编号是从0开始
for (int n = 0; n < source_key_Neigh->size(); n++)
{
for (int m = 0; m < source_key_Neigh->size(); m++)
{
if ((source_key_Neigh->points[n].x == source_key_Neighbors->points[m].x) && (source_key_Neigh->points[n].y == source_key_Neighbors->points[m].y) && (source_key_Neigh->points[n].z == source_key_Neighbors->points[m].z) && (m != n))
{
source_key_Neighbors->points[m].x = NAN;
source_key_Neighbors->points[m].y = NAN;
source_key_Neighbors->points[m].z = NAN;
}
}
}
matlab里编号是从1 开始
ptCloud = pcread('source_key_Neigh.ply');
location=ptCloud.Location;
x = location(:,1);
y = location(:,2);
z = location(:,3);
location1=location;
x1=x;
y1=y;
z1=z;
for i=1:size(x)
for j=1:size(x)
if((x1(j)==x(i))&&(y1(j)==y(i))&&(z1(j)==z(i))&&(i~=j))
location1(j,1)=nan;
location1(j,2)=nan;
location1(j,3)=nan;
end
end
end
location1(all(isnan(location1), 2),:) = [];
5. 查看点云点数
#include <pcl/ModelCoefficients.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/point_types.h>
using namespace std;
typedef pcl::PointXYZRGBA PointT;
int main()
{
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZRGB>);
std::string prefix("2020-10-14-15-19-55_ConditionAnd_RadiusOutlierRemoval");
std::string extension(".ply");
std::string fname = prefix + extension;
if (pcl::io::loadPLYFile<pcl::PointXYZRGB>(fname, *cloud) == -1) //* load the file
{
PCL_ERROR("Couldn't read file. \n");
system("PAUSE");
return (-1);
}
std::cout << cloud->size() << endl;
std::system("pause");
return 0;
}