经典ICP算法的问题

最近可能要用三维点云实现一个三维场景重建的功能,从经典的ICP算法开始,啃了一些文档,对其原理也是一知半解。

 

迭代最近点算法综述

大致参考了这份文档之后,照流程用MATLAB实现了一个简单的ICP算法,首先是发现这份文档中一个明显的错误,

公式6

 

求两个点集的协方差,其中(Pi-p)和(Qi-p')分别求两个点集的各点与重心的差,都是(3*1)向量,这是不能相乘的,根据后文推断,此物的结果应为(3*3)矩阵,所以我大(zuo)胆(si)的改为(Pi-p)' * (Qi-p'),做一次尝试。

 

Matlab代码如下:

%%% ICP迭代最近点算法function [sourcePoint,aimPoint,distance] = ICPiterator( sourcePoint , targetPoint )
%%% 获得匹配点集,重心
aimPoint = getAimPoint(sourcePoint,targetPoint);

sourcePointCentre = getCentre(sourcePoint);
aimPointCentre = getCentre(aimPoint);

%%% 平移矩阵
T = getTranslation(aimPointCentre,sourcePointCentre);

%%% 中心化
midSourcePoint = centreTransform(sourcePoint, sourcePointCentre);
midAimPoint = centreTransform(aimPoint, aimPointCentre);

%%%旋转四元数
quaternion = getRevolveQuaternion(midSourcePoint,midAimPoint);

%%%旋转矩阵
revolveMatrix = getRevolveMatrix(quaternion);

%%%变换sourcePoint = midSourcePoint * revolveMatrix;
sourcePoint = counterCentreTransform(sourcePoint,sourcePointCentre);

range = length(sourcePoint);
for i = 1:1:rangesourcePoint(i,:) = sourcePoint(i,:) + T;
end%%%阈值判定,欧拉距离和
distance = getDistance(sourcePoint,aimPoint);
    
end%%% 点对搜索匹配,得到匹配点集
function [aimPoint] = getAimPoint( sourcePoint , targetPoint ) 
rangeS = length(sourcePoint );
rangeT = length(targetPoint);
aimPoint = zeros(rangeS,3);

for i = 1:1:rangeSminDistance = getDistance(sourcePoint(i,:),targetPoint(1,:));
    aimPoint(i,:) = targetPoint(1,:);
    for j = 1:1:rangeTdistance = getDistance(sourcePoint(i,:),targetPoint(j,:));
        if distance < minDistanceminDistance = distance;
            aimPoint(i,:) = targetPoint(j,:);
        endend
end
end%%%旋转四元数
function [quaternion] = getRevolveQuaternion( sourcePoint , targetPoint )%%% 协方差pp = sourcePoint' * targetPoint;
    range = size(sourcePoint,1);
    pp = pp / range;
    %%% 反对称矩阵dissymmetryMatrix = pp - pp' ;
    %%% 列向量deltadelta = [dissymmetryMatrix(2,3) ; dissymmetryMatrix(3,1) ; dissymmetryMatrix(1,2)];
    %%%对称矩阵QQ = [ trace(pp) delta' ; delta   pp + pp' - trace(pp)*eye(3) ];
    %%%最大特征值,对应特征向量即为旋转四元数maxEigenvalues = max(eig(Q));
    quaternion = null(Q - maxEigenvalues*eye(length(Q)));

end%%% 旋转矩阵
function [revolveMatrix] = getRevolveMatrix(quaternion)revolveMatrix = [ quaternion(1,1)^2 + quaternion(2,1)^2 - quaternion(3,1)^2 - quaternion(4,1)^2    2 * (quaternion(2,1)*quaternion(3,1) - quaternion(1,1)*quaternion(4,1))  2 * (quaternion(2,1)*quaternion(4,1) + quaternion(1,1)*quaternion(3,1));2 * (quaternion(2,1)*quaternion(3,1) + quaternion(1,1)*quaternion(4,1))    quaternion(1,1)^2 - quaternion(2,1)^2 + quaternion(3,1)^2 - quaternion(4,1)^2     2 * (quaternion(3,1)*quaternion(4,1) - quaternion(1,1)*quaternion(2,1));
                        2 * (quaternion(2,1)*quaternion(4,1) - quaternion(1,1)*quaternion(3,1))  2 * (quaternion(3,1)*quaternion(4,1) + quaternion(1,1)*quaternion(2,1))   quaternion(1,1)^2 - quaternion(2,1)^2 - quaternion(3,1)^2 + quaternion(4,1)^2  ];
end%%% 点集重心
function [centre] = getCentre( point )range = length(point);
    centre = sum(point)/range;
end%%% 获取平移矩阵
function [T] = getTranslation( aimPointCentre , sourcePointCentre )T = aimPointCentre - sourcePointCentre;
end%%% 点集中心化
function [point] = centreTransform(point,centre)
range = size(point,1);
for i = 1:1:rangepoint(i,:) = point(i,:) - centre;    
end
endfunction [point] = counterCentreTransform(point,centre)
range = size(point,1);
for i = 1:1:rangepoint(i,:) = point(i,:) + centre;    
end
end%%% 计算两点距离的平方,即欧拉距离和
function [distance] = getDistance(point1,point2)distance = (point1(1,1) - point2(1,1))^2 + (point1(1,2) - point2(1,2))^2 + (point1(1,3) - point2(1,3))^2;
end

 

为了看到迭代过程,这段代码每次只是进行一次迭代,但是实际情况下需要不断迭代,直到两点集的方差收敛,达到拟合要求。

 

用随机数生成了一个含一百个点的点集A,并对A进行一次随机的空间变化,得到B,这样A,B是完全可以拟合的两个点集;

 

点集A:

 

点集B:

 

用A,B来验证算法能不能实现点集的拟合。

 

试验了几次之后,发现无法收敛:

 

问题应该出在旋转四元数和旋转矩阵求解上,这块是一直没能理解透彻的部分。

 

转载于:https://www.cnblogs.com/moranBlogs/p/3798257.html

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

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

相关文章

php 405跳转,php – 返回HTTP 405的CORS预检请求

我正在尝试创建一个RESTful Web服务,并且已经停止实现PUT请求.我尝试过但未能在本网站上关注其他答案以及Mozilla的各种文章.该请求是从域wwwtest.dev-box生成的,它将转到test.dev-box(基本上是一个调用后端应用程序的前端应用程序).以下是我从Live HTTP标头中捕获的标头&#…

wowza rtsp_使用wowza和xuggler将RTMP转为RTSP

wowza rtsp注意&#xff1a;这是我们的“ Xuggler开发教程 ”系列的一部分。 大家好&#xff01; 在过去的三个月中&#xff0c;我们一直在进行电话会议项目。 我们认为&#xff0c;使用诸如Flex之类的技术的基于Web的应用程序将是此类要求苛刻的项目的最佳方法。 随着软件的复…

iOS执行时工具-cycript

cycript是大神saurik开发的一个很强大的工具&#xff0c;能够让开发人员在命令行下和应用交互&#xff0c;在执行时查看和改动应用。它确实能够帮助你破解一些应用&#xff0c;但我认为这个工具主要还是用来学习其它应用的设计&#xff08;主要是UI的设计及实现&#xff09;。 …

开启php soap,php soap 开发文档

一&#xff0e; 必备知识1.wsdl(web服务标记语言)WSDL(网络服务描述语言&#xff0c;Web Services Description Language)是一门基于 XML 的语言&#xff0c;用于描述 Web Services 以及如何对它们进行访问。具体参考请访问下面网址2.soapSOAP 是一种简单的基于 XML 的协议&…

知识点2

1. DUMMY是不是检查所有的类型的权限呢&#xff1f;PS:不是&#xff0c;dummy的意思是虚拟的意思&#xff0c;就是说权限检查的时候有这个权限检查字段&#xff0c;但是不对该字段做权限检查。AUTHORITY-CHECK OBJECT Z_BRANDID ACTVT DUMMY ID BRAND FIELD p_br…

java调用jndi出错,无法使用Java JNDI上下文查找来访问对象

我正在运行Tomcat6并希望从我的Servlet访问数据源。但我得到了javax.naming.OperationNotSupportedException: cant generate an absolute name for this namespaceat org.apache.naming.NamingContext.getNameInNamespace(NamingContext.java:772)我的context.xml在HomeContro…

java是如何实现原语的_Java中的低GC:使用原语而不是包装器

java是如何实现原语的总览 有两个很好的理由在可能的地方使用原语而不是包装器。 明晰。 通过使用原语&#xff0c;您可以清楚地知道null值是不合适的。 性能。 使用原语通常更快。 清晰度通常比性能更重要&#xff0c;并且是使用它们的最佳理由。 但是&#xff0c;本文讨论…

MFC 错误异常,用vs添加资源并为资源定义类后报错:error C2065 : 未声明的标识符...

添加了一个Dialog资源&#xff0c;修改了ID之后右击资源添加了一个类&#xff0c;在类里面有一个成员变量&#xff1a; // 对话框数据 enum { IDD IDD_GETIN }; 而在编译过程中出现报错&#xff0c;错误代号是error C2065 : 未声明的标识符&#xff0c;我的第一反应是为什么…

php 正则匹配数字范围,正则表达式之匹配数字范围

最近有个需求就是根据产品编号批量下架产品&#xff0c;需要下架日期为16-31号之间的产品&#xff0c;比如编号为B201607280023匹配表达式如下:^201607(1[6-9]|2[0-9]|3[0-1]).逻辑很简单&#xff0c;如果是必须是1或2或3开头&#xff0c;如果是1开头则后面范围为6-9&#xff0…

php 取utc时间,得到UTC时间在PHP

使用gmdate将始终返回GMTdate。 语法与date相同。一个简单的gmdate()就足够了$time time(); $check $timedate("Z",$time); echo strftime("%B %d, %Y %H:%M:%S UTC", $check);正如以前在这里回答的那样 &#xff0c;从PHP 5.2.0开始&#xff0c;您可以…

BrnShop开源网上商城第二讲:ASP.NET MVC框架

BrnShop开源网上商城第二讲&#xff1a;ASP.NET MVC框架 原文:BrnShop开源网上商城第二讲&#xff1a;ASP.NET MVC框架在团队设计BrnShop的web项目之初&#xff0c;我们碰到了两个问题&#xff0c;第一个是数据的复用和传递&#xff0c;第二个是大mvc框架和小mvc框架的选择。下…

tomcat不停机部署_Tomcat中的零停机部署(和回滚); 演练和清单

tomcat不停机部署亲爱的大家&#xff0c; 如果您认为Tomcat不能再进步&#xff0c;那您就错了。 Tomcat 7引入了所谓的并行部署 。 这是由SpringSource / VMWare贡献的。 简而言之&#xff0c;并行部署是指能够并行部署一个以上版本的Web应用程序&#xff0c;从而使所有版本都…

dataframe建一个空的,创建一个空的Pandas DataFrame,然后填充它?

我想用时间序列计算中的值迭代地填充数据框 . 所以基本上&#xff0c;我想初始化数据框&#xff0c;包括列A&#xff0c;B和时间戳行&#xff0c;全部为0或全部为NaN .然后我会添加初始值并检查此数据&#xff0c;计算前一行中的新行&#xff0c;比如行[A] [t] 行[A] [t-1] 1左…

Android给TextView和EditText等控件设置透明背景、圆角边框

第一种方法&#xff1a;在drawable文件夹下新建一个文件设置背景样式 代码&#xff1a; 在drawable文件夹下面新建text_view_border.xml <?xml version"1.0" encoding"UTF-8"?> <shape xmlns:android"http://schemas.android.com/apk/res/…

将jOOQ与JDBC比较

本文是我们学院课程的一部分&#xff0c;标题为jOOQ –类型安全的数据库查询 。 在SQL和特定关系数据库很重要的Java应用程序中&#xff0c;jOOQ是一个不错的选择。 当JPA / Hibernate抽象过多&#xff0c;JDBC过多时&#xff0c;这是一种替代方法。 它显示了一种现代的领域特…

matlab三维选取二维,基于Matlab绘制二维和三维图形以及其他图形控制函数的使用方法...

Matlab绘图强大的绘图功能是Matlab的特点之一&#xff0c;Matlab提供了一系列的绘图函数&#xff0c;用户不需要过多的考虑绘图的细节&#xff0c;只需要给出一些基本参数就能得到所需图形&#xff0c;这类函数称为高层绘图函数。此外&#xff0c;Matlab还提供了直接对图形句柄…

迭代器生成器可迭代对象_使用迭代器时如何避免ConcurrentModificationException

迭代器生成器可迭代对象Java Collection类是快速失败的&#xff0c;这意味着如果在使用迭代器遍历某个线程的同时更改了Collection&#xff0c;则iterator.next&#xff08;&#xff09;将抛出ConcurrentModificationException 。 在多线程以及单线程环境中都可能出现这种情况。…

Console命令详解,让调试js代码变得更简单

刚刚在浏览关于js方面的博客时发现这个方法挺好玩的&#xff0c;自己爽了一把。 1 <script> 2 console.time(/X(.)X/ test); 3 "XX".match(/X(.)X/); 4 console.timeEnd(/X(.)X/ test); 5 </script> 然后恶补了一下关于Firebug控制台的知识。熟练地使用…

mysql as tmp,启动mysql时显示:/tmp/mysql.sock 不存在的解决办法

启动mysql时显示&#xff1a;/tmp/mysql.sock 不存在的解决方法启动mysql时显示&#xff1a;/tmp/mysql.sock 不存在的解决方法启动mysql时报错的解决(mysql 5.0.45 redhat as43)启动mysql时报错的解决(mysql 5.0.45 redhat as 43)作者: lawzjf(http://lawzjf.itpub.net)发表于…

PHP求体重成绩函数,PHP数组

数组提出一个问题&#xff1a;一个养鸡场有6只鸡&#xff0c;他们的体重分别为3kg&#xff0c;5kg&#xff0c;1k个&#xff0c;3.4kg&#xff0c;2kg&#xff0c;6.kg请问这六只鸡的总体重是多少平均体重是多少请你用现在掌握的技术编一个程序现在我们使用现有的技术来解决问题…