目录
一、概述
1.1原理
1.2实现步骤
1.3应用场景
二、代码实现
2.1关键函数
2.1.1 使用 pcl::NormalEstimation 计算特定点的法向量
2.1.2 搜索第200个点的法向量
2.1.3 可视化
2.2完整代码
三、实现效果
PCL点云算法汇总及实战案例汇总的目录地址链接:
PCL点云算法与项目实战案例汇总(长期更新)
一、概述
在三维点云处理中,法向量是描述物体表面局部几何特征的关键参数。对于点云中的任意一点,我们可以通过搜索其邻域点来计算该点的法向量。本文将展示如何通过PCL库计算点云中某一特定点(例如第200个点)的法向量。
1.1原理
法向量的计算主要基于点云中每个点的邻域点。通过对邻域点的坐标计算协方差矩阵,并进行特征值分解,得到最小特征值对应的特征向量作为法向量。
计算协方差矩阵的公式为:
1.2实现步骤
- 读取点云数据:加载点云文件。
- 设置Kd树进行最近邻搜索:通过Kd树搜索,找到某一特定点的邻域点。
- 计算法向量:利用 pcl::NormalEstimation 计算出第200个点的法向量。
- 可视化:显示点云及其法向量。
1.3应用场景
- 表面光滑度分析:通过法向量计算局部的表面几何特性。
- 三维建模:在3D建模中,法向量可以帮助识别物体表面的细节和轮廓。
- 机器人抓取规划:利用法向量信息,识别合适的抓取位置。
二、代码实现
2.1关键函数
2.1.1 使用 pcl::NormalEstimation 计算特定点的法向量
pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
ne.setInputCloud(cloud); // 设置输入点云
ne.setSearchMethod(tree); // 设置Kd树搜索方法
ne.setKSearch(30); // 设置邻域搜索的K近邻数
pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
ne.compute(*normals); // 计算法向量
2.1.2 搜索第200个点的法向量
pcl::Normal point_normal = normals->points[199]; // 获取第200个点的法向量
2.1.3 可视化
void visualizeCloudAndNormal(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::Normal point_normal, int index);
2.2完整代码
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/features/normal_3d.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/search/kdtree.h>
#include <boost/thread/thread.hpp>using namespace std;// 可视化函数:显示点云及特定点的法向量
void visualizeCloudAndNormal(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::Normal point_normal, int index);// 可视化函数:显示点云及特定点的法向量
void visualizeCloudAndNormal(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, pcl::Normal point_normal, int index)
{pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("Point Cloud with Normal"));// 创建两个视口int vp_1, vp_2;viewer->createViewPort(0.0, 0.0, 0.5, 1.0, vp_1);viewer->createViewPort(0.5, 0.0, 1.0, 1.0, vp_2);viewer->setBackgroundColor(0.0, 0.0, 0.0, vp_1); // 设置第一个视口背景为白色viewer->setBackgroundColor(0.08, 0.08, 0.08, vp_2); // 设置第二个视口背景为浅灰色// 在第一个视口显示原始点云pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_color(cloud, 255, 0, 0); // 红色viewer->addPointCloud(cloud, cloud_color, "cloud_vp1", vp_1);// 在第二个视口显示原始点云并展示法向量pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_color_2(cloud, 0, 255, 0); // 绿色viewer->addPointCloud(cloud, cloud_color_2, "cloud_vp2", vp_2);// 获取法向量的起点(即第200个点)pcl::PointXYZ point = cloud->points[index];// 添加法向量pcl::PointXYZ normal_endpoint;normal_endpoint.x = point.x + point_normal.normal_x * 0.1; // 法向量长度调整为0.1normal_endpoint.y = point.y + point_normal.normal_y * 0.1;normal_endpoint.z = point.z + point_normal.normal_z * 0.1;viewer->addArrow(normal_endpoint, point, 1.0, 0.0, 0.0, false, "normal_arrow", vp_2);// 运行可视化//viewer->addCoordinateSystem(1.0);while (!viewer->wasStopped()){viewer->spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100000));}
}
int main(int argc, char** argv)
{// 1. 读取点云数据pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);if (pcl::io::loadPCDFile<pcl::PointXYZ>("C:\\Users\\twothree\\Desktop\\PCL_Blog\\PCL_Blog\\cloud_data\\pcd_data\\bunny.pcd", *cloud) == -1){PCL_ERROR("Couldn't read the PCD file!\n");return (-1);}// 2. 构建Kd树并设置法向量估计pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());ne.setInputCloud(cloud); // 设置输入点云ne.setSearchMethod(tree); // 设置Kd树搜索ne.setKSearch(30); // 设置邻域搜索的K近邻数// 3. 计算法向量pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);ne.compute(*normals); // 计算法向量// 4. 获取第200个点的法向量pcl::Normal point_normal = normals->points[199];cout << "第200个点的法向量为: ("<< point_normal.normal_x << ", "<< point_normal.normal_y << ", "<< point_normal.normal_z << ")" << endl;// 5. 可视化visualizeCloudAndNormal(cloud, point_normal, 199);return 0;
}