1.原理
使用3D的平面裁剪点云。
(1)定义你所需的平面。
(2)判断所有点云点在平面的哪一侧,同侧保留,异侧删除。
如何判断点在平面的哪一侧:
以点M为例:
1)设平面上的一个向量G。
2)做平面到点M的垂直向量L,点乘计算向量L和向量G的夹角(点乘算夹角,叉乘算垂直向量)
3)如果夹角在0°到180°(各算法接口计算的值不一样,按情况定阈值),那么点在平面上方;如果夹角在180°到360°,那么点在平面下方。
2.使用场景
使用平面裁剪点云的场景。工作中比如要写一个用户在屏幕上点三个点,然后通过这三个点确定一个平面,去裁剪点云的功能时。
3.注意事项
本示例代码中添加了三个三维点计算平面方程的C++实现,可自行取用。
// 计算三维平面公式Ax + By + Cz + D = 0中的各个系数(三点确定一个平面
double x1 = 143.01; double y1 = 49.68; double z1 = 24.53;
double x2 = 159.08; double y2 = 44.23; double z2 = 24.67;
double x3 = 161.39; double y3 = 51.24; double z3 = 24.5;
double A = (y3 - y1) * (z3 - z1) - (z2 - z1) * (y3 - y1);
double B = (x3 - x1) * (z2 - z1) - (x2 - x1) * (z3 - z1);
double C = (x2 - x1) * (y3 - y1) - (x3 - x1) * (y2 - y1);
double D = -(A * x1 + B * y1 + C * z1);
4.关键函数
设置3D平面裁剪的平面参数。
Eigen::Vector4f plane;
setPlaneParameters(plane);
5.代码
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/plane_clipper3D.h>
#include <pcl/filters/extract_indices.h>
#include <boost/thread/thread.hpp>
#include <pcl/visualization/pcl_visualizer.h>
int main()
{
/****************3D平面裁剪滤波********************/
// 原始点云
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
pcl::io::loadPCDFile("D:/code/csdn/data/bunny.pcd", *cloud); // 加载原始点云数据
// 结果点云
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZRGB>);
Eigen::Vector4f plane; // 3D平面
plane << 0, 0, 1, 0; // A、B、C、D
pcl::IndicesPtr indices(new std::vector <int>()); // 保存裁剪点的索引
// 3D平面裁剪滤波
pcl::PlaneClipper3D<pcl::PointXYZRGB> filters(plane);
filters.setPlaneParameters(plane); // 设置平面参数
filters.clipPointCloud3D(*cloud, *indices);
pcl::ExtractIndices<pcl::PointXYZRGB> extract; // 索引
extract.setInputCloud(cloud);
extract.setIndices(indices);
extract.setNegative(true); // true不保留范围内的点,false保留范围内的点
extract.filter(*cloud_filtered);
/****************展示********************/
boost::shared_ptr<pcl::visualization::PCLVisualizer> view_raw(new pcl::visualization::PCLVisualizer("raw"));
view_raw->addPointCloud<pcl::PointXYZRGB>(cloud, "raw cloud");
view_raw->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "raw cloud");
boost::shared_ptr<pcl::visualization::PCLVisualizer> view_filtered(new pcl::visualization::PCLVisualizer("filter"));
view_filtered->addPointCloud<pcl::PointXYZRGB>(cloud_filtered, "filtered cloud");
view_filtered->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "filtered cloud");
while (!view_raw->wasStopped())
{
view_raw->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
while (!view_filtered->wasStopped())
{
view_filtered->spinOnce(100);
boost::this_thread::sleep(boost::posix_time::microseconds(100000));
}
return 0;
}