PCL 计算点云中任意点的法向量

ops/2024/10/9 5:17:53/

目录

一、概述

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实现步骤

  1. 读取点云数据:加载点云文件。
  2. 设置Kd树进行最近邻搜索:通过Kd树搜索,找到某一特定点的邻域点。
  3. 算法向量:利用 pcl::NormalEstimation 计算出第200个点的法向量。
  4. 可视化:显示点云及其法向量。

1.3应用场景

  1. 表面光滑度分析:通过法向量计算局部的表面几何特性。
  2. 三维建模:在3D建模中,法向量可以帮助识别物体表面的细节和轮廓。
  3. 机器人抓取规划:利用法向量信息,识别合适的抓取位置。

二、代码实现

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;
}

三、实现效果


http://www.ppmy.cn/ops/123009.html

相关文章

(计算机毕设)基于Vue和Spring Boot的宠物救助网站设计与实现

博主可接毕设&#xff01;&#xff01;&#xff01; 毕业设计&#xff08;论文&#xff09; 基于Vue和Spring Boot的宠物救助网站设计与实现 摘 要 随着中国互联网的迅猛发展&#xff0c;传统宠物救助领域面临着信息管理繁琐、辐射范围有限、信息传播受限、丢失宠物找回几率较…

知识改变命运 数据结构【java对象的比较】

0&#xff1a;前言 在基本数据类型中&#xff0c;我们可以直接使用号比较是否相等&#xff0c;还记的学堆哪里时候&#xff0c;插入一个数据&#xff0c;就会与其他数据进行比较&#xff0c;当时我们传入的是Integer类型&#xff0c;在Integer类里面已经实现了compare。 如果…

Hadoop的三种运行模式:单机模式、伪分布式模式和完全分布式模式

单机模式 单机模式是Hadoop最简单的运行模式。在单机模式下&#xff0c;所有Hadoop组件都运行在单个机器上&#xff0c;包括HDFS、MapReduce等。由于只有一个节点参与计算&#xff0c;单机模式适用于开发和测试阶段&#xff0c;不适合用于处理大规模数据。在单机模式下&#xf…

可视化-最小二乘法拟合直线

目录 1、最小二乘法拟合直线 2、需要用到的公式 3、计算各个参数 &#xff0c;得到函数表达式 4、可视化-绘画图像 1、最小二乘法拟合直线 double x[15] {29,34,39,44,49,54,59,64,69,74,79,84,89,94,99}; double y[15] { 0.2989,0.3036,0.3084,0.3133,0.3182,0.3231,0.…

腾讯云上传pushdocker镜像到镜像仓库

文章目录 腾讯云上传docker镜像 腾讯云上传docker镜像 >docker login ccr.ccs.tencentyun.com --usernameXXXXXX用户名>sudo docker tag mynginx:1.0 ccr.ccs.tencentyun.com/crfkitty/mynginx:1.0>docker push ccr.ccs.tencentyun.com/crfkitty/mynginx:1.0 The pu…

「Kafka」Kafka消息可靠性和重复消费问题(五)

在 Kafka 中&#xff0c;实现消息的可靠性和避免重复消费是保证数据一致性和系统稳定性的关键。Kafka 提供了多种机制来实现这两个目标。 1. Kafka 消息可靠性 Kafka 的可靠性主要体现在消息的投递和存储上&#xff0c;以确保消息不会丢失。具体来说&#xff0c;有以下几个措…

注册安全分析报告:惠农网

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

【C++指南】类和对象(二):类的默认成员函数——全面剖析 :构造函数

&#x1f493; 博客主页&#xff1a;倔强的石头的CSDN主页 &#x1f4dd;Gitee主页&#xff1a;倔强的石头的gitee主页 ⏩ 文章专栏&#xff1a;《C指南》 期待您的关注 ​ 阅读本篇文章之前&#xff0c;你需要具备的前置知识&#xff1a;类和对象的基础 点击下方链接 【C指南…