PCL点云库——PCA粗配准

2023-05-16

PCA粗配准


  主成分分析法( Principal Component Analysis,简称PCA)是使数据简化的算法,通过揭露数据内部的主要分布方向,减少了数据集的维数,从而保留了点云集中贡献最大的特征,更好地解释数据的变化规律。PCA 算法进行点云配准是以主方向为依据,根据两点云的主方向计算出对应的三个旋转和三个平移量,可大致对齐两点云数据。
  PCA算法流程如下:
  (1)原始特征矩阵归一化处理(假设M和样本,每个样本n个特征,则对M*N的X数据,进行零均值化,即减去这一列的均值);
  (2)求取归一化处理后特征矩阵的协方差矩阵;
  (3)计算协方差矩阵的特征值及其对应的特征向量;
  (4)将特征向量按对应特征值大小从上到下按行排列成矩阵,取前k行组成矩阵P;
  (5)Y=PX即为降维到k维后的数据。
  文末给出了配准代码,配准效果如图1、图2、图3、图4所示

图1 最大主方向对齐
图2 最小主方向对齐
图3 次大主方向对齐
图4 最大与最小主方向对齐
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/io/pcd_io.h>
#include <pcl/common/transforms.h>

//计算向量u与向量v之间的夹角
void calRotation(Eigen::Vector3f u, Eigen::Vector3f v, double &angle, Eigen::Vector3f &vec);
//获取罗德里格斯旋转矩阵
Eigen::Matrix4f RodriguesMatrixTranslation(Eigen::Vector3f n, double angle);

int main()
{
	pcl::PointCloud<pcl::PointXYZ>::Ptr target(new pcl::PointCloud<pcl::PointXYZ>());//目标点云
	pcl::PointCloud<pcl::PointXYZ>::Ptr source(new pcl::PointCloud<pcl::PointXYZ>());//源点云
	pcl::io::loadPCDFile("cloud\\target.pcd", *target);
	pcl::io::loadPCDFile("cloud\\source.pcd", *source);

	Eigen::Vector4f pcaCentroidtarget;//容量为4的列向量
	pcl::compute3DCentroid(*target, pcaCentroidtarget);//计算目标点云质心
	Eigen::Matrix3f covariance;//创建一个3行3列的矩阵,里面每个元素均为float类型
	pcl::computeCovarianceMatrixNormalized(*target, pcaCentroidtarget, covariance);//计算目标点云协方差矩阵
	Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> eigen_solver(covariance, Eigen::ComputeEigenvectors);//构造一个计算特定矩阵的类对象
	Eigen::Matrix3f eigenVectorsPCA = eigen_solver.eigenvectors();//eigenvectors计算特征向量
	Eigen::Vector3f eigenValuesPCA = eigen_solver.eigenvalues();//eigenvalues计算特征值

	Eigen::Vector4f pcaCentroidsource;
	pcl::compute3DCentroid(*source, pcaCentroidsource);//计算源点云质心
	Eigen::Matrix3f model_covariance;
	pcl::computeCovarianceMatrixNormalized(*source, pcaCentroidsource, model_covariance);//计算源点云协方差矩阵
	Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> modeleigen_solver(model_covariance, Eigen::ComputeEigenvectors);
	Eigen::Matrix3f model_eigenVectorsPCA = modeleigen_solver.eigenvectors();
	Eigen::Vector3f model_eigenValuesPCA = modeleigen_solver.eigenvalues();

	pcl::PointCloud<pcl::PointXYZ>::Ptr target_t(new pcl::PointCloud<pcl::PointXYZ>);
	//平移目标点云,将目标点云通过质心平移到原点
	Eigen::Matrix4f translation_t = Eigen::Matrix4f::Identity();
	//设置矩阵的元素
	translation_t(0, 3) = -pcaCentroidtarget[0];
	translation_t(1, 3) = -pcaCentroidtarget[1];
	translation_t(2, 3) = -pcaCentroidtarget[2];
	pcl::transformPointCloud(*target, *target_t, translation_t);

	pcl::PointCloud<pcl::PointXYZ>::Ptr source_t(new pcl::PointCloud<pcl::PointXYZ>);
	//平移源点云,将源点云通过质心平移到原点
	Eigen::Matrix4f translation_s = Eigen::Matrix4f::Identity();
	//设置矩阵的元素
	translation_s(0, 3) = -pcaCentroidsource[0];
	translation_s(1, 3) = -pcaCentroidsource[1];
	translation_s(2, 3) = -pcaCentroidsource[2];
	pcl::transformPointCloud(*source, *source_t, translation_s);

	pcl::PointCloud<pcl::PointXYZ>::Ptr translationCloud(new pcl::PointCloud<pcl::PointXYZ>);
	Eigen::Vector3f n0, n1, n2;
	double angle0, angle1, angle2;
	calRotation(eigenVectorsPCA.col(0), model_eigenVectorsPCA.col(0), angle0, n0);
	calRotation(eigenVectorsPCA.col(1), model_eigenVectorsPCA.col(1), angle1, n1);
	calRotation(eigenVectorsPCA.col(2), model_eigenVectorsPCA.col(2), angle2, n2);
	Eigen::Matrix4f transform0(Eigen::Matrix4f::Identity());
	Eigen::Matrix4f transform1(Eigen::Matrix4f::Identity());
	Eigen::Matrix4f transform2(Eigen::Matrix4f::Identity());
	transform0 = RodriguesMatrixTranslation(n0, angle0);
	transform1 = RodriguesMatrixTranslation(n1, angle1);
	transform2 = RodriguesMatrixTranslation(n2, angle2);
	pcl::transformPointCloud(*source_t, *translationCloud, transform2);  //源点云整体旋转,最大主方向对齐
	pcl::transformPointCloud(*translationCloud, *translationCloud, transform0);  //源点云整体旋转,最小主方向对齐
	//pcl::transformPointCloud(*translationCloud, *translationCloud, transform1);  //源点云整体旋转,

	pcl::visualization::PCLVisualizer viewer("PCLVisualizer");
	viewer.initCameraParameters();

	int v1(0);
	viewer.createViewPort(0.0, 0.0, 0.5, 1.0, v1);
	viewer.setBackgroundColor(128.0 / 255.0, 138.0 / 255.0, 135.0 / 255.0, v1);
	viewer.addText("Cloud before transforming", 10, 10, "v1 test", v1);
	viewer.addCoordinateSystem(0.5, v1);
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color_v1(target, 0, 255, 0);
	viewer.addPointCloud<pcl::PointXYZ>(target, color_v1, "color_v1", v1);
	viewer.addPointCloud<pcl::PointXYZ>(source, "source", v1);

	int v2(0);
	viewer.createViewPort(0.5, 0.0, 1.0, 1.0, v2);
	viewer.setBackgroundColor(128.0 / 255.0, 138.0 / 255.0, 135.0 / 255.0, v2);
	viewer.addText("Cloud after transforming", 10, 10, "v2 test", v2);
	viewer.addCoordinateSystem(0.5, v2);
	pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color_v2(target_t, 0, 255, 0);
	viewer.addPointCloud<pcl::PointXYZ>(target_t, color_v2, "color_v2", v2);
	viewer.addPointCloud<pcl::PointXYZ>(translationCloud, "translationCloud", v2);

	while (!viewer.wasStopped())
	{
		//在此处可以添加其他处理  
		viewer.spinOnce(100);
	}
	return 0;
}

//计算向量u与向量v之间的夹角
void calRotation(Eigen::Vector3f u, Eigen::Vector3f v, double &angle, Eigen::Vector3f &vec)
{
	angle = acos(u.dot(v) / (u.norm()*v.norm()));
	if (angle > M_PI / 2)
	{
		u = -u;
		angle = M_PI - angle;
	}
	float i, j, k;
	i = u(1)*v(2) - u(2)*v(1), j = v(0)*u(2) - v(2)*u(0), k = u(0)*v(1) - u(1)*v(0);
	vec << i, j, k;
	double value = sqrt(i*i + j*j + k*k);
	vec(0) = vec(0) / value;
	vec(1) = vec(1) / value;
	vec(2) = vec(2) / value;
}

//获取罗德里格斯旋转矩阵
Eigen::Matrix4f RodriguesMatrixTranslation(Eigen::Vector3f n, double angle)
{
	//罗德里格斯公式求旋转矩阵
	Eigen::Matrix4f x_transform(Eigen::Matrix4f::Identity());
	x_transform(0, 0) = cos(angle) + n(0)*n(0)*(1 - cos(angle));
	x_transform(1, 0) = n(2)*sin(angle) + n(0)*n(1)*(1 - cos(angle));
	x_transform(2, 0) = -n(1)*sin(angle) + n(0)*n(2)*(1 - cos(angle));
	x_transform(0, 1) = n(0)*n(1)*(1 - cos(angle)) - n(2)*sin(angle);
	x_transform(1, 1) = cos(angle) + n(1)*n(1)*(1 - cos(angle));
	x_transform(2, 1) = n(0)*sin(angle) + n(1)*n(2)*(1 - cos(angle));
	x_transform(0, 2) = n(1)*sin(angle) + n(0)*n(2)*(1 - cos(angle));
	x_transform(1, 2) = -n(0)*sin(angle) + n(1)*n(2)*(1 - cos(angle));
	x_transform(2, 2) = cos(angle) + n(2)*n(2)*(1 - cos(angle));

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

PCL点云库——PCA粗配准 的相关文章

  • C++中 std::vector 的6种初始化方法

    1 vector lt int gt list1 默认初始化 xff0c 最常用 此时 xff0c vector为空 xff0c size为0 xff0c 表明容器中没有元素 xff0c 而且 capacity 也返回 0 xff0c 意味
  • MIMO雷达处理1

    参考文献 MIMO RADAR SIGNAL PROCESSING 以下为我自己的理解 xff0c 如有问题 xff0c 请指出 目录 初步分析虚拟阵列123 确认目标数 初步分析 MIMO radar与相控阵雷达区别在于MIMO中的各天线
  • AndroidStudio生成aar包和如何使用aar包

    我用的是android studio 2 0正式版 1 简介 aar包是Android studio下打包android工程中src res lib后生成的aar文件 xff0c aar包导入其他android studio 工程后 xff
  • C++智能指针详解:shared_ptr

    C 43 43 没有内存回收机制 xff0c 每次程序员new出来的对象需要手动delete xff0c 流程复杂时可能会漏掉delete xff0c 导致内存泄漏 于是C 43 43 引入智能指针 xff0c 可用于动态资源管理 xff0
  • C++算法题:关于树的算法

    问题1 xff1a 输入一棵二元查找树 xff0c 将该二元查找树转换成一个排序的双向链表 要求不能创建任何新的结点 xff0c 只调整指针的指向 什么是二元查找树 xff1f 比如 xff1a 转换成双向链表的顺序是 xff1a 1 3
  • C++算法题:递归和栈的算法

    问题1 xff1a 跳台阶问题 具体描述 xff0c 一个台阶总共有n级 xff0c 如果一次可以跳1级 xff0c 也可以跳2级 求总共有多少总跳法 xff0c 并分析算法的时间杂度 相当于从下往上跳 xff0c 最后剩一个 xff08
  • Linux的.service服务 实现程序开机自启

    一 service文件的位置 所有可用的单元文件存放在 lib systemd system 和 etc systemd system 目录 我们需要在 lib systemd system 下存放 service文件 xff0c 当sys
  • 计算机网络 复习提纲(完整版)

    第一章 概述 计算机网络 xff1a 利用通信线路和通信设备 xff0c 将地理位置和功能不同的多台计算机互联起来 xff0c 用完善的网络软件实现资源共享和信息传递的网络 组成 xff1a 计算机 xff0c 网络操作系统 xff0c 传
  • 无人机多任务寻径仿真软件与实验平台(一)

    项目背景 xff1a 近年来 xff0c 无人机的应用领域已经得到了极大的拓展 xff0c 旋翼无人机凭借较大的载荷 xff0c 稳定的飞行状态与对高空环境的高度适应 xff0c 成为了应用最为广泛的一类无人机 在欧洲 xff0c 北美洲等
  • 无人机实验平台(七) 实验平台的坐标转换(上)

    为什么要做坐标转换 xff1f 大疆提供的sdk中指出 xff0c 无人机通常情况下通过两个坐标系来控制方向 xff1a 自身坐标系 xff08 Body xff09 和地面坐标系 xff08 N E D xff09 这两个坐标系可以相互转
  • 无人机实验平台(十) 室内悬停问题

    VirtualStick Mode VirtualStick Mode是Sdk提供的一种底层控制模式 xff0c 通过模拟物理摇杆的运动向无人机按照一定频率发送摇杆差分信息 xff0c 使得无人机按照类似于被物理摇杆控制的方式运行 xff0
  • 第30章 ADC—电压采集—零死角玩转STM32-F429系列

    第30章 ADC 电压采集 全套 200 集视频教程和 1000 页 PDF 教程请到秉火论坛下载 xff1a www firebbs cn 野火视频教程优酷观看网址 xff1a http i youku com firege 本章参考资料
  • 大数据安全考试提纲

    范围划得虽大 xff0c 但是主题不多 xff0c 和往常一样记录一下重点 考试范围 1 大数据安全概念及目标 2 传统访问控制技术和基于密码的访问控制技术 3 角色挖掘的算法 4 对称密码 xff0c 非对称密码 xff0c hash算法
  • 算法设计与分析(小总结)

    原先一直没注意这一门 xff0c 大概是因为学这些算法的时候 xff0c 板子都不知道背多少遍了 可是考试毕竟不一样 xff0c 如果来个证明很容易抓瞎 看了往年的试题 xff0c 可能确实因为难度高 xff0c 范围一缩再缩 xff0c
  • 软件测试技术

    引论 为什么进行软件测试 xff1f 软件存在缺陷 xff0c 只有通过测试才可以发现缺陷 xff0c 只有发现缺陷才能把缺陷从产品中清除出去 软件中缺陷带来的损失是巨大的 测试是所有工程学科的基本组成单元 软件测试 xff1a 验证 43
  • c语言自定义tcp协议实现socket通信(windows版本)

    前面一篇博客介绍了mac linux下通过C语言自定义协议实现socket通信的示例 xff0c 因为大部分api与windows还有很多区别 xff0c 这里就特意把windows下的tcp通信实例给介绍一下 无论是linux xff0c
  • opencv for java给图片添加水印中文问题

    opencv提供的给图片添加文字的方法Imgproc putText 可以给图片添加文字 xff0c 最后类似一个添加水印的效果 xff0c 但是这个方法对中文支持不好 xff0c 在没有字体支持的情况下 xff0c 默认中文显示 如下图所
  • 社区版Intellij IDEA安装Spring Boot Assistant插件解决yml无提示问题

    如题所示 xff0c 我们如果个人使用免费社区版的IDEA xff0c 它缺失了很多功能 xff0c 使用起来没有专业版那么强大 xff0c 比如无法直接创建springbootinit项目 xff0c spring配置yml文件没有提示
  • IDEA安装spotbugs插件替代findbugs插件

    相信最近想在IDEA上安装findbugs插件的朋友 xff0c 遇到与我一样的问题 xff0c findbugs与IDEA不兼容 xff1a https plugins jetbrains com plugin 3847 findbugs
  • 第40章 CAN—通讯实验—零死角玩转STM32-F429系列

    第40章 CAN 通讯实验 全套 200 集视频教程和 1000 页 PDF 教程请到秉火论坛下载 xff1a www firebbs cn 野火视频教程优酷观看网址 xff1a http i youku com firege 本章参考资料

随机推荐

  • easyexcel读取excel合并单元格数据

    普通的excel列表 xff0c easyexcel读取是没有什么问题的 但是 xff0c 如果有合并单元格 xff0c 那么它读取的时候 xff0c 能获取数据 xff0c 但是数据是不完整的 如下所示的单元格数据 xff1a 我们通过简
  • clion + opencv环境搭建

    clion是一个jetbrains提供的c 43 43 开发环境 xff0c 和idea pycharm等开发工具类似 xff0c 界面有很多相似的地方 clion内置了一个mingw的编译环境 xff0c 自带了gcc g 43 43 等
  • ChatGLM-6B本地cpu部署

    ChatGLM 6B是清华团队研发的机器人对话系统 xff0c 类似ChatGPT xff0c 但是实际相差很多 xff0c 可以当作一个简单的ChatGPT ChatGLM部署默认是支持GPU加速 xff0c 内存需要32G以上 普通的机
  • java通过HttpServletRequest获取post请求中的body内容

    在java web应用中 xff0c 我们如何获取post请求body中的内容 xff1f 以及需要注意的问题 通常利用request获取参数可以直接通过req getParameter name 的方式获取url上面或者ajax data
  • Your password does not satisfy the current policy requirements解决办法

    mysql5 7 x安装以后 xff0c 想修改随机生成的密码为简单容易记忆的密码 xff0c 如root 123456等 xff0c 这时候通过修改密码的几种方式都不行 xff0c 出现密码不符合当前安全策略要求 为了解决这种问题 xff
  • 用一条SQL语句查询出每门课都大于80分的学生姓名

    两道sql题 xff1a 1 用一条SQL语句查询出每门课都大于80分的学生姓名 2 删除除了自动编号不同 xff0c 其他都相同的学生冗余信息 第一题数据如下 xff1a 分析 xff1a 每门课都大于80分 xff0c 就是说学生最低分
  • ajax通过post方法传数组

    ajax在web项目开发中经常会用到 xff0c 平时我们传递数据 xff0c 基本都是一个参数名对应一个参数值 xff0c 后端通过参数名就可以得到参数 xff0c 从而进行相关逻辑处理 xff0c 但是有时候我们会遇到批量操作 xff0
  • “操作无法完成因为其中的文件夹或文件已在另一个程序中打开”解决办法

    在windows系统中 xff0c 我们经常会遇到这样一个问题 xff1a 删除某一个文件或者文件夹 xff0c 被提醒 xff1a 操作无法完成 xff0c 因为其中的文件夹或文件已在另一个程序中打开 这个时候我们一般会先检查是否真的有程
  • 几种常见mybatis分页实现

    mybatis框架分页实现 xff0c 有几种方式 xff0c 最简单的就是利用原生的sql关键字limit来实现 xff0c 还有一种就是利用interceptor来拼接sql xff0c 实现和limit一样的功能 xff0c 再一个就
  • curl发送POST方法类型带body参数请求以及发送上传文件请求

    curl在实际中会被postman等替代 xff0c 但是他仍然是一个快速的模拟http请求的工具 xff0c 而且也有他不可替代的理由 xff0c 使用简单 xff0c 在命令行下就可以完成 今天不是介绍如何使用curl模拟各种GET P
  • 第45章 DCMI—OV2640摄像头—零死角玩转STM32-F429系列

    第45章 DCMI OV2640摄像头 全套 200 集视频教程和 1000 页 PDF 教程请到秉火论坛下载 xff1a www firebbs cn 野火视频教程优酷观看网址 xff1a http i youku com firege
  • 技术分享|探究群体智能—基于UWB定位技术的无人机集群协同

    随着无人机性能水平提高 xff0c 无人机在民用类和军事类活动中的使用越来越广泛 由于无人机飞行环境和任务难度不同 xff0c 单架无人机因为自身动力和负荷能力很难独自完成任务 xff0c 无人机集群协同作业则是当前科技现代化的任务要求 集
  • 技术分享 | 基于室外RTK/GPS定位系统下的无人机集群协同

    在自然界中 xff0c 为弥补个体能力的不足 xff0c 诸多生物种群能通过个体相互之间的交流与合作呈现出某种群体行为 xff0c 比如鱼群结群游弋 鸟群聚集迁徙以及蚂蚁协同搬运等 受此激励 xff0c 人们希望开发像鸟群 鱼群一样自由集结
  • STL学习系列之一——标准模板库STL介绍

    说明 xff1a 此文为连载版 xff0c 今天学习STL的介绍 1 STL介绍 标准模板库STL是当今每个从事C 43 43 编程的人需要掌握的技术 xff0c 所有很有必要总结下 本文将介绍STL并探讨它的三个主要概念 xff1a 容器
  • 如何在cmakelist中,find_package取指定路径中查找

    在开发中 xff0c 最常遇到环境问题 xff0c 这个opencv版本不对 xff0c 那个pcl版本不对 xff0c 如果将原系统目录下的库卸载后重装新的版本 xff0c 往往会出现一些意想不到的事 xff0c 费时费力 我常常这样做
  • MFC模型树控件TreeCtrl实现按下Ctrl键多选,按下Shift键连选

    MFC模型树控件TreeCtrl实现按下Ctrl键多选 xff0c 按下Shift键连选 MFC的List Box只需要将控件属性中的Selection项设置为Extended xff0c 即可实现Ctrl键多选和Shift键连选 xff1
  • PCL点云库——欧式聚类分割

    欧式聚类分割 pcl EuclideanClusterExtraction是基于欧式距离提取集群的方法 xff0c 仅依据距离 xff0c 将小于距离阈值的点云作为一个集群 具体的实现方法大致是 xff1a 1 找到空间中某点p10 xff
  • PCL点云库——旋转平移矩阵

    旋转平移矩阵 点云摆正 点云配准等点云操作实质上是对点云进行旋转平移 xff0c 使点云变换至目标位姿 PCL中使用的是矩阵乘列向量的计算方法 下面分别给出了点A x y z 绕X轴 Y轴 Z轴逆时针旋转角度 的示意图与旋转矩阵 xff08
  • PCL点云库——点云法线估计

    点云法线估计 PCL中的所有点云的法线都是指向视点的 xff0c 视点坐标默认为 0 0 0 xff0c 对视点进行设置 xff0c 则可对法线进行定向 如图1与图2所示 xff0c 分别为斯坦福兔子在视点坐标为 10 10 10 与 10
  • PCL点云库——PCA粗配准

    PCA粗配准 主成分分析法 Principal Component Analysis xff0c 简称PCA 是使数据简化的算法 xff0c 通过揭露数据内部的主要分布方向 xff0c 减少了数据集的维数 xff0c 从而保留了点云集中贡献