VINS-Fusion代码阅读(四)
pts_i和pts_j:具体指什么含义?(分别为第l个路标点在第i, j个相机归一化相机坐标系中的观察到的坐标,P¯¯¯cil \bar{P}^{c_i}_l
P
ˉ
l
c
i
和 P¯¯¯cjl \bar{P}^{c_j}_l
P
ˉ
l
c
j
);
tangent_base:正切平面上的任意两个正交基(在构造函数中通过计算?被赋值);
静态数据成员sqrt_info和sum_t:在何时被赋值的呢?
class ProjectionFactor : public ceres::SizedCostFunction<2, 7, 7, 7, 1>
{
public:
ProjectionFactor(const Eigen::Vector3d &_pts_i, const Eigen::Vector3d &_pts_j);
virtual bool Evaluate(double const *const *parameters, double *residuals, double **jacobians) const;
void check(double **parameters);
Eigen::Vector3d pts_i, pts_j;
Eigen::Matrix<double, 2, 3> tangent_base;
static Eigen::Matrix2d sqrt_info;
static double sum_t;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
步入正题,ProjectionFactor类中的Evaluate成员函数:
优化变量:[pwbi,qwbi],[pwbj,qwbj],[pbc,qbc],λl [p^w_{b_i}, q^w_{b_i}], [p^w_{b_j}, q^w_{b_j}], [p^b_c, q^b_c], \lambda_l[p
b
i
w
,q
b
i
w
],[p
b
j
w
,q
b
j
w
],[p
c
b
,q
c
b
],λ
l
分别对应:[Pi, Qi], [Pj, Qj], [tic, qic], inv_dep_i
(此处的λ \lambdaλ表示什么含义?逆深度inv_dep_i)(w,b w, bw,b代表的坐标系具体指什么?)
解析中(27)式:
Pcjl=Rcb{Rbjw[Rwbi(Rbc1λlP¯¯¯cil+pbc)+pwbi−pwbj]−pbc} P^{c_j}_l=R^c_b\{R^{b_j}_w[R^w_{b_i}(R^b_c\frac{1}{\lambda_l}\bar{P}^{c_i}_l+p^b_c)+p^w_{b_i}-p^w_{b_j}]-p^b_c\}P
l
c
j
=R
b
c
{R
w
b
j
[R
b
i
w
(R
c
b
λ
l
1
P
ˉ
l
c
i
+p
c
b
)+p
b
i
w
−p
b
j
w
]−p
c
b
}
1λlP¯¯¯cil \frac{1}{\lambda_l}\bar{P}^{c_i}_l
λ
l
1
P
ˉ
l
c
i
==>Eigen::Vector3d pts_camera_i = pts_i / inv_dep_i;
(因此,pts_i表示P¯¯¯cil \bar{P}^{c_i}_l
P
ˉ
l
c
i
,为第l个路标点在第i个相机归一化相机坐标系中的观察到的坐标);
(Rbc∗+pbc) (R^b_c*+p^b_c)(R
c
b
∗+p
c
b
) ==>Eigen::Vector3d pts_imu_i = qic * pts_camera_i + tic;
(此处可以看出来,imu与b bb系是一个系?)
Rwbi∗+pwbi R^w_{b_i}*+p^w_{b_i}R
b
i
w
∗+p
b
i
w
==>Eigen::Vector3d pts_w = Qi * pts_imu_i + Pi;
Rbjw(∗−pwbj) R^{b_j}_w(*-p^w_{b_j})R
w
b
j
(∗−p
b
j
w
) ==>Eigen::Vector3d pts_imu_j = Qj.inverse() * (pts_w - Pj);
Rcb(∗−pbc) R^c_b(*-p^b_c)R
b
c
(∗−p
c
b
) ==>Eigen::Vector3d pts_camera_j = qic.inverse() * (pts_imu_j - tic);
因此,pts_camera_j表示Pcjl P^{c_j}_lP
l
c
j
,是由P¯¯¯cil \bar{P}^{c_i}_l
P
ˉ
l
c
i
计算得来的。
解析中(25)式:
rc(zˆcjl,X)=[b1⃗ b2⃗ ](Pcjl∣∣Pcjl∣∣−P¯¯¯cjl) r_c(\hat{z}^{c_j}_l,X)=\begin{bmatrix}\vec{b_1}\\ \vec{b_2} \end{bmatrix}(\frac{P^{c_j}_l}{||P^{c_j}_l||}-\bar{P}^{c_j}_l)r
c
(
z
^
l
c
j
,X)=[
b
1
b
2
](
∣∣P
l
c
j
∣∣
P
l
c
j
−
P
ˉ
l
c
j
)
residual = tangent_base * (pts_camera_j.normalized() - pts_j.normalized());
residual = sqrt_info * residual;
最后,计算Jacobian,解析中(28)式:
注:此处解析上有一些矩阵维数上的错误,应该为3×∗ 3\times *3×∗,而非3×∗ 3\times *3×∗。
以其中一个为例,分析公式与代码对应关系:
J[0]2×7=[∂rc∂pwbi,∂rc∂qwbi] J[0]^{2\times 7}=[\frac{\partial r_c}{\partial p^w_{b_i}}, \frac{\partial r_c}{\partial q^w_{b_i}}]J[0]
2×7
=[
∂p
b
i
w
∂r
c
,
∂q
b
i
w
∂r
c
]
代码中首先定义了一个jaco_i为3×6 3\times 63×6,然后用一个reduce2×3 2\times 32×3去乘,得到的2×6 2\times 62×6的结果作为J[0] J[0]J[0]的左边6列,最后一列为0;具体如下:
Eigen::Matrix<double, 3, 6> jaco_i;
RcbRbjw R^c_bR^{b_j}_wR
b
c
R
w
b
j
jaco_i.leftCols<3>() = ric.transpose() * Rj.transpose();
−RcbRbjwRwbi(Rbc1λlP¯¯¯cil+pbc) -R^c_bR^{b_j}_wR^w_{b_i}(R^b_c\frac{1}{\lambda_l}\bar{P}^{c_i}_l+p^b_c)−R
b
c
R
w
b
j
R
b
i
w
(R
c
b
λ
l
1
P
ˉ
l
c
i
+p
c
b
)
jaco_i.rightCols<3>() = ric.transpose() * Rj.transpose() * Ri * -Utility::skewSymmetric(pts_imu_i);
Eigen::Matrix<double, 2, 3> reduce(2, 3);
reduce = tangent_base * norm_jaco;此处norm_jaco表达什么含义?对应公式?
reduce = sqrt_info * reduce;
Eigen::Map的用法?
Eigen::Map<Eigen::Matrix<double, 2, 7, Eigen::RowMajor>> jacobian_pose_i(jacobians[0]);
jacobian_pose_i.leftCols<6>() = reduce * jaco_i;
jacobian_pose_i.rightCols<1>().setZero();
J[1]2×7 J[1]^{2\times 7}J[1]
2×7
、J[2]2×7 J[2]^{2\times 7}J[2]
2×7
和J[3]2×1 J[3]^{2\times 1}J[3]
2×1
的计算类似。
至此,视觉约束暂时告一段落。
bool ProjectionFactor::Evaluate(double const *const *parameters, double *residuals, double **jacobians) const
{
TicToc tic_toc;
Eigen::Vector3d Pi(parameters[0][0], parameters[0][1], parameters[0][2]);
Eigen::Quaterniond Qi(parameters[0][6], parameters[0][3], parameters[0][4], parameters[0][5]);
Eigen::Vector3d Pj(parameters[1][0], parameters[1][1], parameters[1][2]);
Eigen::Quaterniond Qj(parameters[1][6], parameters[1][3], parameters[1][4], parameters[1][5]);
Eigen::Vector3d tic(parameters[2][0], parameters[2][1], parameters[2][2]);
Eigen::Quaterniond qic(parameters[2][6], parameters[2][3], parameters[2][4], parameters[2][5]);
double inv_dep_i = parameters[3][0];
Eigen::Vector3d pts_camera_i = pts_i / inv_dep_i;
Eigen::Vector3d pts_imu_i = qic * pts_camera_i + tic;
Eigen::Vector3d pts_w = Qi * pts_imu_i + Pi;
Eigen::Vector3d pts_imu_j = Qj.inverse() * (pts_w - Pj);
Eigen::Vector3d pts_camera_j = qic.inverse() * (pts_imu_j - tic);
Eigen::Map<Eigen::Vector2d> residual(residuals);
#ifdef UNIT_SPHERE_ERROR
residual = tangent_base * (pts_camera_j.normalized() - pts_j.normalized());
#else
double dep_j = pts_camera_j.z();
residual = (pts_camera_j / dep_j).head<2>() - pts_j.head<2>();
#endif
residual = sqrt_info * residual;
if (jacobians)
{
Eigen::Matrix3d Ri = Qi.toRotationMatrix();
Eigen::Matrix3d Rj = Qj.toRotationMatrix();
Eigen::Matrix3d ric = qic.toRotationMatrix();
Eigen::Matrix<double, 2, 3> reduce(2, 3);
#ifdef UNIT_SPHERE_ERROR
double norm = pts_camera_j.norm();
Eigen::Matrix3d norm_jaco;
double x1, x2, x3;
x1 = pts_camera_j(0);
x2 = pts_camera_j(1);
x3 = pts_camera_j(2);
norm_jaco << 1.0 / norm - x1 * x1 / pow(norm, 3), - x1 * x2 / pow(norm, 3), - x1 * x3 / pow(norm, 3),
- x1 * x2 / pow(norm, 3), 1.0 / norm - x2 * x2 / pow(norm, 3), - x2 * x3 / pow(norm, 3),
- x1 * x3 / pow(norm, 3), - x2 * x3 / pow(norm, 3), 1.0 / norm - x3 * x3 / pow(norm, 3);
reduce = tangent_base * norm_jaco;
#else
reduce << 1. / dep_j, 0, -pts_camera_j(0) / (dep_j * dep_j),
0, 1. / dep_j, -pts_camera_j(1) / (dep_j * dep_j);
#endif
reduce = sqrt_info * reduce;
if (jacobians[0])
{
Eigen::Map<Eigen::Matrix<double, 2, 7, Eigen::RowMajor>> jacobian_pose_i(jacobians[0]);
Eigen::Matrix<double, 3, 6> jaco_i;
jaco_i.leftCols<3>() = ric.transpose() * Rj.transpose();
jaco_i.rightCols<3>() = ric.transpose() * Rj.transpose() * Ri * -Utility::skewSymmetric(pts_imu_i);
jacobian_pose_i.leftCols<6>() = reduce * jaco_i;
jacobian_pose_i.rightCols<1>().setZero();
}
if (jacobians[1])
{
Eigen::Map<Eigen::Matrix<double, 2, 7, Eigen::RowMajor>> jacobian_pose_j(jacobians[1]);
Eigen::Matrix<double, 3, 6> jaco_j;
jaco_j.leftCols<3>() = ric.transpose() * -Rj.transpose();
jaco_j.rightCols<3>() = ric.transpose() * Utility::skewSymmetric(pts_imu_j);
jacobian_pose_j.leftCols<6>() = reduce * jaco_j;
jacobian_pose_j.rightCols<1>().setZero();
}
if (jacobians[2])
{
Eigen::Map<Eigen::Matrix<double, 2, 7, Eigen::RowMajor>> jacobian_ex_pose(jacobians[2]);
Eigen::Matrix<double, 3, 6> jaco_ex;
jaco_ex.leftCols<3>() = ric.transpose() * (Rj.transpose() * Ri - Eigen::Matrix3d::Identity());
Eigen::Matrix3d tmp_r = ric.transpose() * Rj.transpose() * Ri * ric;
jaco_ex.rightCols<3>() = -tmp_r * Utility::skewSymmetric(pts_camera_i) + Utility::skewSymmetric(tmp_r * pts_camera_i) +
Utility::skewSymmetric(ric.transpose() * (Rj.transpose() * (Ri * tic + Pi - Pj) - tic));
jacobian_ex_pose.leftCols<6>() = reduce * jaco_ex;
jacobian_ex_pose.rightCols<1>().setZero();
}
if (jacobians[3])
{
Eigen::Map<Eigen::Vector2d> jacobian_feature(jacobians[3]);
#if 1
jacobian_feature = reduce * ric.transpose() * Rj.transpose() * Ri * ric * pts_i * -1.0 / (inv_dep_i * inv_dep_i);
#else
jacobian_feature = reduce * ric.transpose() * Rj.transpose() * Ri * ric * pts_i;
#endif
}
}
sum_t += tic_toc.toc(http://www.my516.com);
return true;
}
---------------------
VINS-Fusion代码阅读(四)的更多相关文章
- 代码阅读分析工具Understand 2.0试用
Understand 2.0是一款源代码阅读分析软件,功能强大.试用过一段时间后,感觉相当不错,确实可以大大提高代码阅读效率.由于Understand功能十分强大,本文不可能详尽地介绍它的所有功能,所 ...
- 40 网络相关函数(八)——live555源码阅读(四)网络
40 网络相关函数(八)——live555源码阅读(四)网络 40 网络相关函数(八)——live555源码阅读(四)网络 简介 15)writeSocket向套接口写数据 TTL的概念 函数send ...
- 29 GroupSock(NetAddressList)——live555源码阅读(四)网络
29 GroupSock(NetAddressList)——live555源码阅读(四)网络 29 GroupSock(NetAddressList)——live555源码阅读(四)网络 简介 Net ...
- 28 GroupSock(NetAddress)——live555源码阅读(四)网络
28 GroupSock(NetAddress)——live555源码阅读(四)网络 28 GroupSock(NetAddress)——live555源码阅读(四)网络 简介 1) NetAddre ...
- 27 GroupSock概述(一)——live555源码阅读(四)网络
27 GroupSock概述(一)——live555源码阅读(四)网络 27 GroupSock概述(一)——live555源码阅读(四)网络 简介 1.网络通用数据类型定义 2.Tunnel隧道封装 ...
- Linux协议栈代码阅读笔记(二)网络接口的配置
Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...
- [置顶] Linux协议栈代码阅读笔记(一)
Linux协议栈代码阅读笔记(一) (基于linux-2.6.21.7) (一)用户态通过诸如下面的C库函数访问协议栈服务 int socket(int domain, int type, int p ...
- Bleve代码阅读(二)——Index Mapping
引言 Bleve是Golang实现的一个全文检索库,类似Lucene之于Java.在这里通过阅读其代码,来学习如何使用及定制检索功能.也是为了通过阅读代码,学习在具体环境下Golang的一些使用方式. ...
- [置顶] Linux协议栈代码阅读笔记(二)网络接口的配置
Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...
- 【新人赛】阿里云恶意程序检测 -- 实践记录11.10 - XGBoost学习 / 代码阅读、调参经验总结
XGBoost学习: 集成学习将多个弱学习器结合起来,优势互补,可以达到强学习器的效果.要想得到最好的集成效果,这些弱学习器应当"好而不同". 根据个体学习器的生成方法,集成学习方 ...
随机推荐
- nodejs 打造 多人对战游戏服务器(初级入门)
使用socket.set 和 socket.get 在存取玩家信息 百牛信息技术bainiu.ltd整理发布于博客园 socket.get('playerinfo', function (err, p ...
- Ribbon整合Eureka,出现 No instances available for XXX 异常
请观察这里的片段有没有问题? @Bean @LoadBalanced public RestTemplate restTemplate() { return new RestTemplate(); } ...
- The IBM Blockchain Platform:Installing the development environment
Follow these instructions to obtain the IBM Blockchain Platform: Develop development tools (primaril ...
- python接口自动化(三十八)-python操作mysql数据库(详解)
简介 现在的招聘要求对QA人员的要求越来越高,测试的一些基础知识就不必说了,来说测试知识以外的,会不会一门或者多门开发与语言,能不能读懂代码,会不会Linux,会不会搭建测试系统,会不会常用的数据库, ...
- 在线抠图网站速抠图sukoutu.com全面技术解析之canvas应用
技术关键词 Canvas应用,泛洪算法(Flood Fill),图片缩放,相对位置等比缩放,判断一个点是否在一个平面闭合多边形,nginx代理 业务关键词 在线抠图,智能抠图,一键抠图,钢笔抠图,矩阵 ...
- E20170425-gg
margin n(网页设置,CSS) 外铺,(金融,外汇交易)保证金 property n(计算机)类的属性变量 , 资产
- 洛谷 - P1162 - 填涂颜色 - 简单搜索
https://www.luogu.org/problemnew/show/P1162 在外面加一圈0把0连起来,然后把所有0换成2,再从(0,0)把连通的2全部改回来. 这也是一个判断内外圈的好办法 ...
- HDU 1230饭前开胃菜
题意不讲了.. 没思路,上去就是干.... 两个所谓要加的数直接存到数组,开一个标记的数组,然后直接加,乱搞一波,就好了. 细心一点. #include<iostream> #includ ...
- poj1015【DP.......无奈了】
首先,读题,真是一窍不通.后来看完程序的意思,才明白吧.. 题意: n个人中选m个,条件是取sum|D-P|最小,当有|D-P|相同的时候取|D+P|最大的.然后输出那些m个人的sumD,sumP,最 ...
- ES6之箭头函数深入理解
相对于普通函数的区别 新的书写方式 this 的改变 不能当构造函数 没有 prototype 属性 没有 arguments 对象 新的书写方式 书写方式很简单!直接看下图, 常规方式写一个函数 c ...