原文链接:Projecting points using a parametric model
本小节将学习如何将点投影到一个参数化模型上(例如平面或球等)。参数化模型通过一组参数来设定,对于平面来说使用其等式形式ax+by+cz+d=0,在PCI中有专门存储常见模型系数的数据结构。
程序代码
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/ModelCoefficients.h>
#include <pcl/filters/project_inliers.h>
#include<pcl/visualization/pcl_visualizer.h>
int
main(int argc, char** argv)
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_projected(new pcl::PointCloud<pcl::PointXYZ>);
pcl::visualization::PCLVisualizer viewer("project inliers");
int v1(1);
int v2(2);
viewer.createViewPort(0, 0, 0.5, 1, v1);
viewer.createViewPort(0.5, 0, 1, 1, v2);
// 填入点云数据
cloud->width = 5;
cloud->height = 1;
cloud->points.resize(cloud->width * cloud->height);
for (size_t i = 0; i < cloud->points.size(); ++i)
{
cloud->points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
cloud->points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
cloud->points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
}
std::cerr << "Cloud before projection: " << std::endl;
for (size_t i = 0; i < cloud->points.size(); ++i)
std::cerr << " " << cloud->points[i].x << " "
<< cloud->points[i].y << " "
<< cloud->points[i].z << std::endl;
// 平面公式:ax + by + cz + d = 0
// 创建一个系数为X=Y=0,Z=1的平面,相当于是x-y平面
// a = b = d = 0, c = 1;
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());
coefficients->values.resize(4);
coefficients->values[0] = coefficients->values[1] = 0;
coefficients->values[2] = 1.0;
coefficients->values[3] = 0;
// 创建滤波器对象
pcl::ProjectInliers<pcl::PointXYZ> proj;//创建滤波器对象
proj.setModelType(pcl::SACMODEL_PLANE); //设置对象对应的投影模型
proj.setInputCloud(cloud);
proj.setModelCoefficients(coefficients);//设置投影模型的参数因子
proj.filter(*cloud_projected);
std::cerr << "Cloud after projection: " << std::endl;
for (size_t i = 0; i < cloud_projected->points.size(); ++i)
std::cerr << " " << cloud_projected->points[i].x << " "
<< cloud_projected->points[i].y << " "
<< cloud_projected->points[i].z << std::endl;
viewer.addPointCloud(cloud, "c1", v1);
viewer.addPointCloud(cloud_projected, "c2", v2);
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1000, "c1", v1);
viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1000, "c2", v2);
viewer.addCoordinateSystem(1000, cloud_projected->points[0].x, cloud_projected->points[0].y, cloud_projected->points[0].z, v2);
viewer.addCoordinateSystem(1000, cloud->points[0].x, cloud->points[0].y, cloud->points[0].z, v1);
while (!viewer.wasStopped())
{
viewer.spinOnce();
}
return (0);
}
在本程序中使用的投影模型为平面。
平面公式:ax + by + cz + d = 0
创建一个系数为X=Y=0,Z=1的平面,相当于是x-y平面
系数设置为:a = b = d = 0, c = 1;
// 平面公式:ax + by + cz + d = 0
// 创建一个系数为X=Y=0,Z=1的平面,相当于是x-y平面
// a = b = d = 0, c = 1;
pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients());
coefficients->values.resize(4);
coefficients->values[0] = coefficients->values[1] = 0;
coefficients->values[2] = 1.0;
coefficients->values[3] = 0;
// 创建滤波器对象
pcl::ProjectInliers<pcl::PointXYZ> proj;//创建滤波器对象
proj.setModelType(pcl::SACMODEL_PLANE); //设置对象对应的投影模型
proj.setInputCloud(cloud);
proj.setModelCoefficients(coefficients);//设置投影模型的参数因子
proj.filter(*cloud_projected);
实验结果
首先随机生成五个点,如左图。
然后将所有点全部投影到X-Y平面(Z=1):如右图:
Cloud before projection:
1.28125 577.094 197.938
828.125 599.031 491.375
358.688 917.438 842.562
764.5 178.281 879.531
727.531 525.844 311.281
Cloud size before projection: 5
Cloud after projection:
1.28125 577.094 0
828.125 599.031 0
358.688 917.438 0
764.5 178.281 0
727.531 525.844 0
Cloud size after projection: 5
由上述结果可知:将点云投影到一个平面,会使点云的某个坐标失去意义(坐标值相同),将三维的点云变成了二维的图像。
同理,对点云数据 table_scene_lms400.pcd进行投影滤波的结果如下:
三维的点云图像已经失去了一个坐标的数据,变成了二维扁平的点云图像。