点云模板匹配

        点云模板匹配是一种在点云数据中寻找特定形状或模式的方法。它通常用于计算机视觉和三维图像处理中,可以应用于物体识别、姿态估计、场景分析等任务。点云模板匹配的基本思想是将一个称为模板的小点云形状与输入的大点云进行匹配,以找到最佳的对应关系。通常,模板是由已知的目标对象或感兴趣的形状提取得到的。

以下是一般的点云模板匹配流程:

  1. 提取模板:从点云中选择一个目标对象或形状,提取出其特征或描述子作为模板。
  2. 预处理:对输入的大点云进行预处理,例如滤波、重采样、去噪等操作,以减少噪声和优化数据质量。
  3. 特征提取:为输入点云和模板点云提取特征或描述子。这些特征可以包括形状特征、几何属性、法线方向、表面曲率等。
  4. 匹配:使用匹配算法(如最近邻搜索、迭代最近点、ICP等)通过比较特征或描述子来寻找最佳的匹配。
  5. 评估与筛选:根据匹配得分或距离,对匹配结果进行评估并筛选出最佳的匹配结果。
  6. 可视化和应用(可选):可以将匹配结果可视化或应用于其他任务,如目标识别、姿态估计等。

        需要注意的是,点云模板匹配的性能受到许多因素的影响,如点云质量、噪声、特征选择、算法选择等。在实际应用中,可能需要尝试不同的方法和参数来获得最佳的匹配结果。

代码实现

#include <limits>
#include <fstream>
#include <vector>
#include <Eigen/Core>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/kdtree/kdtree_flann.h>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/features/normal_3d.h>
#include <pcl/features/fpfh.h>
#include <pcl/registration/ia_ransac.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/search/impl/search.hpp>typedef pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> PCLHandler;class FeatureCloud {
public:typedef pcl::PointCloud<pcl::PointXYZ> PointCloud;typedef pcl::PointCloud<pcl::Normal> SurfaceNormals;typedef pcl::PointCloud<pcl::FPFHSignature33> LocalFeatures;typedef pcl::search::KdTree<pcl::PointXYZ> SearchMethod;FeatureCloud() :search_method_xyz_(new SearchMethod),normal_radius_(0.02f),feature_radius_(0.02f) {}~FeatureCloud() {}// 处理给定的点云voidsetInputCloud(PointCloud::Ptr xyz) {xyz_ = xyz;processInput();}// 加载并处理给定PCD文件中的点云voidloadInputCloud(const std::string& pcd_file) {xyz_ = PointCloud::Ptr(new PointCloud);pcl::io::loadPCDFile(pcd_file, *xyz_);processInput();}// 获取指向点云的指针PointCloud::PtrgetPointCloud() const {return (xyz_);}// 获取指向三维曲面法线的点云的指针SurfaceNormals::PtrgetSurfaceNormals() const {return (normals_);}// 获取指向特征描述点云的指针LocalFeatures::PtrgetLocalFeatures() const {return (features_);}protected:// 计算表面法线和局部特征voidprocessInput() {computeSurfaceNormals();computeLocalFeatures();}// 计算表面法线voidcomputeSurfaceNormals() {// 创建表面法向量normals_ = SurfaceNormals::Ptr(new SurfaceNormals);// 计算表面法向量pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> norm_est;norm_est.setInputCloud(xyz_);norm_est.setSearchMethod(search_method_xyz_);norm_est.setRadiusSearch(normal_radius_);norm_est.compute(*normals_);}// 计算局部特征描述子/*** 根据表面法向量 计算本地特征描述*/voidcomputeLocalFeatures() {features_ = LocalFeatures::Ptr(new LocalFeatures);pcl::FPFHEstimation<pcl::PointXYZ, pcl::Normal, pcl::FPFHSignature33> fpfh_est;fpfh_est.setInputCloud(xyz_);fpfh_est.setInputNormals(normals_);fpfh_est.setSearchMethod(search_method_xyz_);fpfh_est.setRadiusSearch(feature_radius_);fpfh_est.compute(*features_);}private:// 点云数据PointCloud::Ptr xyz_;SurfaceNormals::Ptr normals_;LocalFeatures::Ptr features_; // 快速点特征直方图 Fast Point Feature HistogramSearchMethod::Ptr search_method_xyz_; // KDTree方法查找邻域// 参数float normal_radius_;float feature_radius_;
};class TemplateAlignment {
public:// 用于存储对齐结果的结构struct Result {// 匹配分数float fitness_score;// 转换矩阵Eigen::Matrix4f final_transformation;EIGEN_MAKE_ALIGNED_OPERATOR_NEW};TemplateAlignment() :min_sample_distance_(0.05f),max_correspondence_distance_(0.01f * 0.01f),nr_iterations_(500) {// 初始化随机采样一致性(SAC-IA)算法中的参数sac_ia_.setMinSampleDistance(min_sample_distance_);sac_ia_.setMaxCorrespondenceDistance(max_correspondence_distance_);sac_ia_.setMaximumIterations(nr_iterations_);}~TemplateAlignment() {}// 将给定的点云设置为模板将与之对齐的目标void setTargetCloud(FeatureCloud& target_cloud) {target_ = target_cloud;// 设置输入target点云sac_ia_.setInputTarget(target_cloud.getPointCloud());// 设置特征targetsac_ia_.setTargetFeatures(target_cloud.getLocalFeatures());}// 将给定点云添加到模板点云列表中void addTemplateCloud(FeatureCloud& template_cloud) {templates_.push_back(template_cloud);}// 将给定的模板点云与setTargetCloud()指定的目标对齐// 对齐的核心代码void align(FeatureCloud& template_cloud, TemplateAlignment::Result& result) {// 设置输入源sac_ia_.setInputSource(template_cloud.getPointCloud());// 设置特征源sac_ia_.setSourceFeatures(template_cloud.getLocalFeatures());pcl::PointCloud<pcl::PointXYZ> registration_output;sac_ia_.align(registration_output);// 根据最远相应距离计算匹配分数result.fitness_score = (float)sac_ia_.getFitnessScore(max_correspondence_distance_);// 获取最终转换矩阵result.final_transformation = sac_ia_.getFinalTransformation();}// 将addTemplateCloud设置的所有模板点云与setTargetCloud()指定的目标对齐void alignAll(std::vector<TemplateAlignment::Result, Eigen::aligned_allocator<Result> >& results) {results.resize(templates_.size());for (size_t i = 0; i < templates_.size(); ++i) {align(templates_[i], results[i]);}}// 将所有模板点云与目标点云对齐,以找到具有最佳对齐分数的模板云int findBestAlignment(TemplateAlignment::Result& result) {// 将所有模板与目标点云对齐std::vector<Result, Eigen::aligned_allocator<Result> > results;alignAll(results);// 找到最合适的模板float lowest_score = std::numeric_limits<float>::infinity();int best_template = 0;for (size_t i = 0; i < results.size(); ++i) {const Result& r = results[i];if (r.fitness_score < lowest_score) {lowest_score = r.fitness_score;best_template = (int)i;}}// 输出最佳匹配result = results[best_template];return (best_template);}private:// 模板云及其将要对齐的目标的列表std::vector<FeatureCloud> templates_;FeatureCloud target_;// 随机采样一致性(SAC-IA)算法注册例程及其参数pcl::SampleConsensusInitialAlignment<pcl::PointXYZ, pcl::PointXYZ, pcl::FPFHSignature33> sac_ia_;float min_sample_distance_;float max_correspondence_distance_;int nr_iterations_;
};/*** 对齐对象模板集合到一个示例点云* 通过直通滤波框定范围(得到感兴趣区域)* 将感兴趣区域进行降采样(提高模板匹配效率)*/
int main(int argc, char** argv) 
{// 加载对象模板std::vector<FeatureCloud> object_templates;object_templates.resize(0);// 加载特征云FeatureCloud template_cloud;template_cloud.loadInputCloud("G:/vsdata/PCLlearn/PCDdata/bun0.pcd");object_templates.push_back(template_cloud);// 加载目标点云pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);pcl::PCDReader reader;reader.read("G:/vsdata/PCLlearn/PCDdata/bun0.pcd", *cloud);// 移除离群点const float depth_limit = 1.0;pcl::PassThrough<pcl::PointXYZ> pass;pass.setInputCloud(cloud);pass.setFilterFieldName("z");pass.setFilterLimits(0, depth_limit);pass.filter(*cloud);// 降采样点云, 减少计算量// 定义体素大小 5mmconst float voxel_grid_size = 0.005f;pcl::VoxelGrid<pcl::PointXYZ> vox_grid;vox_grid.setInputCloud(cloud);// 设置叶子节点的大小lx, ly, lzvox_grid.setLeafSize(voxel_grid_size, voxel_grid_size, voxel_grid_size);//vox_grid.filter (*cloud); // Please see this http://www.pcl-developers.org/Possible-problem-in-new-VoxelGrid-implementation-from-PCL-1-5-0-td5490361.htmlpcl::PointCloud<pcl::PointXYZ>::Ptr tempCloud(new pcl::PointCloud<pcl::PointXYZ>);vox_grid.filter(*tempCloud);cloud = tempCloud;// 保存滤波&降采样后的点云图pcl::io::savePCDFileBinary("pass_through_voxel.pcd", *tempCloud);std::cout << "pass_through_voxel.pcd saved" << std::endl;// 对齐到目标特征点云FeatureCloud target_cloud;target_cloud.setInputCloud(cloud);// 设置TemplateAlignment输入TemplateAlignment template_align;for (size_t i = 0; i < object_templates.size(); i++) {FeatureCloud& object_template = object_templates[i];// 添加模板点云template_align.addTemplateCloud(object_template);}// 设置目标点云template_align.setTargetCloud(target_cloud);std::cout << "findBestAlignment" << std::endl;// 查找最佳模板对齐方式// 核心代码TemplateAlignment::Result best_alignment;int best_index = template_align.findBestAlignment(best_alignment);const FeatureCloud& best_template = object_templates[best_index];// 打印匹配度分数(小于0.00002的值是好的)printf("Best fitness score: %f\n", best_alignment.fitness_score);printf("Best fitness best_index: %d\n", best_index);// 打印旋转矩阵和平移向量Eigen::Matrix3f rotation = best_alignment.final_transformation.block<3, 3>(0, 0);Eigen::Vector3f translation = best_alignment.final_transformation.block<3, 1>(0, 3);Eigen::Vector3f euler_angles = rotation.eulerAngles(2, 1, 0) * 180 / M_PI;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");cout << "yaw(z) pitch(y) roll(x) = " << euler_angles.transpose() << endl;printf("\n");printf("t = < %0.3f, %0.3f, %0.3f >\n", translation(0), translation(1), translation(2));// 保存对齐的模板以进行可视化pcl::PointCloud<pcl::PointXYZ> transformed_cloud;// 将模板中保存的点云图进行旋转矩阵变换,把变换结果保存到transformed_cloudpcl::transformPointCloud(*best_template.getPointCloud(), transformed_cloud, best_alignment.final_transformation);//pcl::io::savePCDFileBinary("output.pcd", transformed_cloud);pcl::visualization::PCLVisualizer viewer("example");// 设置坐标系系统viewer.addCoordinateSystem(0.5, "cloud", 0);// 设置背景色viewer.setBackgroundColor(0.05, 0.05, 0.05, 0); // Setting background to a dark grey// 旋转后的点云rotated --------------------------------pcl::PointCloud<pcl::PointXYZ>::Ptr t_cloud(&transformed_cloud);PCLHandler transformed_cloud_handler(t_cloud, 255, 255, 255);viewer.addPointCloud(t_cloud, transformed_cloud_handler, "transformed_cloud");// 设置渲染属性(点大小)viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "transformed_cloud");// 目标点云target --------------------------------PCLHandler target_cloud_handler(cloud, 255, 100, 100);viewer.addPointCloud(cloud, target_cloud_handler, "target_cloud");// 设置渲染属性(点大小)viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "target_cloud");// 模板点云template --------------------------------PCLHandler template_cloud_handler(cloud, 100, 255, 255);viewer.addPointCloud(best_template.getPointCloud(), template_cloud_handler, "template_cloud");// 设置渲染属性(点大小)viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "template_cloud");while (!viewer.wasStopped()) {viewer.spinOnce();}return (0);
}

结果输出 

pass_through_voxel.pcd saved
findBestAlignment
Best fitness score: 0.000008
Best fitness best_index: 0|  1.000 -0.020 -0.007 |
R = |  0.020  0.999  0.026 ||  0.007 -0.027  1.000 |yaw(z) pitch(y) roll(x) =   1.17069 -0.385805  -1.52169t = < 0.000, 0.000, 0.002 >

实现效果 

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

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

相关文章

Python笔记;库,包,模块

在Python中库没有官方说法。 是其他地方沿用过来的。 姑且认为他是一个包或多个包的集合。 包里有子包和模块。 模块以.py格式存储。 下图是一个例子&#xff0c;对于Robot包&#xff1a; import math a math.sqrt(9) 等价于 from math import * a sqrt(9) from math im…

mysql面试题33:Blob和text有什么区别

该文章专注于面试&#xff0c;面试只要回答关键点即可&#xff0c;不需要对框架有非常深入的回答&#xff0c;如果你想应付面试&#xff0c;是足够了&#xff0c;抓住关键点 面试官&#xff1a;Blob和text有什么区别 Blob和text是数据库中存储大文本数据的两种数据类型&#…

数学建模、统计建模、计量建模整体框架的理解以及建模的步骤

数学建模、统计建模、计量建模整体框架的理解以及建模的步骤 引言正文模型的设定模型的估计建模中可能遇到的四种数据类型 模型的检验模型的应用 最后 引言 这篇博客主要写给统计或者数学专业的小白&#xff0c;以供快速上手建模比赛&#xff1b;本人将在这里整合参加建模比赛…

4.03 用户中心-订单管理功能开发

用户中心-订单管理功能开发: (1&#xff09;包含用户订单的查询根据订单并进行分页 (2&#xff09;订单的确定和交易关闭订单删除 详细内容&#xff0c;查询地址&#xff1a;http://www.gxcode.top/code 页面下载地址&#xff1a;

安防监控视频汇聚平台EasyCVR视频广场搜索异常,报错“通道未开启”的问题排查与解决

安防视频监控系统EasyCVR视频汇聚平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等&#xff0c;能对外分发RTSP、RTMP、FLV、…

跨域问题-笔记

这里写目录标题 一、什么是跨域&#xff1a;二、跨域问题解决思路&#xff1a;1.从浏览器入手2.从域名入手3.从jsonp入手4.从代理入手 一、什么是跨域&#xff1a; 跨域指的是不同服务器之间不能相互访问各自的资源或者数据&#xff0c;这出于一个策略——“同源策略”&#x…

“.NET视频总结:认识框架的结构和组件,掌握开发工具的奥妙“一

目录 第一单元&#xff1a;二十一世纪程序执行 背景: 总结&#xff1a; 第二单元:对象导向与类别设计 背景: 总结&#xff1a; 第三单元&#xff1a;使用类别与基底类别库 总结: 第四单元:Windows开发程序 背景: 总结: 第五单元:防护式程序设计 背景: 总结: 第六…

阿里云华中1(武汉)本地地域公网带宽价格表

阿里云华中1&#xff08;武汉&#xff09;地域上线&#xff0c;本地地域只有一个可用区A&#xff0c;高可用需要多可用区部署的应用&#xff0c;不建议选择本地地域&#xff0c;可以选择上海或杭州地域&#xff0c;阿里云服务器华中1&#xff08;武汉&#xff09;地域公网带宽价…

Lesson10---list

lesson18: 一、 1.list是一个XX链表&#xff08;0&#xff1a;19&#xff1a;26&#xff09; 2.链表里面&#xff0c;单独存储数据最适合的结构是XX&#xff08;0&#xff1a;19&#xff1a;53&#xff09; 3.list的任意位置插入删除的时间复杂度是O(N)吗&#xff1f;&…

B树、B+树详解

B树 前言   首先&#xff0c;为什么要总结B树、B树的知识呢&#xff1f;最近在学习数据库索引调优相关知识&#xff0c;数据库系统普遍采用B-/Tree作为索引结构&#xff08;例如mysql的InnoDB引擎使用的B树&#xff09;&#xff0c;理解不透彻B树&#xff0c;则无法理解数据…

SpringBoot 如何使用 Prometheus 进行监控

在当今的软件开发世界中&#xff0c;监控是至关重要的一部分。它允许开发人员和运维团队实时跟踪应用程序的性能、可用性和健康状况。Spring Boot是一个流行的Java框架&#xff0c;用于构建微服务和Web应用程序&#xff0c;而Prometheus是一个开源的监控和警报工具。本文将介绍…

小程序 词云图 echarts-for-weixin-wordcloud

GitHub - clydee-geng/echarts-for-weixin-wordcloud: echarts词云微信小程序版 这个是适配与小程序版的词云图&#xff0c;之前有找到ucharts来代替&#xff0c;但是ucharts的词云图功能有两个缺点&#xff1a;1.无法根据值的大小显示词云图的大小&#xff1b;2.显示的顺序是…

主动配电网故障恢复的重构与孤岛划分matlab程序

微❤关注“电气仔推送”获得资料&#xff08;专享优惠&#xff09; 参考文档&#xff1a; A New Model for Resilient Distribution Systems by Microgrids Formation&#xff1b; 主动配电网故障恢复的重构与孤岛划分统一模型&#xff1b; 同时考虑孤岛与重构的配电网故障…

VR全景展示带来旅游新体验,助力旅游业发展!

引言&#xff1a; VR&#xff08;虚拟现实&#xff09;技术正以惊人的速度改变着各行各业&#xff0c;在旅游业中&#xff0c;VR全景展示也展现了其惊人的影响力&#xff0c;为景区带来了全新的宣传机会和游客体验。 一&#xff0e;什么是VR全景展示&#xff1f; VR全景展示是…

java过滤非中英文的特殊字符,四字节表情字符

过滤非中英文的特殊字符 /*** 过滤特殊字符* param str str* return String*/ public static String filterStr(String str) {if (StringUtils.isBlank(str)) {return str;}String regEx "[~!#$%^&*()|{}:;,\\[\\].<>/?~&#xff01;#&#xffe5;%……&…

Python的就业前景及薪资收入

作为近几年来特别受欢迎的编程语言之一&#xff0c;Python一直以来被众多行业内人士寄予厚望&#xff0c;今后有可能替代老牌霸主Java&#xff0c;成为新一代编程语言榜首。 与其他语言相比&#xff0c;Python中的语言语法特别简单&#xff0c;并且代码具有可读性&#xff0c;多…

ubuntu安装Miniconda并举例使用

更新系统包 sudo apt update sudo apt upgrade官网下载Miniconda&#xff0c;最好是实体机下载后放进虚拟机&#xff0c;方法可以参考Xftp 7连接服务器或者本地虚拟机文章 https://docs.conda.io/en/latest/miniconda.html#linux-installers 进入安装目录执行&#xff0c;右键…

Maven 引入外部依赖

如果我们需要引入第三方库文件到项目&#xff0c;该怎么操作呢&#xff1f; pom.xml 的 dependencies 列表列出了我们的项目需要构建的所有外部依赖项。 要添加依赖项&#xff0c;我们一般是先在 src 文件夹下添加 lib 文件夹&#xff0c;然后将你工程需要的 jar 文件复制到 …

Springboot接收http参数总结(最简单易懂)

1. 前端能携带请求参数的地方 http请求一半前端请求参数放在三个地方&#xff1a;请求头&#xff0c;请求查询参数&#xff08;Query String&#xff09;&#xff0c;请求体。 请求体需要获取HttpServletRequest对象才能获取。 2. 请求体常见格式 而请求体中可以存放多种格式…

深度学习-房价预测案例

1. 实现几个函数方便下载数据 import hashlib import os import tarfile import zipfile import requests#save DATA_HUB dict() DATA_URL http://d2l-data.s3-accelerate.amazonaws.com/def download(name, cache_diros.path.join(.., data)): #save"""下载…