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. python整数与IP地址转换 [转]

    我们有时会将一个整数与IP地址进行互换,用python代码实现很简单将一个整数如2000000,变为一个IP地址的方式 >>> import socket >>> ...

  2. 如何升级xcode 中的cocos2dx 到v2.2.2以上版本

    每次升级cocos2dx版本都觉得不知道怎么弄才行. 这次升级到v2.2.2版本又花了我不少时间.因此在这里分享一下,以后也有地方可以查询. 1. 到http://cocos2d-x.org/ 下载最 ...

  3. E20170510-hm

    prototype  n.     原型,雏形,蓝本; omit (omitted)  vt.     省略; 遗漏; autonomous  adj.     自治的; 有自主权的; fold   ...

  4. Codeforces - Gym102028 - 2018 Jiaozuo Regional Contest

    http://codeforces.com/gym/102028 A. Xu Xiake in Henan Province 看起来像水题.乱搞一下,还真是. #include<bits/std ...

  5. Tenka1 Programmer Beginner Contest D - IntegerotS(位运算)

    传送门 题意 给出N,K,给出N对数a[i],b[i],选择一些数使得or和小于k且\(max\sum b[i]\) 分析 枚举k的每一个1位,将其删去并让低位全为1,对于每一个这样的数c,如果a[i ...

  6. 报错org.springframework.dao.DataIntegrityViolationException

    最简单的原因可能是数据库外键字段选择了不能为空, 改为允许为空就行了.

  7. Luogu P4889 kls与flag 【思维/排序】By cellur925

    题目传送门 这题真的一点也不难qwq.只要想出来就没有什么代码难度的qwq. 每个竹竿只可能向左倒或向右倒,把这两种情况都存在数组中,将数组排序,就可以知道最后落在同一位置的有多少竹竿.就可以知道落在 ...

  8. 富文本编辑器vue2-editor实现全屏功能

    vue2-editor非常不错,可惜并未带全屏功能,自己实现了一个,供大家参考. 实现思路:自定义模块. 1. 定义全屏模块Fullscreen /** * 编辑器的全屏实现 */ import no ...

  9. [Usaco2015 Feb]Censoring

    Description Farmer John has purchased a subscription to Good Hooveskeeping magazine for his cows, so ...

  10. AtCoder Grand Contest 012 B

    B - Splatter Painting Time limit : 2sec / Memory limit : 256MB Score : 700 points Problem Statement ...