1 SLAM实验环境
操作系统: | Ubuntu16 / Ubuntu18 |
---|---|
编译工具: | cmake |
依赖库: | Eigen、Sophus、 |
2 三维空间刚体运动
2.1 旋转矩阵(R: 3x3)
假设坐标系从
e
e
e 经过了欧式变换后,其正交基向量从
[
e
1
,
e
2
,
e
3
]
\begin{bmatrix}e_1, e_2, e_3\end{bmatrix}
[e1,e2,e3] 变成了
[
e
1
′
,
e
2
′
,
e
3
′
]
\begin{bmatrix}e_1' , e_2' , e_3' \end{bmatrix}
[e1′,e2′,e3′],在变换中存在一个向量
a
a
a,其坐标从
[
a
1
a
2
a
3
]
\begin{bmatrix}a_1\\a_2\\a_3\end{bmatrix}
⎣⎡a1a2a3⎦⎤ 变成了
[
a
1
′
a
2
′
a
3
′
]
\begin{bmatrix}a_1' \\a_2' \\a_3' \end{bmatrix}
⎣⎡a1′a2′a3′⎦⎤,所以满足关系:
[
e
1
,
e
2
,
e
3
]
[
a
1
a
2
a
3
]
=
[
e
1
′
,
e
2
′
,
e
3
′
]
[
a
1
′
a
2
′
a
3
′
]
\begin{bmatrix}e_1, e_2, e_3\end{bmatrix}\begin{bmatrix}a_1\\a_2\\a_3\end{bmatrix} = \begin{bmatrix}e_1' , e_2' , e_3' \end{bmatrix}\begin{bmatrix}a_1' \\a_2' \\a_3' \end{bmatrix}
[e1,e2,e3]⎣⎡a1a2a3⎦⎤=[e1′,e2′,e3′]⎣⎡a1′a2′a3′⎦⎤
可以转换成:
a
=
[
a
1
a
2
a
3
]
=
[
e
1
T
e
1
′
e
1
T
e
2
′
e
1
T
e
3
′
e
2
T
e
1
′
e
2
T
e
2
′
e
2
T
e
3
′
e
3
T
e
1
′
e
3
T
e
3
′
e
1
T
e
3
′
]
[
a
1
′
a
2
′
a
3
′
]
=
R
a
′
a = \begin{bmatrix}a_1\\a_2\\a_3\end{bmatrix} = \begin{bmatrix}e_1^Te_1' & e_1^Te_2' &e_1^Te_3' \\e_2^Te_1' &e_2^Te_2' &e_2^Te_3' \\e_3^Te_1' &e_3^Te_3' &e_1^Te_3' \end{bmatrix} \begin{bmatrix}a_1' \\a_2' \\a_3' \end{bmatrix} = Ra'
a=⎣⎡a1a2a3⎦⎤=⎣⎡e1Te1′e2Te1′e3Te1′e1Te2′e2Te2′e3Te3′e1Te3′e2Te3′e1Te3′⎦⎤⎣⎡a1′a2′a3′⎦⎤=Ra′
这里的
R
R
R 称为旋转矩阵
,它是一个行列式为1的正交矩阵(即逆为自身转置的矩阵),则反向旋转有:
a
′
=
R
−
1
a
=
R
T
a
a' = R^{-1}a = R^Ta
a′=R−1a=RTa
如果要描述向量在空间中的欧式变换,还需要一个平移向量
t
t
t,因为
R
R
R 只描述了旋转,所以向量
a
1
a_1
a1 到向量
a
2
a_2
a2 的欧式变换:
a
2
=
R
a
1
+
t
a_2 = Ra_1 + t
a2=Ra1+t
2.2 变换矩阵(T: 4x4)
上式的欧式变换用到了
R
R
R 和
t
t
t,有两次变换就不是线性关系,但可以使用齐次坐标和变换矩阵来将它线性化,设变换矩阵
T
T
T:
T
=
[
R
t
0
T
1
]
T = \begin{bmatrix}R&t\\0^T&1 \end{bmatrix}
T=[R0Tt1]
对应的欧式变化如下:
[
a
2
1
]
=
[
R
t
0
T
0
]
[
a
1
1
]
=
T
[
a
1
1
]
\begin{bmatrix}a^2 \\1\end{bmatrix} = \begin{bmatrix}R&t\\0^T&0\end{bmatrix} \begin{bmatrix}a^1\\1\end{bmatrix} = T\begin{bmatrix}a^1\\1\end{bmatrix}
[a21]=[R0Tt0][a11]=T[a11]
2.3 旋转向量和欧拉角
-
旋转向量
旋转状态也可以用一个
旋转轴
n n n和旋转角
θ \theta θ来描述,组合在一起为旋转向量 ( θ n \scriptsize \theta n θn),它和旋转矩阵可以相互转化:旋转向量 --> 旋转矩阵:
R = c o s θ I + ( 1 − c o s θ ) n n T + s i n θ n ^ R = cos{\theta I} + (1-cos{\theta })nn^T+sin{\theta} \hat{n} R=cosθI+(1−cosθ)nnT+sinθn^
旋转矩阵 --> 旋转向量:
t r ( R ) = c o s θ I + ( 1 − c o s θ ) t r ( n n T ) + s i n θ t r ( n ^ ) = 3 c o s θ + ( 1 − c o s θ ) = 1 + 2 c o s θ \begin{aligned} tr(R) &= cos{\theta}I + (1-cos{\theta})tr(nn^T) + sin\theta tr(\hat{n}) \\ &= 3cos{\theta} + (1 - cos{\theta}) \\ &= 1 + 2cos{\theta} \end{aligned} tr(R)=cosθI+(1−cosθ)tr(nnT)+sinθtr(n^)=3cosθ+(1−cosθ)=1+2cosθ
θ = a r c c o s t r ( R ) − 1 2 \theta = arccos{\frac{tr(R)-1}{2}} θ=arccos2tr(R)−1
R n = n Rn=n Rn=n
上面的 n ^ \hat{n} n^ 表示 n n n 的反对称矩阵:
a ^ = [ 0 − a 3 a 2 a 3 0 − a 1 − a 2 a 1 0 ] \hat{a} = \begin{bmatrix} 0 & -a_3 & a_2 \\ a_3 & 0 & -a_1 \\ -a_2 & a_1 & 0 \end{bmatrix} a^=⎣⎡0a3−a2−a30a1a2−a10⎦⎤ -
欧拉角
使用 [ r , p , y ] T \begin{bmatrix}r , p , y\end{bmatrix}^T [r,p,y]T 来描述旋转,表示分别绕三个坐标轴旋转,不同的旋转顺序会导致结果不一样,如 r p y rpy rpy 角的旋转顺序是 Z Y X ZYX ZYX,欧拉角的缺点是存在
万象锁问题
;
2.4 四元数
q = [ s , v ] T , s = q 0 ∈ R , v = [ q 1 , q 2 , q 3 ] T ∈ R 3 q = \begin{bmatrix} s, v \end{bmatrix}^T, s = q_0\in \mathbb{R}, v = \begin{bmatrix}q_1, q_2, q_3\end{bmatrix}^T\in \mathbb{R}^3 q=[s,v]T,s=q0∈R,v=[q1,q2,q3]T∈R3
四元数为复数,上式中, s s s 为实部, v v v 为虚部;
注:c++中的矩阵运算、旋转向量、欧拉角、四元数的转化可以使用Eigen库,参考这里;
3 李群与李代数
3.1 李群
旋转矩阵构成特殊正交群 SO(3)
,变换矩阵构成了特殊欧式群 SE(3)
:
S
O
(
3
)
=
{
R
∈
R
3
∗
3
∣
R
R
T
=
I
,
d
e
t
(
R
)
=
1
}
SO(3) = \{R\in \mathbb{R}^{3*3} \mid RR^T = I, det(R) = 1\}
SO(3)={R∈R3∗3∣RRT=I,det(R)=1}
S
E
(
3
)
=
{
T
=
[
R
t
0
T
1
]
∈
R
4
∗
4
∣
R
∈
S
O
(
3
)
,
t
∈
R
3
}
SE(3) = \{T=\begin{bmatrix}R & t \\ 0^T & 1 \end{bmatrix}\in \mathbb{R}^{4*4} \mid R \in SO(3), t \in \mathbb{R}^3\}
SE(3)={T=[R0Tt1]∈R4∗4∣R∈SO(3),t∈R3}
这类矩阵之所以称之为‘群’,是因为它们具有一些属性,比如它们相乘后还是属于一类:
R
1
R
2
∈
S
O
(
3
)
,
T
1
T
2
∈
S
E
(
3
)
R_1R_2 \in SO(3), T_1T_2 \in SE(3)
R1R2∈SO(3),T1T2∈SE(3)
3.1 李代数
推导李代数可以由
R
(
t
)
R
(
t
)
T
=
I
R(t)R(t)^T=I
R(t)R(t)T=I 式子引出,求导后在使用反对称矩阵、泰勒展开、微分方程的方法可以得到式子:
R
(
t
)
=
e
x
p
(
ϕ
0
^
t
)
R(t)=exp(\hat{\phi_0}t)
R(t)=exp(ϕ0^t)
即
R
=
e
x
p
(
ϕ
^
)
R =exp(\hat{\phi})
R=exp(ϕ^) ,这里的
ϕ
\phi
ϕ 就是李代数;
李代数
S
O
(
3
)
\mathtt{SO(3)}
SO(3):
S
O
(
3
)
=
{
ϕ
∈
R
3
,
Φ
=
ϕ
^
∈
R
3
∗
3
}
\mathtt{SO(3)} = \{\phi \in \mathbb{R}^3, \Phi = \hat{\phi} \in \mathbb{R}^{3*3} \}
SO(3)={ϕ∈R3,Φ=ϕ^∈R3∗3}
李代数
S
E
(
3
)
\mathtt{SE(3)}
SE(3):
S
E
(
3
)
=
{
ξ
=
[
ρ
ϕ
]
∈
R
6
,
ρ
∈
R
3
,
ϕ
∈
S
O
(
3
)
,
ξ
^
=
[
ϕ
^
ρ
0
T
0
]
∈
R
4
∗
4
}
\mathtt{SE(3)} = \{ \xi = \begin{bmatrix}\rho \\ \phi \end{bmatrix}\in \mathbb{R}^6, \rho \in \mathbb{R}^3, \phi \in \mathcal{\mathtt{SO}(3), \hat{\xi} = \begin{bmatrix} \hat{\phi} & \rho \\ 0^T & 0 \end{bmatrix} \in \mathbb{R}^{4*4}} \}
SE(3)={ξ=[ρϕ]∈R6,ρ∈R3,ϕ∈SO(3),ξ^=[ϕ^0Tρ0]∈R4∗4}
注:c++中的李群、李代数之间的转化可以使用Sophus库,参考这里;
4 相机与图像
参数 | 说明 |
---|---|
1 / Z 1/Z 1/Z | Z Z Z是物平面的深度, X , Y X,Y X,Y乘上 1 / Z 1/Z 1/Z后深度变成了1,即归一化 |
f f f | 相机焦距 |
α , β \alpha , \beta α,β | 缩放(把物理单位转换成像素单位) |
C x , C y C_x,C_y Cx,Cy | 平移 |
K K K | 集成了 C x , C y , α , β C_x,C_y,\alpha ,\beta Cx,Cy,α,β |
注:
K
=
[
f
x
0
C
x
0
f
y
C
y
0
0
1
]
,
f
x
=
α
f
,
f
y
=
β
f
K = \begin{bmatrix} f_x & 0 & C_x \\ 0 & f_y & C_y \\ 0 & 0 & 1 \end{bmatrix}, f_x=\alpha f, f_y = \beta f
K=⎣⎡fx000fy0CxCy1⎦⎤,fx=αf,fy=βf
坐标系转换公式:
Z
P
u
v
=
Z
[
u
v
1
]
=
K
(
R
P
w
+
t
)
=
K
T
P
w
ZP_{uv} = Z \begin{bmatrix} u \\\ v \\\ 1 \end{bmatrix} = K(RP_w + t) = KTP_w
ZPuv=Z⎣⎡u v 1⎦⎤=K(RPw+t)=KTPw
其中,
R
R
R、
t
t
t 为位姿,
P
w
P_w
Pw为世界坐标,
(
R
P
w
+
t
)
(RP_w+t)
(RPw+t)是相机坐标,
K
K
K 为相机内参,
P
u
v
P_{uv}
Puv 为像素坐标,
(
R
P
w
+
t
)
/
Z
(RP_w + t) / Z
(RPw+t)/Z是归一化坐标;
5 非线性优化
参考这里,使用 g2o 模块实现高斯牛顿法;
6 视觉里程计(特征点法)
视觉里程计的算法主要分为两大类:特征点法 和 直接法。
:::tip
- 特征点法:是视觉里程计的主流方法,它具有对光照、动态物体不敏感的优势,是目前比较成熟的解决方案。
- 直接法:
:::
特征点法首先是提取
、匹配
图像特征点,然后根据对应的点来估计
两帧之间的相机运动和场景结构,从而实现一个两帧间
视觉里程计。
估计运动有多种方法,其中,由于相机的原理不同,会采取不同的方法:
相机类型 | 点类型 | 方法 |
---|---|---|
单目 | 2D + 2D | 对极几何 |
双目、RGB-D | 3D + 3D | ICP |
其他 | 3D + 2D | PnP |
6.1 特征点
特征点指图像中一些特别的地方
,比如:角点、区块、边缘,这些特征用于标记相邻图片的对应位置。所以第一步就是通过算法来计算出图像中的特征点,著名算法有:SIFT、SURF、ORB等,找出特征点后,更重要的是把对应的点匹配起来,匹配方法有暴力匹配
、快速近似最邻近
,相关的算法已经集成在 Opencv 中。
6.2 2D-2D: 对极几何
-
对极约束
图中:
- O 1 O_1 O1、 O 2 O_2 O2:相机中心
- I 1 I_1 I1、 I 2 I_2 I2:像平面
- p 1 p_1 p1、 p 2 p_2 p2:对应的特征点
- e 1 e_1 e1、 e 2 e_2 e2:对应的极点
- l 1 l_1 l1、 l 2 l_2 l2:对应的极线
我们知道两个像素点 p 1 p_1 p1、 p 2 p_2 p2 的像素位置:
s 1 p 1 = K P , s 2 p 2 = K ( R P + t ) s_1 p_1 = KP, s_2 p_2 = K(RP + t) s1p1=KP,s2p2=K(RP+t)
其中, K K K为相机内参矩阵, R R R、 t t t 为两个坐标系的相机运动。因为 s 1 p 1 s_1p_1 s1p1 和 p 1 p_1 p1 成投影关系,它们在齐次坐标下的意义是相等的,称这种相等关系为尺度意义下相等
,记作: s p ⋍ p sp \backsimeq p sp⋍p,那么上面的投影关系可以写为:
p 1 ⋍ K P , p 2 ⋍ K ( R P + t ) p_1 \backsimeq KP, p_2 \backsimeq K(RP + t) p1⋍KP,p2⋍K(RP+t)
现在取:
x 1 = K − 1 p 1 , x 2 = K − 1 p 2 x_1 = K^{-1}p_1, x_2=K^{-1}p_2 x1=K−1p1,x2=K−1p2
经过推倒可以得到一个式子:
x 2 T t ^ R x 1 = 0 x_2^T \hat{t} R x_1 = 0 x2Tt^Rx1=0
带入 x 1 x_1 x1、 x 2 x_2 x2 得:
p 2 T K − T t ^ R K − 1 p 1 = 0 p_2^T K^{-T} \hat{t} R K^{-1} p_1 = 0 p2TK−Tt^RK−1p1=0
上面的两个式子都称为对极约束
,它的几何意义是 O 1 O_1 O1、 P P P、 O 2 O_2 O2 共面。我们从上式子中提取两个矩阵:基础矩阵
F F F、本质矩阵
E E E,于是可以进一步简化对极矩阵约束:
E = t ^ R , F = K − T E K − 1 , x 2 T E x 1 = p 2 T F p 1 = 0 E = \hat{t}R, F = K^{-T}EK^{-1}, x_2^T E x_1 = p_2^T F p_1 = 0 E=t^R,F=K−TEK−1,x2TEx1=p2TFp1=0
对极约束简洁的给出了两个匹配点的空间位置关系,于是,相机位姿估计问题变成以下两步:- 根据匹配点的像素位置求出 E E E 或 F F F;
- 根据 E E E 或 F F F 求出 R R R, t t t。
-
本质矩阵
本质矩阵 E = t ^ R E = \hat{t}R E=t^R,它是一个 3x3 的矩阵,有 9 个未知数,我们可以利用 E E E 的线性性质来使用八点法
求解。
我们设一对匹配点,它们的归一化坐标为 x 1 = [ u 1 , v 1 , 1 ] T x_1 = \begin{bmatrix}u_1,v_1,1\end{bmatrix}^T x1=[u1,v1,1]T, x 2 = [ u 2 , v 2 , 1 ] T x_2 = \begin{bmatrix}u_2,v_2,1\end{bmatrix}^T x2=[u2,v2,1]T,根据对极约束,有:
[ u 2 , v 2 , 1 ] [ e 1 e 2 e 3 e 4 e 5 e 6 e 7 e 8 e 9 ] T [ u 1 v 1 1 ] = 0 \begin{bmatrix}u_2,v_2,1\end{bmatrix} \begin{bmatrix}e_1 & e_2 & e_3 \\ e_4 & e_5 & e_6 \\ e_7 & e_8 & e_9\end{bmatrix}^T \begin{bmatrix}u_1 \\ v_1 \\ 1\end{bmatrix} = 0 [u2,v2,1]⎣⎡e1e4e7e2e5e8e3e6e9⎦⎤T⎣⎡u1v11⎦⎤=0
如果我们把矩阵 E E E 展开,写成向量形式:
e = [ e 1 , e 2 , e 3 , e 4 , e 5 , e 6 , e 7 , e 8 , e 9 ] T e = \begin{bmatrix} e_1, e_2, e_3, e_4, e_5, e_6, e_7, e_8, e_9 \end{bmatrix}^T e=[e1,e2,e3,e4,e5,e6,e7,e8,e9]T
那么,对极约束改写成与 e e e有关的形式:
[ u 2 u 1 , u 2 v 1 , u 2 , v 2 u 1 , v 2 v 1 , v 2 , u 1 , v 1 , 1 ] e = 0 \begin{bmatrix} u_2u_1, u_2v_1, u_2, v_2u_1, v_2v_1, v_2, u_1, v_1,1 \end{bmatrix}e = 0 [u2u1,u2v1,u2,v2u1,v2v1,v2,u1,v1,1]e=0
上面的式子是关于一对点的约束,如果我们使用8对点,变成了线性方程组:
[ u 2 1 u 1 1 u 2 1 v 1 1 u 2 1 v 2 1 u 1 1 v 2 1 v 1 1 v 2 1 u 1 1 v 1 1 1 u 2 2 u 1 2 u 2 2 v 1 2 u 2 2 v 2 2 u 1 2 v 2 2 v 1 2 v 2 2 u 1 2 v 1 2 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . u 8 2 u 1 8 u 2 8 v 1 8 u 2 8 v 2 8 u 1 8 v 2 8 v 1 8 v 2 8 u 1 8 v 1 8 1 ] [ e 1 e 2 e 3 e 4 e 5 e 6 e 7 e 8 e 9 ] = 0 \begin{bmatrix} u_2^1u_1^1 & u_2^1v_1^1 & u_2^1 & v_2^1u_1^1 & v_2^1v_1^1 & v_2^1 & u_1^1 & v_1^1 &1 \\ u_2^2u_1^2 & u_2^2v_1^2 & u_2^2 & v_2^2u_1^2 & v_2^2v_1^2 & v_2^2 & u_1^2 & v_1^2 &1 \\ . & . & . & . & . & . & . & . & . \\ . & . & . & . & . & . & . & . & . \\ . & . & . & . & . & . & . & . & . \\ u_8^2u_1^8 & u_2^8v_1^8 & u_2^8 & v_2^8u_1^8 & v_2^8v_1^8 & v_2^8 & u_1^8 & v_1^8 &1 \end{bmatrix} \begin{bmatrix} e_1 \\ e_2 \\ e_3 \\ e_4 \\ e_5 \\ e_6 \\ e_7 \\ e_8 \\ e_9 \end{bmatrix} = 0 ⎣⎢⎢⎢⎢⎢⎢⎡u21u11u22u12...u82u18u21v11u22v12...u28v18u21u22...u28v21u11v22u12...v28u18v21v11v22v12...v28v18v21v22...v28u11u12...u18v11v12...v1811...1⎦⎥⎥⎥⎥⎥⎥⎤⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡e1e2e3e4e5e6e7e8e9⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤=0
如果8对匹配点组成的矩阵满足秩为8的条件,那么 E E E的各元素就可以由上诉方程得到。
:::tip
到这里,已经得到了本质矩阵 E E E,根据它再分解出相机的运动 R R R、 t t t需要采用奇异分解(SVD),分解后会得到4组解,不过分别把这4组解拿来运算就可以排除三项不合常规的。
::: -
单应矩阵
6.3 三角测量
6.4 3D-2D: PnP
如果两张图像中的特征点的3D位置已知,那么最少需要3对点就可以估计相机运动。在双目、RGN-D的视觉里程计中,可以直接使用PnP估计喜相机运动;而在单目视觉里程计中,必须先要进行初始化才能使用PnP。PnP问题有多种求解方法:P3P
、直接线性变换(DLT)
、EPnP、UPnP等,还可以使用非线性优化
的方式。
- 直接线性变换
:::tip 针对问题
假如在世界坐标下存在一批3D点,它们的3D坐标已知,然后相机相对世界坐标系的原点做了运动,并获取到了这些点在相机上的投影,我们需要根据这批3D点坐标
和相机的2D投影坐标
来求相机的位姿R、t。
(当然这个问题可以引申,比如把这里的世界坐标
换成上一个时刻的相机坐标
,那么求解的就是相对位姿变换了。)
:::
在这个问题中,我们设这个3D点为 P P P,它的齐次坐标为 P = [ X , Y , Z , 1 ] T P=[X,Y,Z,1]^T P=[X,Y,Z,1]T,对应的2D投影点 归一化坐标 为 x 1 = [ u 1 , v 1 , 1 ] T x_1=[u_1,v_1,1]^T x1=[u1,v1,1]T,过程中的 R , T R,T R,T 是未知的,所以设定一个增广矩阵 [ R ∣ t ] [R|t] [R∣t],其展开形式为:
s [ u 1 v 1 1 ] = [ t 1 t 2 t 3 t 4 t 5 t 6 t 7 t 8 t 9 t 10 t 11 t 12 ] [ X Y Z 1 ] s \begin{bmatrix} u_1 \\ v_1 \\ 1 \end{bmatrix} = \begin{bmatrix} t_1 & t_2 & t_3 & t_4 \\ t_5 & t_6 & t_7 & t_8 \\ t_9 & t_{10} & t_{11} & t_{12} \end{bmatrix} \begin{bmatrix} X \\ Y \\ Z \\ 1 \end{bmatrix} s⎣⎡u1v11⎦⎤=⎣⎡t1t5t9t2t6t10t3t7t11t4t8t12⎦⎤⎣⎢⎢⎡XYZ1⎦⎥⎥⎤
:::warning
上式中的 [ u 1 , v 1 , 1 ] T \begin{bmatrix}u_1 , v_1 , 1 \end{bmatrix}^T [u1,v1,1]T是归一化后的坐标,需要用像素坐标转换的得到。后文的P3P、最小重投影的例子中才是像素坐标。
:::
当然,上面式子中的等量关系是3D点在相机坐标下的坐标
,等式左边直接用深度 x 归一化
,等式右边用[R|t] x 世界坐标
。通过上式,可以得到约束:
u 1 = t 1 X + t 2 Y + t 3 Z + t 4 t 9 X + t 10 Y + t 11 Z + t 12 , v 1 = t 5 X + t 6 Y + t 7 Z + t 8 t 9 X + t 10 Y + t 11 Z + t 12 , u_1 = \frac{t_1 X + t_2 Y + t_3 Z + t_4}{t_9 X + t_{10}Y + t_{11}Z + t_{12}}, v_1 = \frac{t_5 X + t_6 Y + t_7 Z + t_8}{t_9 X + t_{10}Y + t_{11}Z + t_{12}}, u1=t9X+t10Y+t11Z+t12t1X+t2Y+t3Z+t4,v1=t9X+t10Y+t11Z+t12t5X+t6Y+t7Z+t8,
为了更简化,设:
t
1
=
[
t
1
,
t
2
,
t
3
,
t
4
]
T
,
t
2
=
[
t
5
,
t
6
,
t
7
,
t
8
]
T
,
t
3
=
[
t
9
,
t
10
,
t
11
,
t
12
]
T
t_1 = \begin{bmatrix} t_1, t_2, t_3, t_4 \end{bmatrix}^T, t_2 = \begin{bmatrix} t_5, t_6, t_7, t_8 \end{bmatrix}^T, t_3 = \begin{bmatrix} t_9, t_{10}, t_{11}, t_{12} \end{bmatrix}^T
t1=[t1,t2,t3,t4]T,t2=[t5,t6,t7,t8]T,t3=[t9,t10,t11,t12]T
于是有:
t
1
T
P
−
t
3
T
P
u
1
=
0
t_1^T P - t_3^T P u_1 = 0
t1TP−t3TPu1=0
t
2
T
P
−
t
3
T
P
v
1
=
0
t_2^T P - t_3^T P v_1 = 0
t2TP−t3TPv1=0
所以每一个特征点提供了两个关于
t
t
t的线性约束,假设有
N
N
N的特征点,则有以下方程组:
[
P
1
T
0
−
u
1
P
1
T
0
P
1
T
−
v
1
P
1
T
.
.
.
.
.
.
.
.
.
P
N
T
0
−
u
N
P
N
T
0
P
N
T
−
v
N
P
N
T
]
[
t
1
t
2
t
3
]
=
0
\begin{bmatrix} P_1^T & 0 & -u_1P_1^T \\ 0 & P_1^T & -v_1P_1^T \\ . & . & . \\ . & . & . \\ . & . & . \\ P_N^T & 0 & -u_NP_N^T \\ 0 & P_N^T & -v_NP_N^T \end{bmatrix} \begin{bmatrix} t_1 \\ t_2 \\ t_3 \end{bmatrix} = 0
⎣⎢⎢⎢⎢⎢⎢⎢⎢⎡P1T0...PNT00P1T...0PNT−u1P1T−v1P1T...−uNPNT−vNPNT⎦⎥⎥⎥⎥⎥⎥⎥⎥⎤⎣⎡t1t2t3⎦⎤=0
t
t
t 一共有12维,因此最少通过 6对 匹配点(每个点有两个约束)即可求解,这种方法就是直接线性变换(DLT)
。当匹配点大于6对时,也可以使用SVD等方法对超定方程求最小二乘解。
- P3P
P3P 是另一种解 PnP 的方法,不过它仅仅使用 3对 匹配点,对数据要求少。
:::tip 针对问题
我们要解决的问题和前面一样,已经知道3D点的世界坐标
和相机的2D成像坐标
,求相机的位姿R,t
。
:::
首先建立这样的相机模型:
图中, A , B , C A,B,C A,B,C是世界坐标下(不是相机坐标)的点,坐标已知, a , b , c a,b,c a,b,c是相机上的投影点。
首先,通过余弦定理得到:
O
A
2
+
O
B
2
−
2
O
A
⋅
O
B
⋅
c
o
s
<
a
,
b
>
=
A
B
2
OA^2 + OB^2 - 2 OA \cdot OB \cdot cos<a,b> = AB^2
OA2+OB2−2OA⋅OB⋅cos<a,b>=AB2
O
B
2
+
O
C
2
−
2
O
B
⋅
O
C
⋅
c
o
s
<
b
,
c
>
=
B
C
2
OB^2 + OC^2 - 2 OB \cdot OC \cdot cos<b,c> = BC^2
OB2+OC2−2OB⋅OC⋅cos<b,c>=BC2
O
A
2
+
O
C
2
−
2
O
A
⋅
O
C
⋅
c
o
s
<
a
,
c
>
=
A
C
2
OA^2 + OC^2 - 2 OA \cdot OC \cdot cos<a,c> = AC^2
OA2+OC2−2OA⋅OC⋅cos<a,c>=AC2
以上 3 式整体处以 O C 2 OC^2 OC2,并且记 x = O A / O C , y = O B / O C x = OA/OC, y = OB/OC x=OA/OC,y=OB/OC,得:
x
2
+
y
2
−
2
x
y
c
o
s
<
a
,
b
>
−
v
=
0
x^2 + y^2 - 2 x y cos<a,b> - v = 0
x2+y2−2xycos<a,b>−v=0
y
2
+
1
−
2
y
c
o
s
<
b
,
c
>
−
u
v
=
0
y^2 + 1 - 2 y cos<b,c> - uv = 0
y2+1−2ycos<b,c>−uv=0
x
2
+
1
−
2
x
c
o
s
<
a
,
c
>
−
w
v
=
0
x^2 + 1 - 2 x cos<a,c> - wv = 0
x2+1−2xcos<a,c>−wv=0
把第一个式子代入到后面两个式子中,得到:
(
1
−
u
)
y
2
−
u
x
2
−
cos
<
b
,
c
>
y
+
2
u
x
y
cos
<
a
,
b
>
+
1
=
0
(1-u)y^2 - ux^2 - \cos<b,c>y + 2uxy \cos<a,b> + 1 = 0
(1−u)y2−ux2−cos<b,c>y+2uxycos<a,b>+1=0
(
1
−
w
)
x
2
−
w
y
2
−
cos
<
a
,
c
>
x
+
2
w
x
y
cos
<
a
,
b
>
+
1
=
0
(1-w)x^2 - wy^2 - \cos<a,c>x + 2wxy \cos<a,b> + 1 = 0
(1−w)x2−wy2−cos<a,c>x+2wxycos<a,b>+1=0
在这两个式子中,
cos
<
a
,
b
>
,
cos
<
b
,
c
>
,
cos
<
a
,
c
>
,
u
=
B
C
2
/
A
B
2
,
w
=
A
C
2
/
A
B
2
\cos<a,b>,\cos<b,c>,\cos<a,c>,u=BC^2/AB^2,w=AC^2/AB^2
cos<a,b>,cos<b,c>,cos<a,c>,u=BC2/AB2,w=AC2/AB2为已知量,那么就剩下未知量
x
,
y
x,y
x,y,所以问题变成了求解关于
x
,
y
x,y
x,y的二元二次方程。求解是一个复杂的过程,需要用到吴消元法
,解的的结果最多有4个,可以使用验证点来计算最有可能的解,得到
A
,
B
,
C
A,B,C
A,B,C在相机坐标系下的3D坐标,然后,根据3D-3D的对应点,计算相机的运动
R
,
t
R,t
R,t。
:::danger 这种方法存在的问题是
- 当匹配的点多余3组时,难以利用更多的信息;
- 如果3D点或2D点受噪声影响,或者存在误匹配,则算法失效;
:::
- 最小化重投影误差求解PnP
这种方法比较通用,是一类把相机、三维点放在一起进行最小化
的问题。
:::tip 针对问题
要解决的问题和前面一样,已经知道3D点的世界坐标
和相机的2D成像坐标
,求相机的位姿R,t
。
:::
我们设3D点的坐标为
P
i
=
[
X
i
,
Y
i
,
Z
i
]
T
P_i=\begin{bmatrix}X_i,Y_i,Z_i \end{bmatrix}^T
Pi=[Xi,Yi,Zi]T,2D成像坐标(像素坐标)为
u
i
=
[
u
i
,
v
i
]
T
u_i=\begin{bmatrix}u_i, v_i \end{bmatrix}^T
ui=[ui,vi]T,用李群
T
T
T来表示
R
,
t
R,t
R,t,那么有以下关系:
s
i
=
[
u
i
v
i
1
]
=
K
T
[
X
i
Y
i
Z
i
1
]
s_i = \begin{bmatrix} u_i \\ v_i \\ 1 \end{bmatrix} = KT \begin{bmatrix} X_i \\ Y_i \\ Z_i \\ 1 \end{bmatrix}
si=⎣⎡uivi1⎦⎤=KT⎣⎢⎢⎡XiYiZi1⎦⎥⎥⎤
即:
s
i
u
i
=
K
T
P
i
s_i u_i = KTP_i
siui=KTPi
由于相机的位姿是未知的,并且观测点存在噪声,所以该等式存在一个误差,我们就针对这个误差来构建一个最小二乘问题
,然后找到最好的相机位姿,使它最小化:
T
∗
=
arg
min
1
2
∑
i
=
1
n
∥
u
i
−
1
s
1
K
T
P
i
∥
2
2
T^* = \arg \min \frac{1}{2} \sum_{i=1}^{n} \| u_i - \frac{1}{s_1}KTP_i \|_2^2
T∗=argmin21i=1∑n∥ui−s11KTPi∥22
该问题的误差项是将3D点的投影位置与预测位置做差,所以称为重投影误差
。如下图,
P
2
′
P_2'
P2′为预测位置,
P
2
P_2
P2为投影位置,
e
e
e为投影误差:
最小二乘问题参考这里,其中最关键的要求出误差项关于优化变量的导数,这里不做推导,只列出对应的两个雅可比,一个是误差关于相机位姿的导数
,一个是误差关于特征点的导数
。
误差关于相机位姿
T
T
T 的导数:
∂
e
∂
δ
ξ
=
−
[
f
x
Z
′
0
−
f
x
X
′
Z
′
2
−
f
x
X
′
Y
′
Z
′
2
f
x
+
f
x
X
′
2
Z
′
2
−
f
x
Y
′
Z
′
0
f
y
Z
′
−
f
y
Y
′
Z
′
2
−
f
y
−
f
y
Y
′
2
Z
′
2
f
y
X
′
Y
′
Z
′
2
f
y
X
′
Z
′
]
\frac{\partial e}{\partial \delta \xi} = - \begin{bmatrix} \frac{f_x}{Z'} & 0 & -\frac{f_xX'}{{Z'}^2} & -\frac{f_xX'Y'}{{Z'}^2} & f_x+\frac{f_x{X'}^2}{{Z'}^2} & -\frac{f_xY'}{Z'} \\ 0 & \frac{f_y}{Z'} & -\frac{f_yY'}{{Z'}^2} & -f_y-\frac{f_y{Y'}^2}{{Z'}^2} & \frac{f_yX'Y'}{{Z'}^2} & \frac{f_yX'}{Z'} \end{bmatrix}
∂δξ∂e=−[Z′fx00Z′fy−Z′2fxX′−Z′2fyY′−Z′2fxX′Y′−fy−Z′2fyY′2fx+Z′2fxX′2Z′2fyX′Y′−Z′fxY′Z′fyX′]
误差关于特征点
P
P
P 的导数:
∂
e
∂
P
=
−
[
f
x
Z
′
0
−
f
x
X
′
Z
′
2
0
f
y
Z
′
−
f
y
Y
′
Z
′
2
]
R
\frac{\partial e}{\partial P} = - \begin{bmatrix} \frac{f_x}{Z'} & 0 & -\frac{f_xX'}{{Z'}^2} \\ 0 & \frac{f_y}{Z'} & -\frac{f_yY'}{{Z'}^2} \end{bmatrix} R
∂P∂e=−[Z′fx00Z′fy−Z′2fxX′−Z′2fyY′]R
其中,
[
X
′
,
Y
′
,
Z
′
]
T
=
(
T
P
)
1
:
3
[X',Y',Z']^T = (TP)_{1:3}
[X′,Y′,Z′]T=(TP)1:3,所以
T
T
T、
P
P
P每一次迭代后,
X
′
X'
X′、
Y
′
Y'
Y′、
Z
′
Z'
Z′的值就会发生改变,从而再一次去更新上面的导数值,知道最后达到最优化。
重投影误差的g2o实现参考文章案例2。
6.5 3D-3D ICP
:::tip 针对问题
已经知道两个坐标系下的两组3D点,
P
=
p
1
,
.
.
.
,
P
n
,
P
′
=
P
1
′
,
.
.
.
,
P
n
′
P={p_1,...,P_n}, P'={P_1',...,P_n'}
P=p1,...,Pn,P′=P1′,...,Pn′,求他们之间的位姿变换
R
,
t
R,t
R,t。
:::
同样的,有两种方法可以解决这类问题:线性求解(SVD)
、非线性优化求解
。
- SVD 方法
首先定义第 i i i 对点的误差项:
e i = p i − ( R p i ′ + t ) e_i = p_i - (Rp_i' + t) ei=pi−(Rpi′+t)
然后构建最小二乘问题:
min R , t 1 2 ∑ i = 1 n ∥ ( p i − ( R p i ′ + t ) ) ∥ 2 2 \min_{R,t} \frac{1}{2} \sum_{i=1}^n \| (p_i - (Rp_i' + t)) \|_2^2 R,tmin21i=1∑n∥(pi−(Rpi′+t))∥22
如果定义两组点的质心:
p = 1 n ∑ i = 1 n ( p i ) , p ′ = 1 n ∑ i = 1 n ( p i ′ ) p=\frac{1}{n} \sum_{i=1}^{n}(p_i),p'=\frac{1}{n} \sum_{i=1}^{n}(p_i') p=n1i=1∑n(pi),p′=n1i=1∑n(pi′)
经过推导,最后的优化目标函数可以简化为:
min
R
,
t
J
=
1
2
∑
i
=
1
n
∥
p
i
−
p
−
R
(
p
i
′
−
p
′
)
∥
2
+
∥
p
−
R
p
′
−
t
∥
2
\min_{R,t} J = \frac{1}{2} \sum_{i=1}^{n} \| p_i - p - R(p_i' - p') \|^2 + \| p- Rp' - t\|^2
R,tminJ=21i=1∑n∥pi−p−R(pi′−p′)∥2+∥p−Rp′−t∥2
仔细观察左右两项,我们发现左边只和旋转矩阵
R
R
R 相关,而右边既有
R
R
R 也有
t
t
t,但只和质心相关。我们获得了
R
R
R,令第二项为零就能得到
t
t
t。
:::tip ICP分为以下三个步骤求解:
- 计算两组点的质心位置
p
,
p
′
p,p'
p,p′,然后计算每个点的去质心坐标:
q i = p i − p , q i ′ = p i ′ − p ′ q_i = p_i - p,q_i' = p_i' - p' qi=pi−p,qi′=pi′−p′ - 根据以下优化问题计算旋转矩阵:
R ∗ = arg min R 1 2 ∑ i = 1 n ∥ q i − R q i ′ ∥ 2 R^* = \arg \min_{R} \frac{1}{2} \sum_{i=1}^n \| q_i - Rq_i'\|^2 R∗=argRmin21i=1∑n∥qi−Rqi′∥2 - 根据第2步的
R
R
R 计算
t
t
t:
t ∗ = p − R p ′ t^* = p - Rp' t∗=p−Rp′
:::
- 非线性优化方法
非线性优化方法和 PnP 的优化一样,不过在优化过程中,仅在一次迭代之后就已经收敛。
7 视觉里程计(直接法)
7.1 2D 光流
:::tip
直接法是由光流演变而来的。光流描述了像素在图像中的运动,而直接法则附带着一个相机运动模型。
:::
对于图像中的运动,假设同一个物体的灰度像素不变,那么它会随着时间的流逝出现在不同的位置,我们要做的就是判断它在图像上的运动方向。其中,计算部分像素运动的称为稀疏光流
,计算所有像素的称为稠密光流
。稀疏光流方法: Lucas-Kanade
、高斯牛顿法
,稠密光流:Horn-Schunck
。
7.1.1 Lucas-Kanade 光流
光流问题的前提假设是 灰度不变 :同一个空间点的像素灰度值,在各个图像中是固定不变的。
对于
t
t
t 时刻位于
(
x
,
y
)
(x,y)
(x,y) 处的像素,我们设
t
+
d
t
t + dt
t+dt 时刻它运动到
(
x
+
d
x
,
y
+
d
y
)
(x+dx, y+dy)
(x+dx,y+dy) 处,由于灰度不变,可以得到:
I
(
x
+
d
x
,
y
+
d
y
,
t
+
d
t
)
=
I
(
x
,
y
,
t
)
I(x+dx,y+dy, t+dt) = I(x,y,t)
I(x+dx,y+dy,t+dt)=I(x,y,t)
对等式左边泰勒展开:
I
(
x
+
d
x
,
y
+
d
y
,
t
+
d
t
)
≈
I
(
x
,
y
,
t
)
+
∂
I
∂
x
d
x
+
∂
I
∂
y
d
y
+
∂
I
∂
t
d
t
I(x+dx, y+dy, t+dt) \approx I(x,y,t) + \frac{\partial I}{\partial x}dx + \frac{\partial I}{\partial y}dy + \frac{\partial I}{\partial t}dt
I(x+dx,y+dy,t+dt)≈I(x,y,t)+∂x∂Idx+∂y∂Idy+∂t∂Idt
由于假设了灰度不变,通过上式可以得到:
∂
I
∂
x
d
x
+
∂
I
∂
y
d
y
+
∂
I
∂
t
d
t
=
0
\frac{\partial I}{\partial x}dx + \frac{\partial I}{\partial y}dy + \frac{\partial I}{\partial t}dt = 0
∂x∂Idx+∂y∂Idy+∂t∂Idt=0
等式两边处以
d
t
dt
dt,得到:
∂
I
∂
x
d
x
d
t
+
∂
I
∂
y
d
y
d
t
=
−
∂
I
∂
t
\frac{\partial I}{\partial x}\frac{dx}{dt} + \frac{\partial I}{\partial y}\frac{dy}{dt} = - \frac{\partial I}{\partial t}
∂x∂Idtdx+∂y∂Idtdy=−∂t∂I
设,
d
x
d
t
\frac{dx}{dt}
dtdx 是在
x
x
x 轴上的运动速度
u
u
u,
d
y
d
t
\frac{dy}{dt}
dtdy 是在
y
y
y 轴上的运动速度
v
v
v,同时,
∂
I
∂
x
\frac{\partial I}{\partial x}
∂x∂I 是该点在
x
x
x 方向的梯度
I
x
I_x
Ix,
∂
I
∂
x
\frac{\partial I}{\partial x}
∂x∂I 是在
y
y
y 方向的梯度
I
y
I_y
Iy。把图像灰度对时间的变化量记为
I
t
I_t
It:
[
I
x
I
y
]
[
u
v
]
=
−
I
t
\begin{bmatrix} I_x & I_y \end{bmatrix} \begin{bmatrix} u \\ v \end{bmatrix} = -I_t
[IxIy][uv]=−It
我们想计算的是像素的运动
u
,
v
u,v
u,v,但是该式是带有两个变量的一次方程,仅凭它无法计算出
u
,
v
u,v
u,v。因此需要其他的约束条件,由于在 LK 光流中假设了某以窗口内
w
×
w
w\times w
w×w 的像素具有相同的运动(窗口指追踪像素附近的一块区域),那我们可以把窗口内的像素一起加入运算,形成超定线性方程:
[
I
x
I
y
]
k
[
u
v
]
=
−
I
t
k
,
k
=
1
,
.
.
.
,
w
2
\begin{bmatrix} I_x & I_y \end{bmatrix}_k \begin{bmatrix} u \\ v \end{bmatrix}{} = -I_{tk}, k=1,...,w^2
[IxIy]k[uv]=−Itk,k=1,...,w2
传统的解法是求最小二乘解。opencv 有自带的 LK 算法模块:
cv::calcOpticalFlowPyrLK(img1, img2, pt1, pt2, status, error);
:::details
#include <opencv2/opencv.hpp>
#include <iostream>
int main()
{
cv::Mat img1, img2;
img1 = cv::imread("./cancer1-1.jpg", 1);
img2 = cv::imread("./cancer1-2.jpg", 1);
std::vector<cv::KeyPoint> kp1;
cv::Ptr<cv::GFTTDetector> detector = cv::GFTTDetector::create(500, 0.01, 20); // maximum 500 keypoints
detector->detect(img1, kp1); // 从img1中提取特征点
std::vector<cv::Point2f> pt1, pt2;
for (auto &kp: kp1) pt1.push_back(kp.pt); // 改变特征点格式,从 KeyPoint 到 Point2f
std::vector<uchar> status;
std::vector<float> error;
cv::calcOpticalFlowPyrLK(img1, img2, pt1, pt2, status, error); // 计算光流
for (int i = 0; i < pt2.size(); i++) {
if (status[i]) { // 如果存在对应光流点,就绘制下面的点、线
cv::circle(img1, pt1[i], 2, cv::Scalar(0, 255, 0), 2);
cv::line(img1, pt1[i], pt2[i], cv::Scalar(0, 255, 0));
}
}
cv::imshow("1", img1);
cv::waitKey(0);
return 0;
}
:::
7.1.2 高斯牛顿法
-
单层光流
我们可以将其定义为一个最小二乘问题:
min Δ x , Δ y ∥ I 1 ( x , y ) − I 2 ( x + Δ x , y + Δ y ) ∥ 2 2 \min_{\Delta x, \Delta y} \| I_1(x,y) - I_2(x+\Delta x,y + \Delta y)\|_2^2 Δx,Δymin∥I1(x,y)−I2(x+Δx,y+Δy)∥22
其中,误差 e e e 为:
e = I 1 ( x , y ) − I 2 ( x + Δ x , y + Δ y ) e = I_1(x,y) - I_2(x+\Delta x,y + \Delta y) e=I1(x,y)−I2(x+Δx,y+Δy)
各项偏导:
∂ e i ∂ Δ x = I 2 ( x + Δ x + 1 , y + Δ y ) − I 2 ( x + Δ x − 1 , y + Δ y ) 2 \frac{\partial e_i}{\partial \Delta x} = \frac{I_2(x + \Delta x + 1, y + \Delta y) - I_2(x + \Delta x - 1, y + \Delta y)}{2} ∂Δx∂ei=2I2(x+Δx+1,y+Δy)−I2(x+Δx−1,y+Δy)
∂ e i ∂ Δ y = I 2 ( x + Δ x , y + Δ y + 1 ) − I 2 ( x + Δ x , y + Δ y − 1 ) 2 \frac{\partial e_i}{\partial \Delta y} = \frac{I_2(x + \Delta x, y + \Delta y + 1) - I_2(x + \Delta x , y + \Delta y - 1)}{2} ∂Δy∂ei=2I2(x+Δx,y+Δy+1)−I2(x+Δx,y+Δy−1)
雅可比为 J = [ ∂ e i ∂ Δ x ∂ e i ∂ Δ y ] T J = \begin{bmatrix} \frac{\partial e_i}{\partial \Delta x} & \frac{\partial e_i}{\partial \Delta y} \end{bmatrix}^T J=[∂Δx∂ei∂Δy∂ei]T,然后通过下面的方程求出更新量 Δ a \Delta a Δa:
( ∑ i = 1 N J i J i T ) Δ a = ∑ i = 1 N − J i e i (\sum_{i=1}^{N} J_i J_i^T) \Delta a = \sum_{i=1}^{N} -J_i e_i (i=1∑NJiJiT)Δa=i=1∑N−Jiei
7.2 直接法
8 后端(BA)
BA 是指从视觉图像中提炼出最优的 3D 模型和相机参数(内参和外参)。
9 后端(位姿)
优化位姿。
10 回环检测
如果像视觉里程计那样只估计相邻帧之间的位姿,那么随着时间的推移,误差会慢慢的累积,那么这样就会对构建全局图会有很大的影响。由于在相机运动的过程中,存在相机回到原位置的情况,那么我们就可以根据这两个时刻的位置来优化整个过程中的位姿变换。
所以我们要解决的问题就是如何判断相机回到了原位置,这里采用 SLAM 的主流方法,即通过特征向量来计算图像的相似性。该方法和前端、后端的估计没有关系,只需要找出图像中特征点,然后根据类型统计这些特征点从而生成一个特征向量,计算向量之间的距离即可表示图像的相似性。
由于特征点有多种类型,所以采用 字典 的方法来存储这些特征,相关的使用参考这里。