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代码阅读(四)的更多相关文章

  1. 代码阅读分析工具Understand 2.0试用

    Understand 2.0是一款源代码阅读分析软件,功能强大.试用过一段时间后,感觉相当不错,确实可以大大提高代码阅读效率.由于Understand功能十分强大,本文不可能详尽地介绍它的所有功能,所 ...

  2. 40 网络相关函数(八)——live555源码阅读(四)网络

    40 网络相关函数(八)——live555源码阅读(四)网络 40 网络相关函数(八)——live555源码阅读(四)网络 简介 15)writeSocket向套接口写数据 TTL的概念 函数send ...

  3. 29 GroupSock(NetAddressList)——live555源码阅读(四)网络

    29 GroupSock(NetAddressList)——live555源码阅读(四)网络 29 GroupSock(NetAddressList)——live555源码阅读(四)网络 简介 Net ...

  4. 28 GroupSock(NetAddress)——live555源码阅读(四)网络

    28 GroupSock(NetAddress)——live555源码阅读(四)网络 28 GroupSock(NetAddress)——live555源码阅读(四)网络 简介 1) NetAddre ...

  5. 27 GroupSock概述(一)——live555源码阅读(四)网络

    27 GroupSock概述(一)——live555源码阅读(四)网络 27 GroupSock概述(一)——live555源码阅读(四)网络 简介 1.网络通用数据类型定义 2.Tunnel隧道封装 ...

  6. Linux协议栈代码阅读笔记(二)网络接口的配置

    Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...

  7. [置顶] Linux协议栈代码阅读笔记(一)

    Linux协议栈代码阅读笔记(一) (基于linux-2.6.21.7) (一)用户态通过诸如下面的C库函数访问协议栈服务 int socket(int domain, int type, int p ...

  8. Bleve代码阅读(二)——Index Mapping

    引言 Bleve是Golang实现的一个全文检索库,类似Lucene之于Java.在这里通过阅读其代码,来学习如何使用及定制检索功能.也是为了通过阅读代码,学习在具体环境下Golang的一些使用方式. ...

  9. [置顶] Linux协议栈代码阅读笔记(二)网络接口的配置

    Linux协议栈代码阅读笔记(二)网络接口的配置 (基于linux-2.6.11) (一)用户态通过C库函数ioctl进行网络接口的配置 例如,知名的ifconfig程序,就是通过C库函数sys_io ...

  10. 【新人赛】阿里云恶意程序检测 -- 实践记录11.10 - XGBoost学习 / 代码阅读、调参经验总结

    XGBoost学习: 集成学习将多个弱学习器结合起来,优势互补,可以达到强学习器的效果.要想得到最好的集成效果,这些弱学习器应当"好而不同". 根据个体学习器的生成方法,集成学习方 ...

随机推荐

  1. MongoDB之shard_副本集和分片部署

    机器角色分配和拓扑环境如下: -------------------配置副本集s1-------------------------------1.创建目录在s1h1上创建如下目录[root@node ...

  2. bzoj2660最多的方案——数位DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2660 首先,多种方案的出现是因为一个较大的斐波那契数可以变成两个较小的: 用一个01串来表示 ...

  3. Ubuntu 16.04 如何使用Samba服务器

    对于Windows与Ubuntu之间的数据传输,我们习惯于使用FTP工具,不过还是有学员问到samba服务器搭建和使用的问题,这便是本文的来由. Ubuntu版本:ARM裸机1期加强版配套的Ubunt ...

  4. LNMP+Zabbix的安装与部署

    LNMP+Zabbix的安装与部署 一.Zabbix简介 1.zabbix是一个基于WEB界面的,并提供分布式系统监视以及网络监视功能的企业级的开源解决方案. zabbix能监视各种网络参数,保证服务 ...

  5. JDK7中匿名内部类中使用局部变量要加final,JDK8中不需要,但jdk会默认加上final

    今天看书的时候看到了局部内部类,书上说局部内部类可以访问局部变量,但是必须是final的.因为局部变量在方法调用之后就消失了,使用final声明的话该局部变量会存入堆中,和内部类有一样的声明周期.但是 ...

  6. Ruby attr_reader , attr_writer, attr_accessor方法

    attr_reader方法------读取实例变量 attr_writer方法------改写实例变量 attr_accessor方法-----读写实例变量 class Person attr_rea ...

  7. 040--JavaScript

    一.JavaScript的两种引入方式 {#1 直接编写#} <script> alert('hello Galileo') </script> {#2 导入文件#} < ...

  8. SCUT - 240 - 宝华的文件系统 - 模拟

    https://scut.online/p/240 就是要小心绝对路径中也有.和..出现. #include<bits/stdc++.h> using namespace std; #de ...

  9. 2016 Multi-University Training Contest 1 GCD【RMQ+二分】

    因为那时候没怎么补所以就分到了未搞分组里!!!然后因为标题如此之屌吧= =点击量很高,然后写的是无思路,23333,估计看题人真的是觉得博主就是个撒缺.废话不多说了,补题... update////2 ...

  10. unity ShaderLab 编辑器——sublime text 2

    sublime text 2,支持unity shader关键字高亮显示,智能提示功能.这个脚本编辑器的售价是70美元,不过作者很厚道地给了我们永久的免费试用期. 1)下载sublime text 2 ...