PCL实现点云选取并计算选取点法向量及可视化

2023-10-27

1、背景及效果展示

因项目需求,基于PCL1.8.1 + VS2015 实现点云特征点选取并计算选取的特点法向量,并对特征点选取过程可视化、法向量计算结果可视化,特此记录该小功能实现。

随机选取几个特征点
随机选取几个特征点
​​​​​
计算选取特征点法线并可视化

 

2、实现步骤及流程

1)加载/读取源点云数据;

2)执行回调函数、注册屏幕选点事件;

3)记录回调函数中选取的点云、形成点云子集;

4)基于NormalEstimationOMP 加速计算以源点云为搜索表面的点云子集的法向量;

5)调用可视化函数、显示源点云、子集点云、选取特征点、及特征点法向量。

3、代码实现

#include "stdafx.h"
#include <pcl/point_types.h>
#include <pcl/io/ply_io.h>
#include <pcl/io/pcd_io.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/normal_3d_omp.h>//使用OMP需要添加的头文件
#include <pcl/filters/voxel_grid.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <boost/thread/thread.hpp>
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL);

using namespace std;
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloudT;

// Mutex: //进程锁
boost::mutex cloud_mutex;
PointCloudT::Ptr normalCloud(new PointCloudT);

//用于给回调函数的结构体定义
// structure used to pass arguments to the callback function
struct callback_args
{
	PointCloudT::Ptr clicked_points_3d;
	pcl::visualization::PCLVisualizer::Ptr viewerPtr;
};

//回调函数
void pp_callback(const pcl::visualization::PointPickingEvent& event, void* args)
{
	struct callback_args* data = (struct callback_args *)args;
	if (event.getPointIndex() == -1)
		return;
	PointT current_point;

	event.getPoint(current_point.x, current_point.y, current_point.z);
	
	//TODO
	//data->clicked_points_3d->clear();//将上次选的点清空

	data->clicked_points_3d->points.push_back(current_point);//添加新选择的点
	//pointIndices.push_back(event.getPointIndex());
	normalCloud = data->clicked_points_3d;
	// Draw clicked points in red:将选中点用红色标记
	pcl::visualization::PointCloudColorHandlerCustom<PointT> red(data->clicked_points_3d, 255, 0, 0);
	data->viewerPtr->removePointCloud("clicked_points");
	data->viewerPtr->addPointCloud(data->clicked_points_3d, red, "clicked_points");
	data->viewerPtr->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 10, "clicked_points");
	std::cout << current_point.x << " " << current_point.y << " " << current_point.z << std::endl;
	std::cout << event.getPointIndex() << std::endl;
}

pcl::PointCloud<pcl::PointXYZ>::Ptr genCloud(std::vector<float> x, std::vector<float> y, std::vector<float> z)
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

	cloud->width = x.size();
	cloud->height = 1;
	cloud->points.resize(x.size()*1);

	for (int i = 0; i < cloud->width; i++)
	{
		cloud->points[i].x = x[i];
		cloud->points[i].y = y[i];
		cloud->points[i].z = z[i];
	}
	return cloud;
}

void NormalEstimationVisualizer(boost::shared_ptr<pcl::visualization::PCLVisualizer> &_visualizer, 
	pcl::PointCloud<pcl::Normal>::Ptr &_normal,
	PointCloudT::Ptr& _sourceCloud,
	PointCloudT::Ptr& _normalCloud)
{
	// 创建两个观察视点
	int v1(0);
	int v2(1);
	_visualizer->createViewPort(0.0, 0.0, 0.5, 1.0, v1);
	_visualizer->createViewPort(0.5, 0.0, 1.0, 1.0, v2);

	// 设置背景颜色
	_visualizer->setBackgroundColor(0.0, 0.0, 0.0, v1);
	_visualizer->setBackgroundColor(0.0, 0.0, 0.0, v2);

	// 原始的点云设置为白色的
	_visualizer->removePointCloud("cloud_tar_v1");
	_visualizer->removePointCloud("cloud_tar_v2");//删除点云小名,再add达到刷新updatePointCloud效果,同时保留视口信息
	pcl::visualization::PointCloudColorHandlerCustom<PointT> target_cloud_color(_sourceCloud, 20, 180, 20);
	pcl::visualization::PointCloudColorHandlerCustom<PointT> aligned_cloud_color(_normalCloud, 180, 20, 20);
	_visualizer->addPointCloud(_sourceCloud, target_cloud_color, "cloud_tar_v1", v1);//设置原始的点云都是显示为白色
	_visualizer->addPointCloud(_normalCloud, aligned_cloud_color, "clicked_points", v1);//设置原始的点云都是显示为白色
	_visualizer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, "clicked_points",v1);
	_visualizer->addPointCloud(_sourceCloud, target_cloud_color, "cloud_tar_v2", v2);
	//添加需要显示的点云法向。cloud为原始点云模型,normal为法向信息,1表示需要显示法向的点云间隔,即每1个点显示一次法向,0.2表示法向长度。
	_visualizer->addPointCloudNormals<pcl::PointXYZ, pcl::Normal>(_normalCloud, _normal, 1, 0.2,"normal",v2);

	// 加入文本的描述在各自的视口界面
	//在指定视口viewport=v1添加字符串“white 。。。”其中"icp_info_1"是添加字符串的ID标志,(10,15)为坐标16为字符大小 后面分别是RGB值
	_visualizer->addText("Green: Original point cloud\nRed: Selected point cloud", 10, 15, "icp_info_1", v1);
	_visualizer->addText("Green: Original point cloud\nWhite: Calculated Normal", 10, 15, "icp_info_2", v2);

	while (!_visualizer->wasStopped())
	{
		_visualizer->spinOnce(100);
		boost::this_thread::sleep(boost::posix_time::microseconds(100000));
	}
	
}

int main()
{
	//------------------加载点云数据-------------------
	PointCloudT::Ptr sourceCloud(new PointCloudT);
	boost::shared_ptr<pcl::visualization::PCLVisualizer> viewer(new pcl::visualization::PCLVisualizer("Viewer"));
	boost::shared_ptr<pcl::visualization::PCLVisualizer> normalViewer(new pcl::visualization::PCLVisualizer("Normal viewer"));

	if (pcl::io::loadPLYFile<PointT>("C:\\Users\\mateng\\Desktop\\ARglass.ply", *sourceCloud) == -1)
	{
		PCL_ERROR("Could not read file\n");
	}

	//获得互斥体,期间不能修改点云
	cloud_mutex.lock();

	// Display pointcloud:
	//显示点云
	viewer->addPointCloud(sourceCloud);
	//viewer->setCameraPosition(0, 0, -2, 0, -1, 0, 0);  //设置相机位置

	// Add point picking callback to viewer:
	//可视化窗口执行回调函数
	struct callback_args cb_args;
	PointCloudT::Ptr clicked_points_3d(new PointCloudT);
	cb_args.clicked_points_3d = clicked_points_3d;
	cb_args.viewerPtr = pcl::visualization::PCLVisualizer::Ptr(viewer);
	//注册屏幕选点事件
	viewer->registerPointPickingCallback(pp_callback, (void*)&cb_args);
	//Shfit+鼠标左键选择点
	std::cout << "Shift+click on three floor points, then press 'Q'..." << std::endl;
	// Spin until 'Q' is pressed:
	//摁“Q”键结束
	viewer->spin();
	std::cout << "done." << std::endl;
	//释放互斥体
	cloud_mutex.unlock();

	//------------------计算法线----------------------
	pcl::NormalEstimationOMP<PointT, pcl::Normal> n;//OMP加速
	pcl::PointCloud<pcl::Normal>::Ptr normals(new pcl::PointCloud<pcl::Normal>);
	//建立kdtree来进行近邻点集搜索
	pcl::search::KdTree<PointT>::Ptr tree(new pcl::search::KdTree<PointT>());
	n.setNumberOfThreads(10);//设置openMP的线程数
	//n.setViewPoint(0,0,0);//设置视点,默认为(0,0,0)
	n.setInputCloud(normalCloud);
	n.setSearchSurface(sourceCloud);
	n.setViewPoint(20,20,20);
	n.setSearchMethod(tree);
	n.setKSearch(20);//点云法向计算时,需要所搜的近邻点大小
	//n.setRadiusSearch(0.03);//半径搜素
	n.compute(*normals);//开始进行法向计


    //------------------可视化----------------------
	NormalEstimationVisualizer(normalViewer, normals, sourceCloud, normalCloud);

}

4、总结

本文方法是把选取的特征点作为一个子集并计算该子集在源点云数据下法向量,对于单独特征点云法向量的计算可直接参考pcl中computePointNormal这个函数的使用。感兴趣的朋友可参考链接:PCL只获取点云中一个点的法向量之computePointNormal,文章所述不当之处还请大家指正。

本文参考文章:

PCL学习系列(一)----PCL屏幕选点

PCL 计算点云法向量并显示

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PCL实现点云选取并计算选取点法向量及可视化 的相关文章

  • 获取url中的参数

    获取url 后的参数 location对象 含有当前URL的信息 属性 href 整个URL字符串 protocol 含有URL第一部分的字符串 如http host 包含有URL中主机名 端口号部分的字符串 如 www cenpok ne
  • 使用openssl_encrypt方法替代mcrypt_encrypt做AES加密

    mcrypt encrypt在php7 1中已被废弃 需要使用openssl encrypt代替 mdecrypt generic版 public function encrypt cbc str iv encryptKey module

随机推荐

  • java8中stream()的使用案例

    Test public void t1 List
  • VS2008中的 fatal error C1902: 程序数据库管理器不匹配

    因为VC Bin 下没有 msobj80 dll mspdb80 dll mspdbcore dll mspdbsrv exe 这四个文件 解决的方法 1 gt 直接从Common7 IDE 下复制这四个文件到VC Bin 下即可解决 2
  • Android-四大应用组件之Activity

    一 理论概述 Activity的理解 二 Intent和IntentFilter的理解 显示意图 当目标组件是当前应用的 则用显示意图 隐式意图 当目标组件是其他应用的 则用隐式意图 三 相关API 四 Activity的启动流程 通过Ac
  • 网络安全工具——Wireshark抓包工具

    文章目录 一 Wireshark抓包介绍 1 WireShark简介 2 WireShark的应用 3 WireShark抓数据包技巧 二 Wireshark抓包入门操作 1 常见协议包 2 查看本机要抓包的网络 3 混杂模式介绍 4 如何
  • stratascratch刷题1 salaries difference && Finding Updated Records

    1 解题 select select max salary from db employee join db dept on db employee department id db dept id where department mar
  • 接口测试的基础(网络传输知识与协议篇)

    接口测试的基础 测试人员对于接口测试的理解总是停留在工具使用层面 很多情况下 测试人员会花很大的 代价去学习一个工具 而测试工具本身的局限性 又导致测试人员陷入想直接用现成的测试框架 却又无法进行扩展的僵局 最后由于项目的特殊性等客观因素
  • ping命令中ICMP协议包的分析

    UDP收发以及所需要的ARP协议已经全部实现 接下来让咱们的协议栈支持ping 俗称能ping通 ping的请求和发送实际是ICMP协议的一个子集 ICMP可以参考ICMP数据包结构 Focus 新浪博客 在IP头中ICMP协议的标识是01
  • springboot项目读取 resource下面的json文件,并且解析

    在Spring Boot项目中 如果要读取src main resources目录下的JSON文件 可以使用ResourceLoader来加载文件 并使用Jackson库将JSON文件解析成Java对象 以下是一个简单的示例代码 impor
  • Type-C协议简介(CC检测原理)

    1 简介 越来越多的手机开始采用Type C作为充电和通信端口 Type C连接器实物和PIN定义如下图 目录 1 简介 Type C连接器中有两个管脚CC1和CC2 他们用于识别连接器的插入方向 以及不同的插入设备 本文介绍CC的基本识别
  • Bootrom概述

    1 Bootrom 是指on chip bootrom 在CPU芯片内部 内嵌有小的boot程序 bootloader 类似于PC机主板上的BIOS的存储区域 2 Bootloader怎么得到 如果对开发板有些改动 还能使用开发板的boot
  • solidity学习过程---msg

    solidity 5 0 remix测试 个人学习 欢迎指正 msg 研究了好一会 感觉还是有点困惑 msg sender 当前合约的调用者 1 部署合约的地址 2 调用该合约的地址 msg value 随消息发送的 wei 的数量 其实并
  • 【Spark NLP】第 15 章:聊天机器人

    大家好 我是Sonhhxg 柒 希望你看完之后 能对你有所帮助 不足请指正 共同学习交流 个人主页 Sonhhxg 柒的博客 CSDN博客 欢迎各位 点赞 收藏 留言 系列专栏 机器学习 ML 自然语言处理 NLP 深度学习 DL fore
  • sonarQube详细安装

    目录 安装前提 将zip包scp到服务器 解压sonar的zip包 修改配置 创建用户sonar 将sonar目录授权给sonar用户 执行命令 查看日志 遇到的问题 今天学习了一下sonar 想看看代码质量检查工具的使用 安装前提 需要j
  • python笔记9--socket初步使用

    python笔记9 socket初步使用 1 介绍 2 源码案例 2 1 tcp c s 案例 2 2 udp c s 案例 3 说明 最近需要写个c s小应用 因此看了下socket编程 把学习的笔记贴在此处以便于后续查阅 1 介绍 本文
  • Mysql服务的安装

    本文适用于新手 小白 而且专业术语不到位 本文内容可能无法解决教程外其他问题 望多包涵 多图警告 此教程适用于windows系统 教程流程 安装时 1 下载安装包 这个是下载链接 MySQLhttps www mysql com 打开界面后
  • ubuntu连接mysql命令_远程服务器 ubuntu 安装 mysql 及连接使用

    远程服务器 ubuntu 安装 mysql 及连接使用 MySQL是最流行的开源关系数据库管理系统 它速度快 容易使用 容易扩展 并且流行的LAMP和LEMP的一部分 这篇指南讲解了如何在 Ubuntu 20 04上安装和保护 MySQL
  • SQL 取数值小数后两位,但不四舍五入。

    例 1 67789 结果要显示为 1 67 select round 1 67789 2 1 1 67 语法 ROUND numeric expression length function 参数 numeric expression 精确
  • k8s滚动更新

    1 编写一个yaml文件 vi deployment nginx yaml apiVersion apps v1 kind Deployment metadata labels app nginx name nginx namespace
  • 22.MongoDB删除操作效率及相关问题验证

    最近遇到一个了一个MongoDB数据删除的问题 需要一次性删除上线即1 5年前 1年前的数据且之后每天清空一年过期的数据 在数据量比较大的情况下何种方式的删除效率最高是一个值得研究的问题 本文通过实际测试找出其中规律 本文采用腾讯云mong
  • PCL实现点云选取并计算选取点法向量及可视化

    1 背景及效果展示 因项目需求 基于PCL1 8 1 VS2015 实现点云特征点选取并计算选取的特点法向量 并对特征点选取过程可视化 法向量计算结果可视化 特此记录该小功能实现 随机选取几个特征点 计算选取特征点法线并可视化 2 实现步骤