前言
在学习VINS-Mono过程中,对初始化代码中的坐标转换关系做出了一些推导,特意写了博客记录一下,主要记录大体的变量转换关系。
相机和IMU的外参
若需要VINS标定旋转外参,则进入以下代码:
if (initial_ex_rotation.CalibrationExRotation(corres, pre_integrations[frame_count]->delta_q, calib_ric))
{
ROS_WARN("initial extrinsic rotation calib success");
ROS_WARN_STREAM("initial extrinsic rotation: " << endl << calib_ric);
ric[0] = calib_ric;
RIC[0] = calib_ric;
ESTIMATE_EXTRINSIC = 1;
}
旋转外参 r i c [ 0 ] ric\left[0\right] ric[0] 是 camera 坐标系到 body 坐标系的转换关系,记为 R b , c R_{b,c} Rb,c,平移外参在未后期优化前,默认为 0 0 0,记为 t b , c t_{b,c} tb,c。
全局sfm
首先选定一个 camera 参考坐标系 c l c_l cl:
int l;
if (!relativePose(relative_R, relative_T, l))
{
ROS_INFO("Not enough features or parallax; Move device around");
return false;
}
设 WZ为滑动窗口大小。 c l c_l cl 为滑窗中第 l l l 帧到第 WZ 帧满足一定视差(三角化时相对更准确)并可以解出两帧之间位姿 relative_R、relative_T 的图像帧(一般就是 c 0 c_0 c0 帧)。relative_R、relative_T 表示的是第 WZ帧到第 l l l 帧的变化。
GlobalSFM sfm;
if(!sfm.construct(frame_count + 1, Q, T, l,
relative_R, relative_T,
sfm_f, sfm_tracked_points))
{
ROS_DEBUG("global SFM failed!");
marginalization_flag = MARGIN_OLD;
return false;
}
在 initial_sfm.cpp 中,三角化求的路标点便以 c l c_l cl 帧为参考系。经过一次 ceres 优化后得到滑窗中图像帧的位姿为 q [ i ] q\left[i\right] q[i]、 T [ i ] T\left[i\right] T[i] :
for (int i = 0; i < frame_num; i++)
{
q[i].w() = c_rotation[i][0];
q[i].x() = c_rotation[i][1];
q[i].y() = c_rotation[i][2];
q[i].z() = c_rotation[i][3];
q[i] = q[i].inverse();
}
for (int i = 0; i < frame_num; i++)
{
T[i] = -1 * (q[i] * Vector3d(c_translation[i][0], c_translation[i][1], c_translation[i][2]));
}
这些位姿具体表示的转换关系为:
R
c
l
,
c
0
R_{c_{l},c_{0}}
Rcl,c0、
R
c
l
,
c
1
R_{c_{l},c_{1}}
Rcl,c1、… 、
R
c
l
,
c
W
Z
−
1
R_{c_{l},c_{WZ-1}}
Rcl,cWZ−1、
R
c
l
,
c
W
Z
R_{c_{l},c_{WZ}}
Rcl,cWZ ;
P
c
l
,
c
0
P_{c_{l},c_{0}}
Pcl,c0、
P
c
l
,
c
1
P_{c_{l},c_{1}}
Pcl,c1、… 、
P
c
l
,
c
W
Z
−
1
P_{c_{l},c_{WZ-1}}
Pcl,cWZ−1、
P
c
l
,
c
W
Z
P_{c_{l},c_{WZ}}
Pcl,cWZ 。
用恢复出的三角点 pnp 求解出 all_image_frame 所有帧的位姿:
for (int i = 0; frame_it != all_image_frame.end( ); frame_it++)
{
//省略
...
frame_it->second.R = R_pnp * RIC[0].transpose();
frame_it->second.T = T_pnp;
}
不妨记为:
R
c
l
,
0
R_{c_{l},0}
Rcl,0、
R
c
l
,
1
R_{c_{l},1}
Rcl,1、… 、
R
c
l
,
b
0
R_{c_{l},b_{0}}
Rcl,b0、
R
c
l
,
9
R_{c_{l},9}
Rcl,9、… 、
R
c
l
,
b
1
R_{c_{l},b_{1}}
Rcl,b1、… 、
R
c
l
,
b
W
Z
−
1
R_{c_{l},b_{WZ-1}}
Rcl,bWZ−1、… 、
R
c
l
,
98
R_{c_{l},98}
Rcl,98、
R
c
l
,
b
W
Z
R_{c_{l},b_{WZ}}
Rcl,bWZ ;
P
c
l
,
0
P_{c_{l},0}
Pcl,0、
P
c
l
,
1
P_{c_{l},1}
Pcl,1、… 、
P
c
l
,
c
0
P_{c_{l},c_{0}}
Pcl,c0、
P
c
l
,
9
P_{c_{l},9}
Pcl,9、… 、
P
c
l
,
c
1
P_{c_{l},c_{1}}
Pcl,c1、… 、
P
c
l
,
c
W
Z
−
1
P_{c_{l},c_{WZ-1}}
Pcl,cWZ−1、… 、
P
c
l
,
98
P_{c_{l},98}
Pcl,98、
P
c
l
,
c
W
Z
P_{c_{l},c_{WZ}}
Pcl,cWZ 。
速度、重力和尺度因子
在 initial_alignment.cpp 中,使用 all_image_frame 所有帧间的关系求出陀螺仪 bias、所有帧在body下的速度、
c
l
c_l
cl 帧下的重力因子以及尺度因子:
v
0
v_{0}
v0、
v
1
v_{1}
v1、… 、
v
b
0
v_{b_{0}}
vb0、
v
9
v_{9}
v9、… 、
v
b
1
v_{b_{1}}
vb1、… 、
v
b
W
Z
−
1
v_{b_{WZ-1}}
vbWZ−1、… 、
v
98
v_{98}
v98、
v
b
W
Z
v_{b_{WZ}}
vbWZ 、
g
c
l
g_{c_{l}}
gcl、
s
s
s。
此后第 0 帧到第 WZ 帧的
R
s
Rs
Rs 、
P
s
Ps
Ps 被赋值:
for (int i = 0; i <= frame_count; i++)
{
Matrix3d Ri = all_image_frame[Headers[i].stamp.toSec()].R;
Vector3d Pi = all_image_frame[Headers[i].stamp.toSec()].T;
Ps[i] = Pi;
Rs[i] = Ri;
all_image_frame[Headers[i].stamp.toSec()].is_key_frame = true;
}
这些位姿此时表示为:
R
c
l
,
b
0
R_{c_{l},b_{0}}
Rcl,b0、
R
c
l
,
b
1
R_{c_{l},b_{1}}
Rcl,b1、… 、
R
c
l
,
b
W
Z
−
1
R_{c_{l},b_{WZ-1}}
Rcl,bWZ−1、
R
c
l
,
b
W
Z
R_{c_{l},b_{WZ}}
Rcl,bWZ ;
P
c
l
,
c
0
P_{c_{l},c_{0}}
Pcl,c0、
P
c
l
,
c
1
P_{c_{l},c_{1}}
Pcl,c1、… 、
P
c
l
,
c
W
Z
−
1
P_{c_{l},c_{WZ-1}}
Pcl,cWZ−1、
P
c
l
,
c
W
Z
P_{c_{l},c_{WZ}}
Pcl,cWZ 。
特征点的深度
在 void triangulate(Vector3d Ps[ ],Vector3d tic[ ],Matrix3d ric[ ]) 函数中三角化求出特征点的深度。若特征点的深度值 estimated_depth小于0,则进行三角化求解。
一般来说,三角化的过程如下,已知多个视角匹配的归一化平面上的特征点
{
u
,
u
,
,
.
.
.
}
\{u,u^,,...\}
{u,u,,...}以及对应的多个视觉的投影矩阵
{
P
,
P
’
,
…
}
\{P,P^’,…\}
{P,P’,…};
[
u
x
u
y
1
]
=
λ
[
R
t
]
[
x
y
z
1
]
=
λ
[
p
1
p
2
p
3
p
4
p
5
p
6
p
7
p
8
p
9
p
10
p
11
p
12
]
[
x
y
z
1
]
=
λ
[
P
0
T
P
1
T
P
2
T
]
X
\quad\quad\quad\quad\quad\quad\left[\begin{matrix}u_x\\u_y\\1\end{matrix}\right]=\lambda[R\quad t]\left[\begin{matrix}x\\y\\z\\1\end{matrix}\right]=\lambda\left[\begin{matrix}p_1\quad p_2\quad p_3\quad p_4 \\p_5\quad p_6\quad p_7\quad p_8\\p_9\quad p_{10}\quad p_{11}\quad p_{12}\end{matrix}\right]\left[\begin{matrix}x\\y\\z\\1\end{matrix}\right]=\lambda\left[\begin{matrix}P^T_0\\P^T_1\\P^T_2\end{matrix}\right]X
⎣⎡uxuy1⎦⎤=λ[Rt]⎣⎢⎢⎡xyz1⎦⎥⎥⎤=λ⎣⎡p1p2p3p4p5p6p7p8p9p10p11p12⎦⎤⎣⎢⎢⎡xyz1⎦⎥⎥⎤=λ⎣⎡P0TP1TP2T⎦⎤X
{
u
x
=
λ
P
0
T
X
u
y
=
λ
P
1
T
X
1
=
λ
P
2
T
X
⇒
[
P
0
T
−
u
x
P
2
T
P
1
T
−
u
y
P
2
T
]
X
=
0
\left\{\begin{matrix}u_x=\lambda P^T_0X\\u_y=\lambda P^T_1X\\1\ =\ \lambda P^T_2X\end{matrix}\right.\Rightarrow\left[\begin{matrix}P^T_0-u_xP^T_2\\P^T_1-u_yP^T_2\end{matrix}\right]X=0
⎩⎨⎧ux=λP0TXuy=λP1TX1 = λP2TX⇒[P0T−uxP2TP1T−uyP2T]X=0
那么 n 个匹配的特征点可构建 2n*4 大小的矩阵,SVD 求解得到 3D 点。
在VINS这个三角化的代码中,分成两种情况分析。
- 初始化没完成,此时
P
b
0
,
c
0
=
0
P_{b_0,c_0}=0
Pb0,c0=0,对 feature 中每个特征点:
若特征点的 start_frame 为0,
t 0 = P s [ 0 ] c l , c 0 + R s [ 0 ] c l , b 0 ∗ P b 0 , c 0 = P c l , c 0 t0=Ps[0]_{c_l,c_0}+Rs[0]_{c_l,b_0}*P_{b_0,c_0}=P_{c_l,c_0} t0=Ps[0]cl,c0+Rs[0]cl,b0∗Pb0,c0=Pcl,c0;
R 0 = R s [ 0 ] c l , b 0 ∗ R b 0 , c 0 = R c l , c 0 R0=Rs[0]_{c_l,b_0}*R_{b_0,c_0}=R_{c_l,c_0} R0=Rs[0]cl,b0∗Rb0,c0=Rcl,c0;
对 feature_per_frame 的特征点的不同坐标:
第 0 帧: t 1 = t 0 ; R 1 = R 0 ; t = 0 t1=t0\ ; R1=R0\ ;\ t=0 t1=t0 ;R1=R0 ; t=0 即 P c 0 , c 0 ; P_{c_0,c_0}; Pc0,c0; R = I R=I R=I 即 R c 0 , c 0 ; R_{c_0,c_0}; Rc0,c0;
第 1 帧: t 1 = P s [ 1 ] c l , c 1 + R s [ 1 ] c l , b 1 ∗ P b 1 , c 1 = P c l , c 1 ; t1=Ps[1]_{c_l,c_1}+Rs[1]_{c_l,b_1}*P_{b_1,c_1}=P_{c_l,c_1}\ ; t1=Ps[1]cl,c1+Rs[1]cl,b1∗Pb1,c1=Pcl,c1 ;
R 1 = R s [ 1 ] c l , b 1 ∗ R b 1 , c 1 = R c l , c 1 ; \qquad\quad R1=Rs[1]_{c_l,b_1}*R_{b_1,c_1}=R_{c_l,c_1}\ ; R1=Rs[1]cl,b1∗Rb1,c1=Rcl,c1 ;
t = R c l , c 0 − 1 ( P c l , c 1 − P c l , c 0 ) = P c 0 , c 1 ; \qquad\quad\ t=R^{-1}_{c_l,c_0}(P_{c_l,c_1}-P_{c_l,c_0})=P_{c_0,c_1}; t=Rcl,c0−1(Pcl,c1−Pcl,c0)=Pc0,c1;
R = R c l , c 0 − 1 ∗ R c l , c 1 = R c 0 , c 1 ; \qquad\quad R=R^{-1}_{c_l,c_0}*R_{c_l,c_1}=R_{c_0,c_1} ; R=Rcl,c0−1∗Rcl,c1=Rc0,c1;
代码中的投影矩阵 P是 c 0 c_0 c0 到 c 1 c_1 c1 的位姿变换;
第 2 帧: t = P c 0 , c 2 ; t=P_{c_0,c_2}; t=Pc0,c2; R = R c 0 , c 2 ; R=R_{c_0,c_2} ; R=Rc0,c2;
投影矩阵 P是 c 0 c_0 c0 到 c 2 c_2 c2 的位姿变换;
…
若特征点的 start_frame 为 1,2…,依次类推。
可以推出 SVD 求解得到的是每个特征点在其 start_frame 帧下的深度z。 - 初始化完成了,此时
P
b
0
,
c
0
P_{b_0,c_0}
Pb0,c0不为 0,P、V、Q皆转换到世界坐标系下,为 body 坐标系到世界坐标系的变换关系。
对 feature中每个特征点:
若特征点的 start_frame 为 0,
t 0 = P s [ 0 ] w , b 0 + R s [ 0 ] w , b 0 ∗ P b 0 , c 0 = P w , c 0 t0=Ps[0]_{w,b_0}+Rs[0]_{w,b_0}*P_{b_0,c_0}=P_{w,c_0} t0=Ps[0]w,b0+Rs[0]w,b0∗Pb0,c0=Pw,c0;
R 0 = R s [ 0 ] w , b 0 ∗ R b 0 , c 0 = R w , c 0 R0=Rs[0]_{w,b_0}*R_{b_0,c_0}=R_{w,c_0} R0=Rs[0]w,b0∗Rb0,c0=Rw,c0;
第 0 帧: t 1 = t 0 ; R 1 = R 0 ; t = 0 t1=t0\ ; R1=R0\ ;\ t=0 t1=t0 ;R1=R0 ; t=0 即 P c 0 , c 0 ; P_{c_0,c_0}; Pc0,c0; R = I R=I R=I 即 R c 0 , c 0 ; R_{c_0,c_0}; Rc0,c0;
第 1 帧: t 1 = P s [ 1 ] c l , c 1 + R s [ 1 ] c l , b 1 ∗ P b 1 , c 1 = P c l , c 1 ; t1=Ps[1]_{c_l,c_1}+Rs[1]_{c_l,b_1}*P_{b_1,c_1}=P_{c_l,c_1}\ ; t1=Ps[1]cl,c1+Rs[1]cl,b1∗Pb1,c1=Pcl,c1 ;
R 1 = R s [ 1 ] c l , b 1 ∗ R b 1 , c 1 = R c l , c 1 ; \qquad\quad R1=Rs[1]_{c_l,b_1}*R_{b_1,c_1}=R_{c_l,c_1}\ ; R1=Rs[1]cl,b1∗Rb1,c1=Rcl,c1 ;
t = R c l , c 0 − 1 ( P c l , c 1 − P c l , c 0 ) = P c 0 , c 1 ; \qquad\quad\ t=R^{-1}_{c_l,c_0}(P_{c_l,c_1}-P_{c_l,c_0})=P_{c_0,c_1}; t=Rcl,c0−1(Pcl,c1−Pcl,c0)=Pc0,c1;
R = R c l , c 0 − 1 ∗ R c l , c 1 = R c 0 , c 1 ; \qquad\quad R=R^{-1}_{c_l,c_0}*R_{c_l,c_1}=R_{c_0,c_1} ; R=Rcl,c0−1∗Rcl,c1=Rc0,c1;
代码中的投影矩阵 P 是 c 0 c_0 c0 到 c 1 c_1 c1 的位姿变换;
第 2 帧: t = P c 0 , c 2 ; t=P_{c_0,c_2}; t=Pc0,c2; R = R c 0 , c 2 ; R=R_{c_0,c_2} ; R=Rc0,c2;
投影矩阵 P 是 c 0 c_0 c0 到 c 2 c_2 c2 的位姿变换;
若特征点的 start_frame 为 1,2…,依次类推。
同样可以推出 SVD 求解得到的是每个特征点在其 start_frame 帧下的深度z。
真实尺度下的R、P、V和特征点深度
此时在滑窗中:
1.
R
R
R表示的仍是各body坐标系到
c
l
c_l
cl的转换关系:
\quad
R
s
[
0
]
:
R
s
[
0
]
c
l
,
b
0
Rs[0]:Rs[0]_{c_{l},b_{0}}
Rs[0]:Rs[0]cl,b0;
\quad
R
s
[
1
]
:
R
s
[
1
]
c
l
,
b
1
Rs[1]:Rs[1]_{c_{l},b_{1}}
Rs[1]:Rs[1]cl,b1;
\quad
…
\quad
R
s
[
W
Z
]
:
R
s
[
W
Z
]
c
l
,
b
W
Z
Rs[WZ]:Rs[WZ]_{c_{l},b_{WZ}}
Rs[WZ]:Rs[WZ]cl,bWZ ;
2.
P
P
P通过转换,表示body坐标系到
c
l
c_l
cl的转换关系:
for (int i = frame_count; i >= 0; i--)
{
Ps[i] = s * Ps[i] - Rs[i] * TIC[0] - (s * Ps[0] - Rs[0] * TIC[0]);
}
\quad
P
s
[
0
]
:
s
∗
P
s
[
0
]
c
l
,
c
0
−
R
s
[
0
]
c
l
,
b
0
∗
P
s
[
0
]
b
0
,
c
0
−
(
s
∗
P
s
[
0
]
c
l
,
c
0
−
R
s
[
0
]
c
l
,
b
0
∗
P
s
[
0
]
b
0
,
c
0
)
=
0
即
s
∗
P
s
[
0
]
c
l
,
b
0
Ps[0]:s*Ps[0]_{{c_l},{c_0}}-Rs[0]_{{c_l},{b_0}}*Ps[0]_{{b_0},{c_0}}-(s*Ps[0]_{{c_l},{c_0}}-Rs[0]_{{c_l},{b_0}}*Ps[0]_{{b_0},{c_0}})=0即s*Ps[0]_{{c_l},{b_0}}
Ps[0]:s∗Ps[0]cl,c0−Rs[0]cl,b0∗Ps[0]b0,c0−(s∗Ps[0]cl,c0−Rs[0]cl,b0∗Ps[0]b0,c0)=0即s∗Ps[0]cl,b0;
\quad
P
s
[
1
]
:
s
∗
P
s
[
1
]
c
l
,
c
1
−
R
s
[
1
]
c
l
,
b
1
∗
P
s
[
1
]
b
1
,
c
1
−
(
s
∗
P
s
[
0
]
c
l
,
c
0
−
R
s
[
0
]
c
l
,
b
0
∗
P
s
[
0
]
b
0
,
c
0
)
即
s
∗
P
s
[
1
]
c
l
,
b
1
Ps[1]:s*Ps[1]_{{c_l},{c_1}}-Rs[1]_{{c_l},{b_1}}*Ps[1]_{{b_1},{c_1}}-(s*Ps[0]_{{c_l},{c_0}}-Rs[0]_{{c_l},{b_0}}*Ps[0]_{{b_0},{c_0}})即s*Ps[1]_{{c_l},{b_1}}
Ps[1]:s∗Ps[1]cl,c1−Rs[1]cl,b1∗Ps[1]b1,c1−(s∗Ps[0]cl,c0−Rs[0]cl,b0∗Ps[0]b0,c0)即s∗Ps[1]cl,b1;
\quad
…
\quad
P
s
[
W
Z
]
:
即
s
∗
P
s
[
W
Z
]
c
l
,
b
W
Z
Ps[WZ]:即s*Ps[WZ]_{{c_l},{b_{WZ}}}
Ps[WZ]:即s∗Ps[WZ]cl,bWZ;
3.
V
V
V被转换以
c
l
c_l
cl为参考坐标系:
for (frame_i = all_image_frame.begin(); frame_i != all_image_frame.end(); frame_i++)
{
if(frame_i->second.is_key_frame)
{
kv++;
Vs[kv] = frame_i->second.R * x.segment<3>(kv * 3);
}
}
\quad
V
s
[
0
]
:
R
s
[
0
]
c
l
,
b
0
∗
v
b
0
Vs[0]:Rs[0]_{c_{l},b_{0}}*v_{b_0}
Vs[0]:Rs[0]cl,b0∗vb0;
\quad
V
s
[
1
]
:
R
s
[
1
]
c
l
,
b
1
∗
v
b
1
Vs[1]:Rs[1]_{c_{l},b_{1}}*v_{b_1}
Vs[1]:Rs[1]cl,b1∗vb1;
\quad
…
\quad
V
s
[
W
Z
]
:
R
s
[
W
Z
]
c
l
,
b
W
Z
∗
v
b
W
Z
Vs[WZ]:Rs[WZ]_{c_{l},b_{WZ}}*v_{b_{WZ}}
Vs[WZ]:Rs[WZ]cl,bWZ∗vbWZ ;
4.feature中的每个特征点深度estimated_depth都乘以s,得到在实际尺度下的特征点深度。
for (auto &it_per_id : f_manager.feature)
{
it_per_id.used_num = it_per_id.feature_per_frame.size();
if (!(it_per_id.used_num >= 2 && it_per_id.start_frame < WINDOW_SIZE - 2))
continue;
it_per_id.estimated_depth *= s;
}
当知道真实的米制平移时,投影矩阵
{
P
,
P
’
,
…
}
\{P,P^’,…\}
{P,P’,…}的平移带有尺度;
[
u
x
u
y
1
]
=
λ
′
[
R
t
]
[
x
y
z
′
1
]
=
λ
′
[
p
1
p
2
p
3
s
p
4
p
5
p
6
p
7
s
p
8
p
9
p
10
p
11
s
p
12
]
[
x
y
z
′
1
]
=
λ
′
[
p
1
p
2
p
3
p
4
p
5
p
6
p
7
p
8
p
9
p
10
p
11
p
12
]
[
x
y
z
′
s
]
=
λ
′
s
[
p
1
p
2
p
3
p
4
p
5
p
6
p
7
p
8
p
9
p
10
p
11
p
12
]
[
x
/
s
y
/
s
z
′
s
1
]
=
λ
[
p
1
p
2
p
3
p
4
p
5
p
6
p
7
p
8
p
9
p
10
p
11
p
12
]
[
x
/
s
y
/
s
z
′
/
s
1
]
\left[\begin{matrix}u_x\\u_y\\1\end{matrix}\right]=\lambda^{'} [R\quad t]\left[\begin{matrix}x\\y\\z^{'}\\1\end{matrix}\right]=\lambda^{'} \left[\begin{matrix}p_1\quad p_2\quad p_3\quad sp_4 \\p_5\quad p_6\quad p_7\quad sp_8\\p_9\quad p_{10}\quad p_{11}\quad sp_{12}\end{matrix}\right]\left[\begin{matrix}x\\y\\z^{'}\\1\end{matrix}\right]=\lambda^{'} \left[\begin{matrix}p_1\quad p_2\quad p_3\quad p_4 \\p_5\quad p_6\quad p_7\quad p_8\\p_9\quad p_{10}\quad p_{11}\quad p_{12}\end{matrix}\right]\left[\begin{matrix}x\\y\\z^{'}\\s\end{matrix}\right]=\lambda^{'} s\left[\begin{matrix}p_1\quad p_2\quad p_3\quad p_4 \\p_5\quad p_6\quad p_7\quad p_8\\p_9\quad p_{10}\quad p_{11}\quad p_{12}\end{matrix}\right]\left[\begin{matrix}x/s\\y/s\\z^{'}s\\1\end{matrix}\right]=\lambda\left[\begin{matrix}p_1\quad p_2\quad p_3\quad p_4 \\p_5\quad p_6\quad p_7\quad p_8\\p_9\quad p_{10}\quad p_{11}\quad p_{12}\end{matrix}\right]\left[\begin{matrix}x/s\\y/s\\z^{'}/s\\1\end{matrix}\right]
⎣⎡uxuy1⎦⎤=λ′[Rt]⎣⎢⎢⎡xyz′1⎦⎥⎥⎤=λ′⎣⎡p1p2p3sp4p5p6p7sp8p9p10p11sp12⎦⎤⎣⎢⎢⎡xyz′1⎦⎥⎥⎤=λ′⎣⎡p1p2p3p4p5p6p7p8p9p10p11p12⎦⎤⎣⎢⎢⎡xyz′s⎦⎥⎥⎤=λ′s⎣⎡p1p2p3p4p5p6p7p8p9p10p11p12⎦⎤⎣⎢⎢⎡x/sy/sz′s1⎦⎥⎥⎤=λ⎣⎡p1p2p3p4p5p6p7p8p9p10p11p12⎦⎤⎣⎢⎢⎡x/sy/sz′/s1⎦⎥⎥⎤
此时求解的estimator_depth
=
z
′
=
z
∗
s
= z^{'}= z*s
=z′=z∗s。
R、P、V转换到世界坐标系
Matrix3d R0 = Utility::g2R(g);
double yaw = Utility::R2ypr(R0 * Rs[0]).x();
R0 = Utility::ypr2R(Eigen::Vector3d{-yaw, 0, 0}) * R0;
g = R0 * g;
Matrix3d rot_diff = R0;
for (int i = 0; i <= frame_count; i++)
{
Ps[i] = rot_diff * Ps[i];
Rs[i] = rot_diff * Rs[i];
Vs[i] = rot_diff * Vs[i];
}
1.首先求得将归一化的
g
c
l
g_{c_l}
gcl转换到世界坐标系
(
0
0
1
)
T
(0\ 0\ 1)^T
(0 0 1)T的旋转矩阵
R
w
,
c
l
R_{w,{c_l}}
Rw,cl,使用XYZ顺序欧拉角来表示的话不妨记为
R
w
,
c
l
=
{
R
z
w
,
c
l
∗
R
y
w
,
c
l
∗
R
x
w
,
c
l
}
R_{w,{c_l}}=\{Rz_{w,{c_l}}*Ry_{w,{c_l}}*Rx_{w,{c_l}}\}
Rw,cl={Rzw,cl∗Ryw,cl∗Rxw,cl}。用{…}表示由欧拉角表示的旋转矩阵。
2.令
R
0
=
{
R
y
w
,
c
l
∗
R
x
w
,
c
l
}
R0=\{Ry_{w,{c_l}}*Rx_{w,{c_l}}\}
R0={Ryw,cl∗Rxw,cl},
R
0
R0
R0是yaw角为0的
R
w
,
c
l
R_{w,{c_l}}
Rw,cl,yaw角的变化不影响
R
0
R0
R0有和
R
w
,
c
l
R_{w,{c_l}}
Rw,cl一样的转换重力向量参考系的功能,因为
(
0
0
1
)
T
(0\ 0\ 1)^T
(0 0 1)T没有xy平面的值(除了0),可以参考《如何通俗地解释欧拉角?之后为何要引入四元数?》直观感受一下欧拉角。
3.求得
R
0
∗
R
s
[
0
]
c
l
,
b
0
R0*Rs[0]_{c_l,b_0}
R0∗Rs[0]cl,b0的yaw角,并用XYZ顺序欧拉角{-yaw,0,0}形成旋转矩阵,记作
R
z
w
,
b
0
−
1
Rz^{-1}_{w,b_0}
Rzw,b0−1;最终的rot_diff为
{
R
z
w
,
b
0
−
1
∗
R
y
w
,
c
l
∗
R
x
w
,
c
l
}
\{Rz^{-1}_{w,b_0}*Ry_{w,{c_l}}*Rx_{w,{c_l}}\}
{Rzw,b0−1∗Ryw,cl∗Rxw,cl}。
4.用rot_diff转换第0帧到第WZ帧的Rs、Ps、Vs。
P
s
[
0
]
w
,
b
0
=
{
R
z
w
,
b
0
−
1
∗
R
y
w
,
c
l
∗
R
x
w
,
c
l
}
∗
s
∗
P
s
[
0
]
c
l
,
b
0
Ps[0]_{w,b_0}=\{Rz^{-1}_{w,b_0}*Ry_{w,{c_l}}*Rx_{w,{c_l}}\}*s*Ps[0]_{c_l,b_0}
Ps[0]w,b0={Rzw,b0−1∗Ryw,cl∗Rxw,cl}∗s∗Ps[0]cl,b0
R
s
[
0
]
w
,
b
0
=
{
R
z
w
,
b
0
−
1
∗
R
y
w
,
c
l
∗
R
x
w
,
c
l
}
∗
R
s
[
0
]
c
l
,
b
0
Rs[0]_{w,b_0}=\{Rz^{-1}_{w,b_0}*Ry_{w,{c_l}}*Rx_{w,{c_l}}\}*Rs[0]_{c_l,b_0}
Rs[0]w,b0={Rzw,b0−1∗Ryw,cl∗Rxw,cl}∗Rs[0]cl,b0
P
s
[
0
]
w
,
b
0
=
{
R
z
w
,
b
0
−
1
∗
R
y
w
,
c
l
∗
R
x
w
,
c
l
}
∗
R
s
[
0
]
c
l
,
b
0
∗
v
b
0
Ps[0]_{w,b_0}=\{Rz^{-1}_{w,b_0}*Ry_{w,{c_l}}*Rx_{w,{c_l}}\}*Rs[0]_{c_l,b_0}*v_{b_0}
Ps[0]w,b0={Rzw,b0−1∗Ryw,cl∗Rxw,cl}∗Rs[0]cl,b0∗vb0
…
依次类推得到其它帧的变换。
可见rot_diff将第0帧到WZ帧
c
l
c_l
cl帧坐标系下的Rs、Ps、Vs的水平方向即roll和pitch和变得世界坐标系的roll和pitch一致(yaw不可观),同时让初始帧
R
s
[
0
]
w
,
b
0
Rs[0]_{w,b_0}
Rs[0]w,b0的yaw角为0。后期优化时还会将滑窗中帧的yaw角调整到优化前的大小,防止优化值乱漂,这些留着下篇博客在讨论吧。