C++ PCL三维点云物体目标识别

news2025/1/20 3:42:52

程序示例精选

C++ PCL三维点云物体目标识别

如需安装运行环境或远程调试,见文章底部个人QQ名片,由专业技术人员远程协助!

前言

这篇博客针对<<C++ PCL三维点云物体目标识别>>编写代码,代码整洁,规则,易读。 学习与应用推荐首选。

功能:读取三维点云图的物体目标识别


文章目录

一、所需工具软件

二、使用步骤

        1. 引入库

        2. 代码实现

        3. 运行结果

三、在线协助

一、所需工具软件

1. VS

2. PCL

二、使用步骤

1.引入库

#include <pcl/io/pcd_io.h>
#include <pcl/point_cloud.h>
#include <pcl/correspondence.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/features/shot_omp.h>
#include <pcl/features/board.h>
#include <pcl/keypoints/uniform_sampling.h>
#include <pcl/recognition/cg/hough_3d.h>
#include <pcl/recognition/cg/geometric_consistency.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/kdtree/impl/kdtree_flann.hpp>
#include <pcl/common/transforms.h>
#include <pcl/console/parse.h>

2. 代码实现

代码如下:

void
parseCommandLine(int argc, char *argv[])
{
	//Show help
	if (pcl::console::find_switch(argc, argv, "-h"))
	{
		showHelp(argv[0]);
		exit(0);
	}

	//Model & scene filenames
	std::vector<int> filenames;
	filenames = pcl::console::parse_file_extension_argument(argc, argv, ".pcd");
	if (filenames.size() != 2)
	{
		std::cout << "Filenames missing.\n";
		showHelp(argv[0]);
		exit(-1);
	}

	model_filename_ = argv[filenames[0]];
	scene_filename_ = argv[filenames[1]];

	//Program behavior
	if (pcl::console::find_switch(argc, argv, "-k"))//可视化构造对应点时用到的关键点
	{
		show_keypoints_ = true;
	}
	if (pcl::console::find_switch(argc, argv, "-c"))//可视化支持实例假设的对应点对
	{
		show_correspondences_ = true;
	}
	if (pcl::console::find_switch(argc, argv, "-r"))//计算点云的分辨率和多样性
	{
		use_cloud_resolution_ = true;
	}

	std::string used_algorithm;
	if (pcl::console::parse_argument(argc, argv, "--algorithm", used_algorithm) != -1)
	{
		if (used_algorithm.compare("Hough") == 0)
		{
			use_hough_ = true;
		}
		else if (used_algorithm.compare("GC") == 0)
		{
			use_hough_ = false;
		}
		else
		{
			std::cout << "Wrong algorithm name.\n";
			showHelp(argv[0]);
			exit(-1);
		}
	}

	//General parameters
	pcl::console::parse_argument(argc, argv, "--model_ss", model_ss_);
	pcl::console::parse_argument(argc, argv, "--scene_ss", scene_ss_);
	pcl::console::parse_argument(argc, argv, "--rf_rad", rf_rad_);
	pcl::console::parse_argument(argc, argv, "--descr_rad", descr_rad_);
	pcl::console::parse_argument(argc, argv, "--cg_size", cg_size_);
	pcl::console::parse_argument(argc, argv, "--cg_thresh", cg_thresh_);
}


int
main(int argc, char *argv[])
{
	parseCommandLine(argc, argv);

	pcl::PointCloud<PointType>::Ptr model(new pcl::PointCloud<PointType>());           //模型点云
	pcl::PointCloud<PointType>::Ptr model_keypoints(new pcl::PointCloud<PointType>()); //模型角点
	pcl::PointCloud<PointType>::Ptr scene(new pcl::PointCloud<PointType>());           //目标点云
	pcl::PointCloud<PointType>::Ptr scene_keypoints(new pcl::PointCloud<PointType>()); //目标角点
	pcl::PointCloud<NormalType>::Ptr model_normals(new pcl::PointCloud<NormalType>()); //法线
	pcl::PointCloud<NormalType>::Ptr scene_normals(new pcl::PointCloud<NormalType>()); //
	pcl::PointCloud<DescriptorType>::Ptr model_descriptors(new pcl::PointCloud<DescriptorType>()); //描述子
	pcl::PointCloud<DescriptorType>::Ptr scene_descriptors(new pcl::PointCloud<DescriptorType>());

	//
	//  Load clouds
	//
	if (pcl::io::loadPCDFile(model_filename_, *model) < 0)
	{
		std::cout << "Error loading model cloud." << std::endl;
		showHelp(argv[0]);
		return (-1);
	}
	if (pcl::io::loadPCDFile(scene_filename_, *scene) < 0)
	{
		std::cout << "Error loading scene cloud." << std::endl;
		showHelp(argv[0]);
		return (-1);
	}

	//
	//  Set up resolution invariance
	//
	if (use_cloud_resolution_)
	{
		float resolution = static_cast<float> (computeCloudResolution(model));
		if (resolution != 0.0f)
		{
			model_ss_ *= resolution;
			scene_ss_ *= resolution;
			rf_rad_ *= resolution;
			descr_rad_ *= resolution;
			cg_size_ *= resolution;
		}

		std::cout << "Model resolution:       " << resolution << std::endl;
		std::cout << "Model sampling size:    " << model_ss_ << std::endl;
		std::cout << "Scene sampling size:    " << scene_ss_ << std::endl;
		std::cout << "LRF support radius:     " << rf_rad_ << std::endl;
		std::cout << "SHOT descriptor radius: " << descr_rad_ << std::endl;
		std::cout << "Clustering bin size:    " << cg_size_ << std::endl << std::endl;
	}



	std::cout << "Model total points: " << model->size() << "; Selected Keypoints: " << model_keypoints->size() << std::endl;

	uniform_sampling.setInputCloud(scene);
	uniform_sampling.setRadiusSearch(scene_ss_);
	//uniform_sampling.compute (sampled_indices);
	//pcl::copyPointCloud (*scene, sampled_indices.points, *scene_keypoints);
	uniform_sampling.filter(*scene_keypoints);
	std::cout << "Scene total points: " << scene->size() << "; Selected Keypoints: " << scene_keypoints->size() << std::endl;

	//
	//  Compute Descriptor for keypoints:为关键点计算描述子
	//
	pcl::SHOTEstimationOMP<PointType, NormalType, DescriptorType> descr_est;
	descr_est.setNumberOfThreads(4);
	descr_est.setRadiusSearch(descr_rad_);     //设置搜索半径

	descr_est.setInputCloud(model_keypoints);  //模型点云的关键点
	descr_est.setInputNormals(model_normals);  //模型点云的法线 
	descr_est.setSearchSurface(model);         //模型点云       
	descr_est.compute(*model_descriptors);     //计算描述子

	descr_est.setInputCloud(scene_keypoints);
	descr_est.setInputNormals(scene_normals);
	descr_est.setSearchSurface(scene);
	descr_est.compute(*scene_descriptors);

	//
	//  Find Model-Scene Correspondences with KdTree:使用Kdtree找出 Model-Scene 匹配点
	//
	pcl::CorrespondencesPtr model_scene_corrs(new pcl::Correspondences());

	pcl::KdTreeFLANN<DescriptorType> match_search; //设置配准方式
	match_search.setInputCloud(model_descriptors);//模型点云的描述子




		//  Clustering
		pcl::Hough3DGrouping<PointType, PointType, RFType, RFType> clusterer;
		clusterer.setHoughBinSize(cg_size_);     //hough空间的采样间隔:0.01
		clusterer.setHoughThreshold(cg_thresh_); //在hough空间确定是否有实例存在的最少票数阈值:5
		clusterer.setUseInterpolation(true);     //设置是否对投票在hough空间进行插值计算
		clusterer.setUseDistanceWeight(false);   //设置在投票时是否将对应点之间的距离作为权重参与计算

		clusterer.setInputCloud(model_keypoints); //设置模型点云的关键点
		clusterer.setInputRf(model_rf);           //设置模型对应的局部坐标系
		clusterer.setSceneCloud(scene_keypoints);
		clusterer.setSceneRf(scene_rf);
		clusterer.setModelSceneCorrespondences(model_scene_corrs);//设置模型与场景的对应点的集合

		//clusterer.cluster (clustered_corrs);
		clusterer.recognize(rototranslations, clustered_corrs); //结果包含变换矩阵和对应点聚类结果
	}
	else // Using GeometricConsistency:使用几何一致性性质
	{
		pcl::GeometricConsistencyGrouping<PointType, PointType> gc_clusterer;
		gc_clusterer.setGCSize(cg_size_);        //设置几何一致性的大小
		gc_clusterer.setGCThreshold(cg_thresh_); //阈值

		gc_clusterer.setInputCloud(model_keypoints);
		gc_clusterer.setSceneCloud(scene_keypoints);
		gc_clusterer.setModelSceneCorrespondences(model_scene_corrs);

		//gc_clusterer.cluster (clustered_corrs);
		gc_clusterer.recognize(rototranslations, clustered_corrs);
	}

	//
	//  Output results:找出输入模型是否在场景中出现
	//
	std::cout << "Model instances found: " << rototranslations.size() << std::endl;
	for (size_t i = 0; i < rototranslations.size(); ++i)
	{
		std::cout << "\n    Instance " << i + 1 << ":" << std::endl;
		std::cout << "        Correspondences belonging to this instance: " << clustered_corrs[i].size() << std::endl;

		//打印处相对于输入模型的旋转矩阵与平移矩阵
		Eigen::Matrix3f rotation = rototranslations[i].block<3, 3>(0, 0);
		Eigen::Vector3f translation = rototranslations[i].block<3, 1>(0, 3);

		printf("\n");
		printf("            | %6.3f %6.3f %6.3f | \n", rotation(0, 0), rotation(0, 1), rotation(0, 2));
		printf("        R = | %6.3f %6.3f %6.3f | \n", rotation(1, 0), rotation(1, 1), rotation(1, 2));
		printf("            | %6.3f %6.3f %6.3f | \n", rotation(2, 0), rotation(2, 1), rotation(2, 2));
		printf("\n");
		printf("        t = < %0.3f, %0.3f, %0.3f >\n", translation(0), translation(1), translation(2));
	}

	//
	//  Visualization
	//
	pcl::visualization::PCLVisualizer viewer("点云库PCL学习教程第二版-基于对应点聚类的3D模型识别");
	viewer.addPointCloud(scene, "scene_cloud");//可视化场景点云
	viewer.setBackgroundColor(0, 0, 0);
	pcl::PointCloud<PointType>::Ptr off_scene_model(new pcl::PointCloud<PointType>());
	pcl::PointCloud<PointType>::Ptr off_scene_model_keypoints(new pcl::PointCloud<PointType>());

	if (show_correspondences_ || show_keypoints_)//可视化配准点
	{
		//We are translating the model so that it doesn't end in the middle of the scene representation
		//对输入的模型进行旋转与平移,使其在可视化界面的中间位置
		pcl::transformPointCloud(*model, *off_scene_model, Eigen::Vector3f(0, 0, 0), Eigen::Quaternionf(1, 0, 0, 0));
		pcl::transformPointCloud(*model_keypoints, *off_scene_model_keypoints, Eigen::Vector3f(-1, 0, 0), Eigen::Quaternionf(1, 0, 0, 0));

		pcl::visualization::PointCloudColorHandlerCustom<PointType> off_scene_model_color_handler(off_scene_model, 0, 255, 0);
		viewer.addPointCloud(off_scene_model, off_scene_model_color_handler, "off_scene_model");
	}

	if (show_keypoints_)//可视化关键点:蓝色
	{
		pcl::visualization::PointCloudColorHandlerCustom<PointType> scene_keypoints_color_handler(scene_keypoints, 0, 0, 255);
		viewer.addPointCloud(scene_keypoints, scene_keypoints_color_handler, "scene_keypoints");
		viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, "scene_keypoints");

		pcl::visualization::PointCloudColorHandlerCustom<PointType> off_scene_model_keypoints_color_handler(off_scene_model_keypoints, 0, 0, 255);
		viewer.addPointCloud(off_scene_model_keypoints, off_scene_model_keypoints_color_handler, "off_scene_model_keypoints");
		viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 5, "off_scene_model_keypoints");
	}

	for (size_t i = 0; i < rototranslations.size(); ++i)
	{
		pcl::PointCloud<PointType>::Ptr rotated_model(new pcl::PointCloud<PointType>());
		pcl::transformPointCloud(*model, *rotated_model, rototranslations[i]);//把model转化为rotated_model

		std::stringstream ss_cloud;
		ss_cloud << "instance" << i;

		pcl::visualization::PointCloudColorHandlerCustom<PointType> rotated_model_color_handler(rotated_model, 255, 0, 0);
		viewer.addPointCloud(rotated_model, rotated_model_color_handler, ss_cloud.str());


				//  We are drawing a line for each pair of clustered correspondences found between the model and the scene
				viewer.addLine<PointType, PointType>(model_point, scene_point, 0, 255, 0, ss_line.str());
			}
		}
	}

	while (!viewer.wasStopped())
	{
		viewer.spinOnce();
	}

	return (0);
}

3. 运行结果

三、在线协助:

如需安装运行环境或远程调试,见文章底部个人 QQ 名片,由专业技术人员远程协助!
1)远程安装运行环境,代码调试
2)Qt, C++, Python入门指导
3)界面美化
4)软件制作

当前文章连接:Python+Qt桌面端与网页端人工客服沟通工具_alicema1111的博客-CSDN博客

博主推荐文章:python人脸识别统计人数qt窗体-CSDN博客

博主推荐文章:Python Yolov5火焰烟雾识别源码分享-CSDN博客

                         Python OpenCV识别行人入口进出人数统计_python识别人数-CSDN博客

个人博客主页:alicema1111的博客_CSDN博客-Python,C++,网页领域博主

博主所有文章点这里alicema1111的博客_CSDN博客-Python,C++,网页领域博主

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/719063.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

web学习--maven--项目管理工具

写在前面&#xff1a; 这学期搞主攻算法去了&#xff0c;web的知识都快忘了。开始复习学习了。 文章目录 maven介绍功能介绍maven安装jar包搜索仓库 pom文件项目介绍父工程依赖管理属性控制可选依赖构建 依赖管理依赖的传递排除依赖可选依赖 maven生命周期分模块开发模块聚合…

《安全软件开发框架(SSDF) 1.1:降低软件漏洞风险的建议》解读(三)

安全软件开发框架SSDF是由美国国家标准与技术研究院发布的关于安全软件开发的一组实践&#xff0c;帮助开发组织减少发布的软件中的漏洞数量&#xff0c;减少利用未检测到或未解决的漏洞的潜在影响&#xff0c;从根本上解决漏洞防止再次发生。本文根据《Secure Software Develo…

【Nginx05】Nginx学习:HTTP核心模块(二)Server

Nginx学习&#xff1a;HTTP核心模块&#xff08;二&#xff09;Server 第一个重要的子模块就是这个 Server 相关的模块。Server 代表服务的意思&#xff0c;其实就是这个 Nginx 的 HTTP 服务端所能提供的服务。或者更直白点说&#xff0c;就是虚拟主机的配置。通过 Server &…

SpringBoot操作Excel实现导入和导出功能(详细讲解+Gitee源码)

前言&#xff1a;在日常的开发中&#xff0c;避免不了操作Excel&#xff0c;比如从系统当中导出一个报表&#xff0c;或者通过解析客户上传的Excel文件进行批量解析数据入库等等&#xff0c;本篇博客主要汇总日常开发中如何使用开源的Apache提供的POI流操作Excel进行导入导出功…

el-dialog 层级问题混乱

使用 element -UI 的弹窗时&#xff0c;一般来说弹窗的层级应该比较高&#xff0c;背景置灰。 下边这个弹窗是正常情况下的&#xff1a; 有时候出现这样的情况&#xff1a; 解决问题&#xff1a; 只需要 在标签里边添加 append-to-body 属性问题就解决了。

WPF TextBox 添加范围验证

WPF TextBox 添加范围验证 添加范围验证&#xff0c;若出现范围错误添加信息捕捉 使用到技术&#xff1a;使用ValidationRules实现范围验证&#xff0c;当范围出现错误时&#xff0c;可以通过触发器Validation.HasErrorTrue设置自定义错误样式。 使用Behavior技术捕捉所有验证…

1-Nginx介绍及安装(源码安装)

1.Nginx介绍 Nginx&#xff08;engine x&#xff09;是一个轻量级、高性能的HTTP和反向代理服务器&#xff0c;也是一个IMAP/POP3/SMTP服务器。 Nginx特点&#xff1a; ->占用内存少 ->并发能力强(3W/S) 2.Nginx安装 2.1.环境 [rootcentos79-3 ~]# cat /etc/redha…

未来网站开发必备:14个让你惊艳的JavaScript Web API!

微信搜索 【大迁世界】, 我会第一时间和你分享前端行业趋势&#xff0c;学习途径等等。 本文 GitHub https://github.com/qq449245884/xiaozhi 已收录&#xff0c;有一线大厂面试完整考点、资料以及我的系列文章。 快来免费体验ChatGpt plus版本的&#xff0c;我们出的钱 体验地…

进制(数制)及进制之间的转换汇总(超详细)

进制是一种表示数字的方法&#xff0c;它决定了数字在数值系统中的位置和权值。常见的进制包括十进制、二进制、八进制和十六进制。 1. 十进制&#xff08;decimal&#xff09;&#xff1a; 十进制是我们日常生活中最常用的进制&#xff0c;使用0-9这10个数字来表示。每一位的…

小研报 - 神奇的 SD 图(InsCode Stable Diffusion 美图活动一期)

一、 Stable Diffusion 模型 在线使用地址&#xff1a;https://inscode.csdn.net/inscode/Stable-Diffusion 二、模型版本及相关配置 Steps: 20, Sampler: Euler a, CFG scale: 7, Seed: 2391134711, Size: 512x512, Model hash: 74c61c3a52, Model: GuoFeng3, Version: v1.2…

【应用笔记】CW32 电容式触摸按键设计指南

前言 CW32 电容式触摸按键设计指南向客户提供一种利用 CW32 内部资源结合软件编程实现电容式触摸按键有效 触摸检测的方法。本指南的内容重点在于工作原理、软件检测过程以及调试指引。 利用芯源半导体的 CW32 系列小规模 MCU 的 IO、比较器、定时器、高速高精度内置 RC 时钟…

C++ 实现跳表

目录 1.什么是跳表-skiplist 2.skiplist的效率如何保证&#xff1f; 3.skiplist的实现 4.skiplist跟平衡搜索树和哈希表的对比 1.什么是跳表-skiplist skiplist 本质上也是一种查找结构&#xff0c;用于解决算法中的查找问题&#xff0c;跟平衡搜索树和哈希表的价值是一样…

计算机毕业论文内容参考|基于C的空中战机游戏设计与实现

文章目录 导文文章重点摘要前言绪论1课题背景2国内外现状与趋势3课题内容相关技术与方法介绍系统分析系统设计系统实现系统测试总结与展望1本文总结2后续工作展望导文 计算机毕业论文内容参考|基于C的空中战机游戏设计与实现 文章重点 摘要 本文将介绍基于C编程语言的空中战机…

【电影推荐系统】数据加载

目录 数据集 解释 movie.csv ratings.csv tag.csv 数据预处理 mongodb 将数据按照csv文件里的分割符进行分割&#xff0c;转换为DF Moive Rating Tag es 将mongo集合tag 根据mid tag > mid tags(tag1|tag2|tag3...) moive 添加一列 tags 导入后数据库信息 mong…

python爬虫_正则表达式获取天气预报并用echarts折线图显示

文章目录 ⭐前言⭐python re库&#x1f496; re.match函数&#x1f496; re.search函数&#x1f496; re.compile 函数 ⭐正则获取天气预报&#x1f496; 正则实现页面内容提取&#x1f496; echarts的天气折现图 ⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分…

SpringBoot使用EasyExcel批量导出500万数据

SpringBoot使用EasyExcel批量导出500万数据 说明excel版本比较EasyExcel介绍项目目录mysql对应表建表语句pom.xmlapplication.yml配置类启动类代码OrderInfo 实体类OrderInfoExcel excel模版标题类(EasyExcel需要使用这个)TestController控制层接口层TestServiceTestServiceImp…

L298N模块驱动2项4线步进电机的多种方法及其优缺点

摘要&#xff1a;本文将详细介绍L298N模块驱动2项4线步进电机的多种方法&#xff0c;并分析各种方法的优缺点。在实例程序中&#xff0c;将展示不同方法的代码示例&#xff0c;帮助读者理解并实际应用。 引言&#xff1a; 步进电机作为一种常用的电机类型&#xff0c;在许多嵌入…

估值 2 个月从 11 亿美元降到 3 亿美元,投资人清仓跑路,国产大模型创业遇冷...

图片来源&#xff1a;由无界 AI生成 创业未半&#xff0c;而中道崩殂。 6 月 29 日&#xff0c;美团发布公告以 20.65 亿元全资收购光年之外全部权益&#xff0c;距离光年之外正式营业刚过去 84 天。 这是目前中国大模型创业领域最大的收购案&#xff0c;光年之外也在 4 个月时…

HTML5 游戏开发实战 | 黑白棋

黑白棋&#xff0c;又叫反棋(Reversi)、奥赛罗棋(Othello)、苹果棋、翻转棋。黑白棋在西方和日本很流行。游戏通过相互翻转对方的棋子&#xff0c;最后以棋盘上谁的棋子多来判断胜负。黑白棋的棋盘是一个有88方格的棋盘。开始时在棋盘正中有两白两黑四个棋子交叉放置&#xff0…

观察级水下机器人第一次使用总结2023年6月

最近有个科研项目需要用到ROV&#xff0c;其合同三年之前就签订了&#xff0c;由于疫情的影响&#xff0c;一直没有执行。刚好我们的ROV也验收了&#xff0c;正好派上用场。因为属于ROV使用的菜鸟级&#xff0c;我们邀请厂家无锡智海张工和陈工&#xff0c;中海辉固ROV操作经验…