g2o求解BA 第10章

1、g2o_bal_class.h
1.1 projection.h
g2o还是用图模型和边,顶点就是相机和路标,边就是观测,就是像素坐标。只不过这里的相机是由
旋转(3个参数,轴角形式,就是theta*nx,theta*ny,theta*ny),位移(3个参数),f,k1,k2.
就是之前BA模型的实现。
但是这里归一化平面坐标取得是负值,而且最后没有加cx,cy.
具体实现在projection.h中的CamProjectionWithDistortion函数实现的,而其中世界坐标转成相机坐标是由rotation.h中的函数AngleAxisRotatePoint实现的。具体参见轴角和四元数和空间点.note
1.2顶点
自定义了相机顶点和路标顶点(名字自己定),继承自g2o::BaseVertex.一个9维,Eigen::VectorXd,一个3维,Eigen::Vector3d.
跟之前一样,不一样的是有了覆盖。就是对oplusImpl函数用override进行覆盖。覆盖形式为
virtual void oplusImpl(const double* update) override{}
里面会对update进行操作,变成v,之前都是 _estimate += Eigen::Vector3d(update);
而这里update不再是Eigen::Vector3d的形式,而是变成了地图类型。
一个是Eigen::VectorXd::ConstMapType v(update,VertexCameraBAL::Dimension);
一个是Eigen::Vector3d::ConstMapType v(update);
然后_estimate+=v就可以了。
1.3边
观测值在当前图片中可以看到这个路标,通过计算描述子可以在当前图片中找到和路标匹配的特征点,这个匹配的特征点的像素坐标就是观测值。
同样还是把vertex(0)赋值给顶点camera,vertex(1)赋值给顶点point.
这里的计算误差的函数被重写了。
同样virtual void computeError() override{ }
而计算误差用了括号运算符(),在template<typename T>下。
过程是由CamProjectionWithDistortion(camera,point,predictions)得到预测值predictions,然后预测值与测量值measurement()的对应项相减得到residual[0],residual[2].
virtual void linearizeOplus() override{},这里linearizeOplus也被重写了。
同样还是先赋值顶点。然后自定义BalAutoDiff自动求导函数。
typedef ceres::internal::AutoDiff<EdgeObservationBAL,double,VertexCameraBAL::Dimension,VertexPointBAL::Dimension> BalDutoDiff,
用了ceres的autodiff,里面放的四个参数分别是边类,数据类型,两个顶点类。
定义对Camera顶点求导后的矩阵,dError_dCamera,维度Dimension*顶点的维度,应该是9.
因为过往的雅克比矩阵是2*6形式。每个误差都有一个雅可比矩阵,这里应该是每个雅可比矩阵的形式。
和对Point顶点求导后的矩阵dError_dPoint.
Eigen::Matrix<double,Dimension,VertexCameraBAL::Dimension,Eigen::RowMajor> dError_dCamera;
Eigen::Matrix<double,Dimension,VertexPointBAL::Dimension,Eigen::RowMajor> dError_dPoint.
parameters是由cam的估计值和point的估计值组成,指针形式。
jacobian是由camera的导数和point的导数组成。
使用BALAutoDiff中的Differentiate函数。放入边,参数,维度Dimension,value(它的值就是Dimension),还有要得到雅可比矩阵jacobian.
返回值是一个bool值,表示的是差分状态,也就是求导状态。
如果它为true的话,_jacobianXi就为dError_dCamera,_jacobianXj就为dError_dPoint,如果返回false,那么,_jacobianXi,_jacobianXj就设为0.
问题就是Dimension这个值具体是什么,不知道。
2.g2o_bundle.cpp
2.1BuildProblem函数
作用:给图模型添加顶点,添加边
变量:bal_problem类,指针形式,图模型optimizer,优化参数params
2.1.1添加顶点
从bal_problem中读取路标数量,相机位姿数量,相机块大小9或10(取决于旋转用四元数还是用轴角表示),路标块大小3。
造一个数raw_cameras,它是一个指针,由balProblem的cameras函数得出,这个函数的返回值是parameters,parameters为9*相机位姿的数量再加上3*路标点的数量。

做一个循环,阈值是相机位姿数量,接下来是要添加相机顶点。
类型为typedef Eigen::Map<const Eigen::VectorXd> ConstVectorRef;
值为(raw_cameras+9*i,9)
相机的估计值就是temVecCamera;估计值应该是跟相机顶点类型一样的啊。应该也是Eigen::VectorXd的。
然后顶点的估计值就是temVecCamera,id就是i(一般在for循环里,顶点id都设成i.)图模型添加相机顶点。顶点就是之前定义的类。一般指针形式,后面加new,是为了分配一个对象给它。
VertexCameraBAL* pCamera = new VertexCameraBAL();
添加路标顶点
也是造一个数指针raw_points,它的返回值是parameters+9*相机位姿数量,对每个路标点来说,
constVectorRef temVecPoint(raw_points+3*j,3)
同样设置路标顶点为pPoint,pPoint的估计值就为temVecPoint.
这里要设置路标点可以进行边缘化,也就是可以进行消元。但为什么相机没有设这个值。
图模型添加这个顶点pPoint.
这里设置路标点id为j+num_cameras,因为为了保证每个顶点都有一个对应的id.
2.1.2添加边
定义常量观测值的数量为num_observations。
定义指针observations对应的值为2*观测值的数量。
利用观测值造一个循环

设置鲁棒核函数,之所以要设置鲁棒核函数是为了平衡误差,不让二范数的误差增加的过快。鲁棒核函数里要自己设置delta值,这个delta值是,当误差的绝对值小于等于它的时候,误差函数不变。否则误函数变为delta(|e|-1/2delta).
如果输入的参数params的鲁棒性检验通过if(params.robustify)
那么设置鲁棒核函数为g2o里的huber loss函数。
g2o::RobustKernelHuber* rk=new g2o::RobustKernelHuber;
设置delta值为1.0.设置边的鲁棒核函数为rk..setDelta,.setRobustKernel().
设置边的顶点0对应的相机顶点为optimizer->vertex(camera_id),指针camera_id为观测值的数量[i]
设置边的顶点1对应的路标顶点为optimizer->vertex(point_id),指针point_id为观测值的数量[i]+相机数量.
设置其协方差矩阵也就是.setInformation,为2*2的单位矩阵。
设置其测量值为observations[2*i+0],observations[2*i+1].
图模型添加边。
设顶点,设估计值,设id,图模型添加顶点。
设边,设顶点,设协方差矩阵,设测量值,图模型添加边。

3.图模型求解
还是之前一样的过程,这里自定义类型名为BalBlockSolver,这里是造了一个函数SetSolverOptionsFromFlags,变量是bal_problem类,params参数,图模型optimizer.
先把矩阵块求解器solver_ptr,线性方程求解器linearSolver初值设为0
如果params.linear_solver的值为dense_schur,那么线性方程求解器用稠密的,也就是Dense,
如果params.linear_solver的值为sparse_schur,那么linearSolver用稀疏的,也就是Cholmod,而且设置linearSolver对矩阵排序保持稀疏性
dynamic_cast<g2o::LinearSolverCholmod<BalBlockSolver::PoseMatrixType>* >(linearSolver)->setBlockOrdering(true); 这个只在稀疏的情况下使用。
由linearSolver得到矩阵块求解器solver_ptr.
如果params.trust_region_strategy为列文伯格-马夸而特,那么梯度下降方法solver就选为列文伯格-马夸而特
如果为dogleg,那就用dogleg来做梯度下降方法solver.


g2o在做BA的优化时必须将其所有点云全部schur掉,否则会出错。其原因在于我们使用了g2o::LinearSolver<BalBlockSolver::PoseMatrixType>这个类型来指定linearsolver,其中模板参数当中的位姿矩阵类型在程序中为相机姿态参数的维度,于是BA当中schur消元后解得线性方程组必须是只含有相机姿态变量。
Ceres库则没有g20这样的限制,Ceres给了开发者很大的空间去操作自己的优化策略,它在Schur消元操作时完全不需要把所有点云都消元掉,用户可以自己编写函数选择消元哪些点云。接下来我们也会给出Ceres的BA。

 

转载于:https://www.cnblogs.com/talugirl/p/7384115.html

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

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

相关文章

宝塔面板 Windows 2012 R2 使用指南(在更新中)

第一次使用Windows系统服务器 1、安装宝塔Windows面板 For 2012 R2镜像。 从镜像市场选择 输入宝塔Windows面板 For 2012 R2进行选择&#xff0c;点击使用。 设置密码 2、使用windows电脑进行远程桌面连接

支付宝当面付接口如何计算优惠

支付宝当面付官方接口文档&#xff1a;https://docs.open.alipay.com/194/105170/ 在弄清楚如何计算优惠之前先了解下相关金额参数&#xff1a; 1、请求中金额参数total_amount&#xff1a;订单总金额&#xff0c;订单总金额&#xff0c;单位为元&#xff0c;精确到小数点后两位…

微信 公众号 JS接口安全域名 是啥 什么意思

在微信开发时&#xff0c;需要点击【公众号设置】→【功能设置】→【JS接口安全域名】填写自己的访问域名。 因为微信的安全做得比较好&#xff0c;我们根据 微信 js sdk写的函数、方法&#xff0c;只有在指定的安全域名下才能被微信唤起。 注意&#xff1a;设置完安全域后&am…

oracle知识博客链接

http://blog.csdn.net/YiQiJinBu/article/category/1100395/1 转载于:https://www.cnblogs.com/fushou/p/7387964.html

sign check fail: check Sign and Data Fail解决方案

我们先看一下类似的错误信息如下&#xff1a; com.alipay.api.AlipayApiException: sign check fail: check Sign and Data Fail这里着重说明&#xff0c;报这个错误是因为支付宝公钥&#xff08;alipay_public_key&#xff09;使用错误导致的&#xff01; 很多开发者把自己生成…

js 判断 浏览器 是否为 微信 浏览器

//判断是否是微信浏览器的函数 function isWeiXin(){var ua window.navigator.userAgent.toLowerCase();if(ua.match(/MicroMessenger/i) micromessenger){return true;}else{return false;} } isWeiXin()

kafka 常用命令汇总

启动 kafka 服务 # 使用 -daemon 选项表示后台运行kafka服务 ./kafka-server-start.sh -daemon ../config/server.properties 创建主题 ./kafka-topics.sh --create --zookeeper zk_host:port --replication-factor 1 --partitions 1 --topic topic_name 列举所有主题 ./kafka-…

支付宝接口报错 insufficient-isv-permissions 错误原因: ISV权限不足解决方案

原贴地址&#xff1a;https://openclub.alipay.com/read.php?tid1672&fid72&#xff0c;欢迎大家访问错误信息一般如下&#xff1a; 错误代码 insufficient-isv-permissions 错误原因: ISV权限不足错误原因&#xff1a; 1.应用未上线 2.正式环境和沙箱环境网关使用…

Luogu P1115 最大子段和(dp 贪心)

P1115 最大子段和 题目描述 给出一段序列&#xff0c;选出其中连续且非空的一段使得这段和最大。 输入输出格式 输入格式&#xff1a; 输入文件maxsum1.in的第一行是一个正整数N&#xff0c;表示了序列的长度。 第2行包含N个绝对值不大于10000的整数A[i]&#xff0c;描述了这段…

微信 手机 网站 开发 签名 signature node (在更新中)

在进行微信手机网站开发时&#xff0c;第一座大山就是获取签名。下面是微信JS-SDK开发文档的内容&#xff0c;本文主要理清思路&#xff0c;开发起来&#xff0c;就很快了。 wx.config({debug: true, // 开启调试模式,调用的所有api的返回值会在客户端alert出来&#xff0c;若…

无效的appid排查方案

原贴地址&#xff1a;https://openclub.alipay.com/read.php?tid1909&fid72&ant_sourcezsearch&#xff0c;欢迎大家访问 报错信息一般如下&#xff1a; {"code":"40002","msg":"Invalid Arguments","sub_code":&q…

微信 IP白名单

买了周杰伦演唱会的门票才能去周杰伦演唱会听歌。在微信开发中获取access_token也是讲得同一个道理。我们首先需要设置微信的IP白名单。 点击查看即可配置。

教你设置eclipse自动生成的author等注释

每新建一个类上面都会有一行注释&#xff1a; /*** author 颠覆白的黑* version 创建时间&#xff1a;2018年3月26日 下午5:29:31* 类说明 */操作步骤和大家分享一下&#xff1a; window&#xff0d;>preference&#xff0d;>java&#xff0d;>code styple&#xff0…

前端学习(2546):debugger

执行进行数据代理 变量存储了一下 加入断点

暑期学习2

关于video视频插入 仍然是mime类型不支持&#xff0c;于是我将火狐换掉换成了chrome。 然后在运行的时候 第一点、视频文件无法找到&#xff1b;第二点、html5video.js无法找到 于是我先讲html5video.js删除重新去下载了个video文件复制进js包中 其实就只剩下视频文件无法找到这…

http 请求头 header Referer 含义和作用

Referer是header的一部分&#xff0c;当浏览器向web服务器发送请求的时候&#xff0c;一般会带上Referer&#xff0c;告诉服务器页面的请求地址&#xff0c;服务器就可以进行信息处理了。 HTTP Referer的一些实际用途&#xff1a; 1、防盗链。 我在www.google.com里有一个ww…

教你配置支付宝应用网关和授权回调地址

1.应用网关和授权回调地址是什么&#xff1f; a).应用网关是用于接收支付宝异步通知&#xff0c;例如口碑开店中&#xff0c;需要配置此网关来接收【开发者门店被动通知】。 注&#xff1a;这里的异步通知不是我们接口参数中的notify_url&#xff0c;是口碑开…

.NET MVC运行周期

1.路由比对 接到http请求&#xff0c;在UrlRoutingModule模块中处理与网址路由有关的运算。默认情况下如果该网址可以对应于网站跟目录下的实体文件&#xff0c;则不会交给MVC处理&#xff0c;直接交由IIS运行。可以通过在Application_start函数中设置RouteTable.Routes.RouteE…

工作90:富文本编辑器使用篇wangedit

WangEdit组件 <template lang"html"><div class"editor"><div ref"toolbar" class"toolbar"></div><div ref"editor" class"text"></div></div> </template>&l…