pcl协方差计算精度

news2024/11/16 18:05:38

最近在计算法线的时候发现法线的结果偏差很大,经过分析得到在计算点云协方差矩阵时,选择不同的方法会导致不同的结果。下面是测试过程:
1、测试点云
点云
点云是中间一点的邻域点,是从上往下看,法线的方向近似为(0,0,1)也就是沿着Z轴方向。

第一种方法:按照公式计算

1、先计算中心点

pcl::compute3DCentroid(*cloud, centroid);
 4.26244
-9.52218
 7.24367
       1

2、计算去中心化的点云

pcl::demeanPointCloud(*cloud, centroid, cloud_demean);

3、计算协方差矩阵

covariance_matrix = static_cast<Eigen::Matrix3f> (cloud_demean.topRows<3>() * cloud_demean.topRows<3>().transpose());
    1.56941  0.00116825  0.00467487
 0.00116825     1.57477  0.00205587
 0.00467487  0.00205587 0.000789469

4、特征向量

Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> evd(covariance_matrix);
0.000772649
    1.56918
    1.57502
-0.00297917   -0.978679    0.205372
 -0.0013039    0.205377    0.978682
   0.999995 -0.00264787  0.00188798

注:以上的协方差矩阵并没有除以数据的个数n,下面为除以n的结果

covariance_matrix /= cloud->size();
 0.00039853  2.9666e-07 1.18712e-06
 2.9666e-07 0.000399891 5.22061e-07
1.18712e-06 5.22061e-07 2.00475e-07

相应的特征值和特征向量

evd.compute(covariance_matrix);
1.96266e-07
0.000398471
0.000399955
-0.00297925    -0.97868    0.205369
-0.00130392    0.205373    0.978683
   0.999995 -0.00264789  0.00188795

可以看出两者获取的特征向量是相同的,由于计算误差的问题,导致小数点后四五位后有差异,可以接受。

第二种方法:对公式进行化简

计算代码如下:

		for (size_t i = 0; i < point_count; ++i)
		{
			accu[0] += cloud[i].x * cloud[i].x;
			accu[1] += cloud[i].x * cloud[i].y;
			accu[2] += cloud[i].x * cloud[i].z;
			accu[3] += cloud[i].y * cloud[i].y; // 4
			accu[4] += cloud[i].y * cloud[i].z; // 5
			accu[5] += cloud[i].z * cloud[i].z; // 8
			accu[6] += cloud[i].x;
			accu[7] += cloud[i].y;
			accu[8] += cloud[i].z;
		}
				centroid[0] = accu[6]; centroid[1] = accu[7]; centroid[2] = accu[8];
		centroid[3] = 1;
		covariance_matrix.coeffRef(0) = accu[0] - accu[6] * accu[6];
		covariance_matrix.coeffRef(1) = accu[1] - accu[6] * accu[7];
		covariance_matrix.coeffRef(2) = accu[2] - accu[6] * accu[8];
		covariance_matrix.coeffRef(4) = accu[3] - accu[7] * accu[7];
		covariance_matrix.coeffRef(5) = accu[4] - accu[7] * accu[8];
		covariance_matrix.coeffRef(8) = accu[5] - accu[8] * accu[8];
		covariance_matrix.coeffRef(3) = covariance_matrix.coeff(1);
		covariance_matrix.coeffRef(6) = covariance_matrix.coeff(2);
		covariance_matrix.coeffRef(7) = covariance_matrix.coeff(5);

可以确定这里的计算方法是没有问题的。根据公式可以得到,此方法计算得到的是除以数据n的结果

pcl::computeMeanAndCovarianceMatrix(*cloud, covariance_matrix1, centroid1);
 0.000402451  6.10352e-05 -0.000331879
 6.10352e-05  9.91821e-05  0.000862122
-0.000331879  0.000862122  -0.00104523

计算特征值和特征向量

Eigen::SelfAdjointEigenSolver<Eigen::Matrix3f> evd1(covariance_matrix1);
-0.00156048
0.000393528
0.000623361
 0.161933  0.843809  0.511628
-0.459571    0.5233 -0.717601
 0.873254  0.118926  -0.47253

从以上结果可以看出,这里的结果明显是有问题的,对称矩阵的特征值都是正的。
下面将数据换成double类型进行测试:

Eigen::SelfAdjointEigenSolver<Eigen::Matrix3d> evd1(covariance_matrix1);
协方差:
0.000398508 2.87849e-07   1.166e-06
2.87849e-07 0.000399546 4.86634e-07
  1.166e-06 4.86634e-07 4.04394e-08
特征值:
3.64367e-08
0.000398436
0.000399622
特征向量:
0.00292528    0.96767   0.252203
0.00121596  -0.252208   0.967672
 -0.999995 0.00252404 0.00191443

可以看出,以上结果是正确的。

总结:

分析产生以上结果的原因:float类型在计算平方时,由于有效数字较少,当平方很大时,小数点后面的部分就被忽略,造成除以n之后的结果变得精度不够。
逐步对比float和double两个类型的计算结果
结果

上侧为double,下侧为float
之所以产生这样的结果,是由于未中心化的点云数据坐标值较大,直接进行平方运算数值就会变得很大,由于float的有效数字9位,
4.26249981的平方,
double计算结果:18.168904623985327
float计算结果:18.1689053
这些一点点的差异最终就会造成结果造成很大的误差。
由于方法一只有一次乘法,相对而言计算结果会好点。

pcl协方差计算中有介绍

  /** \brief Compute the normalized 3x3 covariance matrix and the centroid of a given set of points in a single loop.
    * Normalized means that every entry has been divided by the number of entries in indices.
    * For small number of points, or if you want explicitely the sample-variance, scale the covariance matrix
    * with n / (n-1), where n is the number of points used to calculate the covariance matrix and is returned by this function.
    * \note ***This method is theoretically exact. However using float for internal calculations reduces the accuracy but increases the efficiency.***
    * \param[in] cloud the input point cloud
    * \param[out] covariance_matrix the resultant 3x3 covariance matrix
    * \param[out] centroid the centroid of the set of points in the cloud
    * \return number of valid point used to determine the covariance matrix.
    * In case of dense point clouds, this is the same as the size of input cloud.
    * \ingroup common
    */

其中说明了:这个方法理论上是准确的。然而,使用浮点数进行内部计算降低了精度,但提高了效率。

注意:PCL法线估计方法,使用的就是方法二,导致计算结果偏差很大。怎么改进呢?
修改如下代码:

		inline bool
			computePointNormal(const pcl::PointCloud<PointInT> &cloud, const std::vector<int> &indices,
				float &nx, float &ny, float &nz, float &curvature)
		{
			
			if (indices.size() < 3 ||
				compute3DCentroid(cloud, indices, xyz_centroid_) == 0||
				computeCovarianceMatrix(cloud, indices, xyz_centroid_, covariance_matrix_)==0)
			{				
				nx = ny = nz = curvature = std::numeric_limits<float>::quiet_NaN();
				return false;				
			}

			// Get the plane normal and surface curvature
			solvePlaneParameters(covariance_matrix_, nx, ny, nz, curvature);
			return true;
		}

先计算中心点,然后计算协方差。
这样修改后,计算的结果是正确的。

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

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

相关文章

操作股票下单接口的执行流程代码分享

股票下单接口也相当于是程序化交易&#xff0c;可以根据用户的意愿&#xff0c;定制的交易计划去执行&#xff0c;还可以在一定程度上战胜人性的弱点&#xff0c;下面来看看操作股票下单接口的执行流程代码分享&#xff1a; // 委托下单 // category: 0>买入, 1>卖出,…

DataWhale - OpenCV教程01

MetaData: Author:Link: https://vxr.xet.tech/s/49dV3oPublisher:Date: 2022-12-12 - 16:28 笔记记录的时间 ✅ 2022-12-12 Tag: 软件技能 计算机视觉的发展历史&#xff1a; 1982年马尔的书《视觉》&#xff0c;将视觉的任务分为两类&#xff1a;重建和识别。2012年&#…

十年老码农现身说法:凛冬将至,为什么我不劝退互联网

大家好&#xff0c;我是xxx 这两天在B站刷到好多吐槽秋招拿不到offer的视频&#xff0c;其中有几个看得我又好笑又同情。 有一个老哥说自己19年硕士毕业的时候想要进华为但差了临门一脚没能拿到offer&#xff0c;非常遗憾&#xff0c;最后觉得一定是自己不够强所以没能如愿。…

如何运行Scala Object

一 、问题描述 执行一个Scala Obejct 程序&#xff0c;Java 沿袭过来的当然直接用main&#xff0c;Scala 官方还提供了另外的一种方法 定义的object extend App trait在object中定义好main() 二、Scala CookBook 这是一段对《 Scala Cookbook》的摘抄&#xff0c;6.4 如何运…

人工智能时代,Python还不快学起来吗

“是时候学点Python了”。作为一名不怎么安分的程序员&#xff0c;你或许觉得&#xff0c;产生这样的想法并不奇怪&#xff0c;但学习Python却是出于自己对工作现状以及如何应对未来挑战所作出的思考。读过我以前博客的朋友&#xff0c;可能都知道&#xff0c;我推崇软件领域中…

Android开发黑白灰模式和夜间模式设置

接口数据来源鸿洋大神“玩安卓”网站&#xff1a;https://wanandroid.com/ 黑白灰正常模式和黑白灰夜间模式截图 夜间模式与正常模式截图 黑白灰与原色模式设置 /*** 设置灰白色*/protected void setGrayScreen() {Paint paint new Paint();ColorMatrix cm new ColorMatrix(…

八十七氟癸基笼状聚倍半硅氧烷poss

八十七氟癸基笼状聚倍半硅氧烷poss 八十七氟癸基笼状聚倍半硅氧烷是一种含氟有机、无机杂化的笼状聚倍半硅氧烷&#xff0c;可用于可用于热塑性塑料体系改性&#xff0c;降低其表面能。也可用于自修复超疏水材料。 应用领域 1、塑料改性&#xff0c;降低表面张力 2、自修复…

【温故而知新】分布式系统(二)

分布式系统的 CAP 理论 时间&#xff1a;2022年12月12日 作者&#xff1a;小蒋聊技术 【温故而知新】分布式系统&#xff08;二&#xff09;分布式系统的 CAP 理论_小蒋聊技术_免费在线阅读收听下载 - 喜马拉雅手机版欢迎收听小蒋聊技术的其他类最新章节声音“【温故而知新】分…

漏洞深度分析|Thinkphp 多语言 RCE

项目介绍 ThinkPHP 是一个快速、简单的面向对象的轻量级 PHP 开发框架&#xff0c;创立于2006年初&#xff0c;遵循Apache2开源协议发布&#xff0c;是为了敏捷WEB应用开发和简化企业应用开发而诞生的。 根据目前FOFA系统最新数据&#xff08;一年内数据&#xff09;&#xf…

基于昇思MindSpore,实现使用胶囊网络的图像描述生成算法

项目链接 https://github.com/Liu-Yuanqiu/acn_mindspore 项目描述 图像描述生成算法 人类可以轻易的使用语言来描述所看到的场景&#xff0c;但是计算机却很难做到&#xff0c;图像描述生成任务的目的就是教会计算机如何描述所看到的内容&#xff0c;其中涉及到了对视觉信…

JavaOOP面试题(108道)

✅作者简介&#xff1a;热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏&#xff1a;Java面试题…

mybatis以及mybatisplus批量插入问题

1. 思路分析&#xff1a; 批量插入是我们日常开放经常会使用到的场景&#xff0c;一般情况下我们也会有两种方案进行实施&#xff0c;如下所示。 方案一 就是用 for 循环循环插入&#xff1a; 优点&#xff1a;JDBC 中的 PreparedStatement 有预编译功能&#xff0c;预编译之…

vue3较vue不同的地方

自定义指令的区别&#xff1a; vue2的写法&#xff1a; Vue.directive(scroll, {}) //scroll是指令名称 vue3的写法&#xff1a; 定义全局的&#xff1a;在main.js文件中定义&#xff1a; createApp(App).directive("hello",{}).use(store).use(router).mount(#…

小程序import及include引用的简单理解

场景&#xff1a;在小程序中&#xff0c;WXML 提供两种文件引用方式import和include 我自己记录下自己的一些简单理解 官方文档&#xff1a;引用 | 微信开放文档 第一&#xff1a;import import&#xff0c;就是可以引入自定义指定的template模板 比如&#xff1a;我在import页…

stm32f767之ADC

一&#xff0c;基本介绍 1&#xff0c;ADC时钟。 ADC时钟一般常用来自于经可编程预分频器分频的APB2 时钟&#xff0c;该预分频器允许ADC 在fPCLK2/2、 /4、/6 或/8 下工作。ADCCLK 的最大值限制。2&#xff0c;ADC通道。 有16 条复用通道。我的理解是每个ADC&#xff08;1&…

气泡水位计安装示意图 气泡水位计工作原理

气泡式水位计测量精度高&#xff0c;免气瓶&#xff0c;免测井&#xff0c;免维护&#xff0c;抗振动&#xff0c;寿命长&#xff0c;特别适用于流动水体、大中小河流等水深比较大的场合。具有安装简单&#xff0c;操作、组网灵活&#xff0c;尤其是无井水位测量最理想的水位监…

城市燃气系统安全解决方案

汽车制造业 MES系统 DNC系统 生产 安全域1 管理层 工控安全隔离装置 交换机 安全配置核查系统 HMI 历史数据库 运行监控系统 实时数据库 打印机过程 安全域2 监控层 工控漏洞扫描系统 安全交换机 工控安全审计系统 工控入侵检测系统工程师站 A 操作员站 A 实时数据库A 操作员站…

[附源码]Python计算机毕业设计SSM基于的冠状病毒疫情防控资讯交流推荐网站(程序+LW)

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

stream_open函数分析

在讲 stream_open() 函数之前&#xff0c;需要先了解 stream_open() 里面使用到的一些基本的数据结构。如下&#xff1a; 第一个数据结构是 struct VideoState &#xff0c;VideoState 可以说是播放器的全局管理器。字段非常多&#xff0c;时钟&#xff0c;队列&#xff0c;解…

Android 11 的状态栏的隐藏

概述 Android 11 的状态栏与导航栏较之前的版本有较大的差异, 在Android 7.0 SystemUI 状态/导航栏的隐藏与显示中所描述的部分内容已不再适用. 比如, 自动隐藏的时间, 隐藏的动画, 较之前的版本已面目全非, 本文将对隐藏状态栏部分的内容进行一些补充. APP如何隐藏状态栏 参…