视觉前端
特征点法
ORB特征
基本原理
ORB算法将FAST特征点的检测方法和BRIEF特征描述子结合起来,并进行改进和优化。
算法步骤
-
利用FAST检测特征点,然后利用Harris角点的度量方法,从FAST特征点中挑选除Harris角点响应值最大的N个特征点。其中响应函数为
R = d e t ( M ) − k ( t r a c e ( M ) ) 2 R=det(M)-k(trace(M))^2 R=det(M)−k(trace(M))2
ORB中用NMS来筛选关键点,只保留分数最大的前n个关键点。由于FAST关键点不具备尺度不变性,因此ORB采用了图像金字塔来实现尺度不变性,通过构建高斯金字塔,然后在每一层金字塔图像上检测角点。 -
利用灰度质心法实现BRIEF描述子的旋转不变性。
灰度质心法认为角点的灰度和质心之间存在一个偏移,这个向量可以用于表示方向。对于任意特征点p,p的领域像素的矩定义为:
m i j = ∑ x = − r r ∑ y = − r r x i y j I ( x , y ) m_{ij}=\sum\limits_{x=-r}^{r}\sum\limits_{y=-r}^{r}x^iy^jI(x,y) mij=x=−r∑ry=−r∑rxiyjI(x,y)
其中 I ( x , y ) I(x,y) I(x,y)为点 ( x , y ) (x,y) (x,y)处的灰度值, q q q为质心, i , j = 0 , 1 i,j=0,1 i,j=0,1。那么我们可以得到图像的质心为:
C = ( m 10 m 00 , m 01 m 00 ) C=(\frac{m_{10}}{m_{00}},\frac{m_{01}}{m_{00}}) C=(m00m10,m00m01)
那么特征点与质心的夹角定义为FAST特征点的方向:
θ = a r c t a n ( m 01 , m 10 ) \theta=arctan(m_{01},m_{10}) θ=arctan(m01,m10)
BRIEF描述子是通过比较中心像素点p的任意邻域内的256对像素间的差值来生成二进制描述子,其结果是一个长度为256的二值码串,由特征点邻域内的256个点对组成,这 2 × 256 2\times256 2×256个点 ( x i , y i ) , i = 1 , 2 , . . . . . , 2 n (x_i,y_i),i=1,2,.....,2n (xi,yi),i=1,2,.....,2n组成一个矩阵 S S S:
S = [ x 1 x 2 . . . x 2 n y 1 y 2 . . . y 2 n ] S=\begin{bmatrix} x_1 & x_2 & ... &x_{2n} \\ y_1 & y_2 & ... & y_{2n} \end{bmatrix} S=[x1y1x2y2......x2ny2n]
ORB使用邻域方向 θ \theta θ和对应的旋转矩阵 R θ R_{\theta} Rθ,构建 S S S的校正版本 S θ S_{\theta} Sθ:
S θ = R θ S S_{\theta}=R_{\theta}S Sθ=RθS
其中,
R θ = [ c o s θ s i n θ − s i n θ c o s θ ] R_{\theta}=\begin{bmatrix} cos\theta & sin\theta \\ -sin\theta & cos\theta \end{bmatrix} Rθ=[cosθ−sinθsinθcosθ]
θ \theta θ就是上面求得的FAST特征点的方向。对于任意一对像素点 x i , y i x_i,y_i xi,yi,若 x i < y i x_i<y_i xi<yi,则该位置的描述子为1,否则为0。
-
rBRIEF解决描述子的区分性。
光流法
光流约束方程
光流基于如下两个假设:
- 在很短的时间内目标的像素值不会变化;
- 邻近的像素具有相似的运动。
令
I
(
x
,
y
,
t
)
I(x,y,t)
I(x,y,t)表示t时刻的像素点
(
x
,
y
)
(x,y)
(x,y)的灰度值,则根据亮度恒定假设,我们有:
I
(
x
,
y
,
t
)
=
I
(
x
+
Δ
x
,
y
+
Δ
y
,
t
+
Δ
t
)
I(x,y,t) = I(x + \Delta x, y + \Delta y, t + \Delta t)
I(x,y,t)=I(x+Δx,y+Δy,t+Δt)
我们对上式右侧进行一阶Taylor展开,可得:
I
(
x
+
Δ
x
,
y
+
Δ
y
,
t
+
Δ
t
)
≈
I
(
x
,
y
,
t
)
+
∂
I
∂
x
Δ
x
+
∂
I
∂
y
Δ
y
+
∂
I
∂
t
Δ
t
I(x + \Delta x, y + \Delta y, t + \Delta t) \approx I(x,y,t) + \frac{\partial I}{\partial x}\Delta x + \frac{\partial I}{\partial y}\Delta y + \frac{\partial I}{\partial t}\Delta t
I(x+Δx,y+Δy,t+Δt)≈I(x,y,t)+∂x∂IΔx+∂y∂IΔy+∂t∂IΔt
最后得到光流约束方程:
∂
I
∂
x
Δ
x
+
∂
I
∂
y
Δ
y
+
∂
I
∂
t
Δ
t
=
0
\frac{\partial I}{\partial x}\Delta x + \frac{\partial I}{\partial y}\Delta y + \frac{\partial I}{\partial t}\Delta t = 0
∂x∂IΔx+∂y∂IΔy+∂t∂IΔt=0
由于这个方程有两个未知数
(
Δ
x
,
Δ
y
)
(\Delta x,\Delta y)
(Δx,Δy),所以没有唯一解。为了得到唯一解,就必须新增约束或假设,因此也就有了不同的算法。
Lucas-Kanade算法
Lucas-Kanade算法假设局部光流恒定,他使用一个3x3的patch,patch内的9个像素都具有同样的运动。因此,问题变为了:9个方程,求解2个未知数。算法使用最小二乘法(GN)迭代求解:
[
Δ
x
Δ
y
]
=
[
∑
i
f
x
i
2
∑
i
f
x
i
f
y
i
∑
i
f
x
i
f
y
i
∑
i
f
y
i
2
]
−
1
[
−
∑
i
f
x
i
f
t
i
−
∑
i
f
y
i
f
t
i
]
=
[
J
J
T
]
−
1
[
−
J
r
]
\begin{bmatrix} \Delta x \\ \Delta y \end{bmatrix} = \begin{bmatrix} \sum_{i}{f_{x_i}}^2 & \sum_{i}{f_{x_i} f_{y_i} } \\ \sum_{i}{f_{x_i} f_{y_i}} & \sum_{i}{f_{y_i}}^2 \end{bmatrix}^{-1} \begin{bmatrix} - \sum_{i}{f_{x_i} f_{t_i}} \\ - \sum_{i}{f_{y_i} f_{t_i}} \end{bmatrix} = [JJ^T]^{-1}[-Jr]
[ΔxΔy]=[∑ifxi2∑ifxifyi∑ifxifyi∑ifyi2]−1[−∑ifxifti−∑ifyifti]=[JJT]−1[−Jr]
其中
f
x
=
∂
I
∂
x
=
I
2
(
x
+
Δ
x
+
1
,
y
+
Δ
y
)
−
I
2
(
x
+
Δ
x
−
1
,
y
+
Δ
y
)
2
f
y
=
∂
I
∂
y
=
I
2
(
x
+
Δ
x
,
y
+
Δ
y
+
1
)
−
I
2
(
x
+
Δ
x
,
y
+
Δ
y
−
1
)
2
J
=
[
f
x
,
f
y
]
T
,
r
=
f
t
=
预
测
值
−
真
实
值
=
I
2
(
x
+
Δ
x
,
y
+
Δ
y
)
−
I
1
(
x
,
y
)
f_x = \frac{\partial I}{\partial x}=\frac{I_2(x+\Delta x+1,y+\Delta y)-I_2(x+\Delta x-1,y+\Delta y)}{2} \\ f_y = \frac{\partial I}{\partial y}=\frac{I_2(x+\Delta x,y+\Delta y+1)-I_2(x+\Delta x,y+\Delta y-1)}{2}\\ J = [f_x,f_y]^T , \quad r=f_t=预测值-真实值=I_2(x+\Delta x,y+\Delta y)-I_1(x,y)
fx=∂x∂I=2I2(x+Δx+1,y+Δy)−I2(x+Δx−1,y+Δy)fy=∂y∂I=2I2(x+Δx,y+Δy+1)−I2(x+Δx,y+Δy−1)J=[fx,fy]T,r=ft=预测值−真实值=I2(x+Δx,y+Δy)−I1(x,y)
注意,式中的逆矩阵和Harris角点检测中的M很像,这表明角点更适合跟踪。
为了解决较大运动时无法跟踪的问题,算法使用图像金字塔,当图像进行上采样时,大运动变成了小运动,小运动被去除了。
直接法
外点处理(估计基础矩阵)
参考 RANSAC&鲁棒核函数
外点
传感器测量值可能会受多种因素干扰而不可靠,同时特征匹配也会存在误匹配的情况,如果不正确地检测并剔除他们,视觉SLAM中的很多算法(如计算本质矩阵、三角测量、PnP等)将会失败。
我们将非常不可能的测量值(根据测量模型)称为外点(outlier)。
对外点的一种常用判断标准是(一维数据中)将超出平均值三个标准差的测量值作为外点。
处理外点的两种最常用方案为:
1、RANSAC,选择正确的匹配进行估计。
2、M-估计,降低错误匹配的权重。
RANSAC
随机采样一致性(random sample consensus,RANSAC)是一种对带有外点的数据拟合参数模型的迭代方法。
该方法的目的是从所有数据中选择内点数据,用于估计。首先给出如下定义:
点:每一个数据,SLAM里指的是匹配的点对
野值/外点:错误的点
内点:正确的点
内点集:内点的集合
外点集:外点的集合
模型:带估计的参数
s s s:估计模型所需要的最小点数
S S S:所有的点形成的点集
显然,内点集就是我们想要找的正确数据。RANSAC的想法是从点集中随机的选择出 s s s个点,估计出一个模型,查看剩余点是否符合这个模型。如果大部分点都符合这个模型,就相当于我们找到了一个合适的模型,自然的符合模型的点就是内点啦。由于是随机选择,一次可能难以找到正确的模型,因此需要多次才可以。下面给出完整的RANSAC算法。
目标
一个模型与含离群值的数据集S的鲁棒拟合。
算法
STEP 1. 随机的从 S S S中选择 s s s个点作为一个样本,估计出模型。
STEP 2. 确定在模型距离阈值 t t t内的数据点集 S i S_i Si , S i S_i Si为采样的一致集,并定义为S的内点。
STEP 3. 如果 S i S_i Si的大小(内点数)大于某个阈值 T T T,用所有内点 S i S_i Si重新估计模型并结束。
STEP 4. 如果 S i S_i Si的大小小于阈值 T T T,则选择一个新的自己,重复上述步骤
STEP 5. 经过 N N N次试验,选择最大一致集 S i S_i Si,并用 S i S_i Si的所有点重新估计模型
RANSAC中有三个参数需要确定,分别是 t t t、 T T T、 N N N。
1 内点阈值t
根据模型,每个点可以计算出一个距离的平方
d
2
d^2
d2,利用阈值
t
2
t^2
t2即可判断该点是否为内点。
d
2
d^2
d2的选择要根据具体模型进行选择,基本矩阵估计中采用点到极线的距离的平方,单应和相机内参估计中使用点到点的距离的平方。m个独立标准正态分布的平方和服从m自由度的卡方分布,选择阈值
t
t
t使得点为内点的概率为
α
\alpha
α。可以基于下式判断是否为内点:
{
I
n
l
i
e
r
d
2
<
t
2
O
u
t
l
i
e
r
d
2
≥
t
2
,
w
h
e
r
e
t
2
=
F
−
1
(
α
)
σ
2
\left \{ \begin{aligned} Inlier &\quad d^2 < t^2 \\ Outlier &\quad d^2 \ge t^2, \quad where \quad t^2=F^{-1}(\alpha)\sigma^2 \end{aligned} \right.
{InlierOutlierd2<t2d2≥t2,wheret2=F−1(α)σ2
一般取
α
=
95
%
\alpha=95\%
α=95%。
2 采样次数N
假设一个点为内点的概率为w,则外点概率为 ϵ = 1 − w \epsilon=1-w ϵ=1−w,我们要求:
事件A:在 N N N次采样中,至少要有一次选取的子集 s s s内没有外点的概率 p = 0.99 p=0.99 p=0.99。
事件A的逆事件为:N次采样中,所有选取的子集 s s s内至少存在一个外点。这个概率为 ( 1 − w s ) N = 1 − p (1-w^s)^N=1-p (1−ws)N=1−p。那么
N = log ( 1 − p ) log ( 1 − w s ) N=\frac{\log(1-p)}{\log(1-w^s)} N=log(1−ws)log(1−p)
由此可得,采样次数与内外点的比例有关,而与数据量无关;并且随着最小点数s的增大而增大。
3 内点数量阈值T
当我们发现内点的数量足够多的时候就可以提前结束采样。内点数量的阈值 T T T如何决定呢?我们一般认为,在给定外点的比例 ϵ \epsilon ϵ时,对于数据个数 n n n,有 T = ( 1 − ϵ ) n T=(1-\epsilon)n T=(1−ϵ)n。这个比例可以估计的稍微保守一些。
4 自适应决定采样次数
从(1)可以看出,采样次数N与内点概率w有关,但实际情况是,一组数据中有多少内点事先是未知的。
开始时可以设 w = 0 w=0 w=0,此时 N = ∞ N=\infin N=∞ 。经过一次采样后,设获得的内点数为 n i n_i ni,可以更新内点概率为 w = n i n w=\frac{n_i}{n} w=nni,从而更新一次 N N N。如此,迭代往复,每次若发现内点个数增加,就更新 N N N。
改进后的RANSAC算法如下:
N = ∞ N=\infin N=∞,sample_count = 0
if (N > sample_count)
选取s个样本,拟合模型,并根据t计算内点数inliers_count;
if (inliers_count > pre_inliers_count): // 新内点数增加,更新N
w = inliers_count / n;
N = log(1.0 - p) / log(1.0 - std::pow(w, s));
end
sample_count++;
end
RANSAC与最小二乘的区别:
最小二乘法尽量去适应包括外点在内的所有点。而RANSAC得出一个仅仅用内点计算出模型,并且概率还足够高。但是,RANSAC不能保证结果一定正确(只有一定的概率得到可信的模型),为了保证算法有足够高的合理概率,必须小心选择算法的参数。对于外点数量较多的数据集,RANSAC的效果远优于直接的最小二乘法。
RANSAC估计基础矩阵
输入:2d-2d匹配关系 vector<Point2f> pts1, pts2;ransac内点距离阈值 double ransac_thresh=3; 置信度 double confidence = 0.9
输出:匹配关系是否为内点 vector<uchar> status; F矩阵 Eigen::Matrix3d F
步骤:
0、计算采样次数N(maxIters)
N
=
log
(
1
−
p
)
log
(
1
−
w
k
)
N=\frac{\log(1-p)}{\log(1-w^k)}
N=log(1−wk)log(1−p)
其中,p为在N次采样中,至少有一次选取的子集s内没有外点的概率;k为拟合模型需要的样本数,对应基础矩阵num_samples=8;w为一个点为内点的概率。
Example: For w = 50%, p = 99%, k = 8: M = log(0.001) / log(0.99609) = 1176,即需要采样1176次从而保证RANSAC的成功率不低于0.99.
for i = 0 to maxIters:
随机选取8对匹配点 => Mat<double, 3, 8> pset1, pset2 #齐次坐标(u,v,1)
8点法估计F矩阵
{
DLT构建矩阵 A(x'x, x'y, x', y'x, y'y, y', x, y, 1) * f_9x1 = 0
SVD分解 A = U * S * V.T
取V的最后一列作为基础矩阵的初值 f = V.col(8) => 由f构建矩阵F
奇异值约束 F = U * diag(s1, s2, 0) * V.T
}
统计内点个数 findInliers
{
d = ransac_thresh * ransac_thresh;
inliers = 0;
for i = 0 to M:
error = (x'.T * F * x)^2 / ( (F*x)_1^2 + (F*x)_2^2 + (F.T*x')_1^2 + (F.T*x')_2^2 ); #sampson距离
if (error < d)
inliers++;
}
更新最好估计
if (inliners > best_inliers)
best_inliers = inliers;
根据最好估计的所有内点使用最小二乘重新估计F矩阵
F = calcFundamentalLeastSquare(best_inliers, pts1, pts2);
M-估计
SLAM中的很多状态估计都是以最小化误差平方和作为代价函数,一个偏离较大的外点会对估计结果产生巨大的影响。而M估计的主要思想便是将原先误差的平方项替换为一个增长没那么快的函数,同时保证自己的光滑性质(能求导),获得更加鲁棒的最小二乘,这个函数又称为鲁棒核函数。
常见的鲁棒核函数有Huber核:
对极几何2D-2D
对极几何求解位姿
在特征匹配后,通过对极几何得到2D-2D关系。对极几何是两幅视图之间内在的射影几何,它独立于景物,只依赖于相机的内参和相对位姿。对极几何约束了一幅图上的点在另一幅图上的对应位置应在对极线上。
x
2
=
R
x
1
+
t
x_2=Rx_1+t
x2=Rx1+t
通过等式两边分别先后左乘
[
t
]
×
[t]_{\times}
[t]×和
x
2
T
x_2^T
x2T,可以得到:
x
2
T
[
t
]
×
R
x
1
=
p
2
T
K
−
T
[
t
]
×
R
K
−
1
p
1
=
0
x^T_2[t]_{\times}Rx_1=p_2^TK^{-T}[t]_{\times}RK^{-1}p_1=0
x2T[t]×Rx1=p2TK−T[t]×RK−1p1=0
根据对极几何可以推导出对极约束:
x
2
T
E
x
1
=
p
2
T
F
p
1
=
0
x^T_2Ex_1=p_2^TFp_1=0
x2TEx1=p2TFp1=0
E为本质矩阵,F为基础矩阵,分别对应归一化平面坐标和像素坐标的对极几何关系。一般使用8点法求解基础矩阵和本质矩阵,若匹配点对多于8对,则可用RANSAC进行求解(见外点处理)。
8点法求基本矩阵:
-
对于一对像素坐标点 ( x , y , 1 ) T (x,y,1)^T (x,y,1)T和 ( x ′ , y ′ , 1 ) T (x',y',1)^T (x′,y′,1)T,将方程展开,重构成:
( x ′ x , x ′ y , x ′ , y ′ x , y ′ y , y ′ , x , y , 1 ) f 9 × 1 = 0 (x'x,x'y,x',y'x,y'y,y',x,y,1)\bold{f}_{9\times1}=0 (x′x,x′y,x′,y′x,y′y,y′,x,y,1)f9×1=0 -
由于F的自由度为8,因此最少需要8个点即可求解该方程,通过构造8个点的矩阵A,对其进行SVD分解,由A对应的最小奇异值的奇异向量确定F。
根据估计出来的本质矩阵E,可以通过SVD分解恢复出相机的外参R和t。设E的SVD分解为
E
=
U
S
V
T
E=USV^T
E=USVT,其中
S
=
d
i
a
g
(
σ
,
σ
,
0
)
S=diag(\sigma,\sigma,0)
S=diag(σ,σ,0),则R和t的可能结果为:
t
1
=
U
(
:
,
2
)
,
R
1
=
U
R
z
(
π
2
)
V
T
t
2
=
−
U
(
:
,
2
)
,
R
2
=
U
R
z
T
(
π
2
)
V
T
t_1=U(:,2),\quad R_1=UR_z(\frac{\pi}{2})V^T \\ t_2=-U(:,2),\quad R_2=UR^T_z(\frac{\pi}{2})V^T
t1=U(:,2),R1=URz(2π)VTt2=−U(:,2),R2=URzT(2π)VT
其中,
R
z
(
π
2
)
=
[
0
−
1
0
1
0
0
0
0
1
]
,
R
z
T
(
π
2
)
=
[
0
1
0
−
1
0
0
0
0
1
]
R_z(\frac{\pi}{2})=\begin{bmatrix} 0 & -1 & 0 \\ 1 & 0 & 0 \\ 0 & 0 & 1 \end{bmatrix},\quad R^T_z(\frac{\pi}{2})=\begin{bmatrix} 0 & 1 & 0 \\ -1 & 0 & 0 \\ 0 & 0 & 1 \end{bmatrix}
Rz(2π)=⎣⎡010−100001⎦⎤,RzT(2π)=⎣⎡0−10100001⎦⎤
因此一共存在4组可能的
[
R
,
t
]
[R, t]
[R,t]组合,如下图:
需要使得空间中一点同时位于两个相机的前方,以得到正确的相机位姿,具体方法为:
利用R、t和匹配点
p
1
,
p
2
p_1,p_2
p1,p2进行三角化得到地图点
P
P
P,P需要同时位于两个相机前方:
[
x
c
y
c
z
c
]
=
R
P
+
t
,
z
c
>
0
对
两
个
相
机
成
立
\begin{bmatrix} x_c \\y_c \\z_c \end{bmatrix}=RP+t,\quad z_c>0对两个相机成立
⎣⎡xcyczc⎦⎤=RP+t,zc>0对两个相机成立
单应性矩阵求解位姿
[ u 2 v 2 1 ] = [ h 1 h 2 h 3 h 4 h 5 h 6 h 7 h 8 h 9 ] [ u 1 v 1 1 ] \begin{bmatrix} u_2 \\ v_2 \\ 1 \end{bmatrix} = \begin{bmatrix} h_1 & h_2 & h_3\\ h_4 & h_5 & h_6 \\ h_7 & h_8 & h_9 \end{bmatrix} \begin{bmatrix} u_1 \\ v_1 \\ 1 \end{bmatrix} ⎣⎡u2v21⎦⎤=⎣⎡h1h4h7h2h5h8h3h6h9⎦⎤⎣⎡u1v11⎦⎤
自由度为8的单应矩阵至少需要4对匹配点求解,当大于4对时,可以通过RANSAC方法进行估计。
4点法求单应矩阵:
对于方程
x
′
=
H
x
x'=\bold{H}x
x′=Hx,两边叉乘
x
′
x'
x′得:
x
′
×
H
x
=
0
\bold{x}'\times\bold{H}\bold{x}=\bold{0}
x′×Hx=0
把H的第j行记为
h
j
T
\bold{h}^{jT}
hjT,
x
\bold{x}
x记为
(
x
,
y
,
1
)
T
(x,y,1)^T
(x,y,1)T,则叉积可以写为:
x
′
×
H
x
=
[
y
′
h
3
T
x
−
h
2
T
x
h
1
T
x
−
x
′
h
3
T
x
x
′
h
2
T
x
−
y
′
h
1
T
x
]
\bold{x}'\times\bold{H}\bold{x}= \begin{bmatrix} y'\bold{h}^{3T}x - \bold{h}^{2T}x \\ \bold{h}^{1T}x-x'\bold{h}^{3T}x \\ x'\bold{h}^{2T}x-y'\bold{h}^{1T}x \end{bmatrix}
x′×Hx=⎣⎡y′h3Tx−h2Txh1Tx−x′h3Txx′h2Tx−y′h1Tx⎦⎤
由上式可以写出H的三个方程:
[
0
T
−
x
T
y
′
x
T
x
T
0
T
−
x
′
x
T
−
y
′
x
′
T
x
′
x
T
0
T
]
[
h
1
h
2
h
3
]
=
0
→
A
3
×
9
h
9
×
1
=
0
\begin{bmatrix} \bold{0}^T & -\bold{x}^T & y'\bold{x}^T \\ \bold{x}^T & \bold{0}^T & -x'\bold{x}^T \\ -y'\bold{x'}^T & x'\bold{x}^T & \bold{0}^T \end{bmatrix} \begin{bmatrix} \bold{h}_1\\ \bold{h}_2 \\ \bold{h}_3 \end{bmatrix} =\bold{0} \rightarrow \bold{A}_{3\times9}\bold{h}_{9\times1}=\bold{0}
⎣⎡0TxT−y′x′T−xT0Tx′xTy′xT−x′xT0T⎦⎤⎣⎡h1h2h3⎦⎤=0→A3×9h9×1=0
上式虽然有3个方程,但由于第3行可由前两行得到,因此每队点实际只能给出H的两个约束,而H的自由度为8。因此,至少需要4组点即可求解方程
A
2
n
×
9
h
=
0
\bold{A}_{2n\times9}\bold{h}=\bold{0}
A2n×9h=0,由A的最小奇异值对应的奇异向量确定h,从而确定矩阵H。
当相机做纯旋转时,
H
=
K
R
K
−
1
H=KRK^{-1}
H=KRK−1,由H可求解得相机的外参R。
在opencv中,使用cv::decomposeHomographyMat(H, K, Rs, Ts, cv::noArray());
求解位姿Rs、Ts。
基础矩阵、本质矩阵和单应矩阵自由度
1、基础矩阵自由度
首先F矩阵是三阶的,并且其满足尺度等价性(因为像素坐标通过齐次坐标表示,因此矩阵同乘一个常数,最后求得的坐标是一致的,即 F 33 = 1 F_{33}=1 F33=1),因此自由度减1,再其次F矩阵为不可逆矩阵,行列式为0,因此自由度再减1,因此F矩阵自由度为7。
PS:相机做纯平移运动时,F矩阵自由度退化为2,在纯平面运动时,自由度退化为6.
2、本质矩阵自由度
由于本质矩阵为 E = [ t ] × R E=[t]_{\times}R E=[t]×R,t和R都是3自由度,同时E满足尺度等价性,因此其自由度为5。
3、单应矩阵自由度
单应矩阵满足尺度等价性,因此自由度为8.
总结
-
基础矩阵表示的是两视图的对极约束,独立于景物结构,只依赖于摄像机的内部参数和相对姿态;本质矩阵是基础矩阵在归一化图像坐标下的表示;单应矩阵表示点和点之间的映射,但要求场景点在同一个平面上或者是相机纯旋转。
-
基础矩阵无法得到这个点对应点在另一幅图像上的确切位置(映射的是对极线);单应矩阵可以找到点在另一幅图像上对应点的确切位置。
-
当相机进行纯旋转时,或者场景中的点在同一平面上或近平面上,由于F矩阵会发生退化,必须使用单应矩阵H而不能使用基础矩阵F;当相机的平移距离相对于场景的深度较小,即低视差场景的时候也可以使用单应矩阵H。因此通常会同时估计基础矩阵F和单应矩阵H,选择重投影误差较小的作为运动估计矩阵(ORB-SLAM的初始化方法)。
PnP(3D-2D)
当知道n个3D地图点及其投影位置时,可以通过PnP估计相机位姿。前面提到的2D-2D的对极几何方法需要至少8个点对,且存在初始化、纯旋转和尺度的问题。PnP问题有多种求解方法,包括直接线性变化(DLT)、EPnP等,还能用非线性优化的motion-BA方法。
DLT
考虑某个空间点P,它的齐次坐标为 P = ( X , Y , Z , 1 ) T \bold{P}=(X,Y,Z,1)^T P=(X,Y,Z,1)T。在图像 I 1 I_1 I1中,投影到特征点 x 1 = ( u 1 , v 1 , 1 ) T x_1=(u_1,v_1,1)^T x1=(u1,v1,1)T(以归一化平面齐次坐标表示)。定义增广矩阵 [ R ∣ t ] [\bold{R}|\bold{t}] [R∣t]为3x4的矩阵,包括旋转和平移,则存在如下关系:
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⎦⎥⎥⎤
用最后一行消去s,得到两个约束:
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_1X+t_2Y+t_3Z+t_4}{t_9X+t_{10}Y+t_{11}Z+t_{12}},\quad v_1=\frac{t_5X+t_6Y+t_7Z+t_8}{t_9X+t_{10}Y+t_{11}Z+t_{12}}
u1=t9X+t10Y+t11Z+t12t1X+t2Y+t3Z+t4,v1=t9X+t10Y+t11Z+t12t5X+t6Y+t7Z+t8
将增广矩阵写成行向量形式有:
[
R
∣
t
]
=
[
t
1
t
2
t
3
]
[\bold{R}|\bold{t}]=\begin{bmatrix} \bold{t}_1 \\ \bold{t}_2 \\ \bold{t}_3 \end{bmatrix}
[R∣t]=⎣⎡t1t2t3⎦⎤
则两个约束可以写为:
t
1
T
P
−
t
3
T
P
u
1
=
0
t
2
T
P
−
t
3
T
P
v
1
=
0
\bold{t}_1^T\bold{P}-\bold{t}_3^T\bold{P}u_1=0 \\ \bold{t}_2^T\bold{P}-\bold{t}_3^T\bold{P}v_1=0
t1TP−t3TPu1=0t2TP−t3TPv1=0
可见每个特征点提供了两个关于T的线性约束,T一共有12维,因此最少需要6对匹配点即可求解。
在DLT求解中,我们直接将T矩阵看成了12个未知数,忽略了它们之间的联系。因为旋转矩阵
R
∈
S
O
(
3
)
\bold{R}\in SO(3)
R∈SO(3),需要针对DLT估计的旋转矩阵寻找一个最好的旋转矩阵做近似。可以通过QR分解,也可以把结果从矩阵空间重新投影到SE(3)流形上:
R
←
(
R
R
T
)
−
1
2
R
\bold{R} \leftarrow (\bold{R}\bold{R}^T)^{-\frac{1}{2}}\bold{R}
R←(RRT)−21R
motion-only BA
考虑n个地图点P和其投影p,我们希望计算相机的位姿R,t,假设某地图点3D坐标为
P
i
=
[
X
i
,
Y
i
,
Z
i
]
T
\bold{P}_i=[X_i,Y_i,Z_i]^T
Pi=[Xi,Yi,Zi]T,其投影的像素坐标为
p
i
=
[
u
i
,
v
i
]
T
\bold{p}_i=[u_i,v_i]^T
pi=[ui,vi]T,则像素位置和3D坐标的关系如下:
s
i
[
u
i
v
i
1
]
=
K
(
R
[
X
i
Y
i
Z
i
]
+
t
)
s_i\begin{bmatrix} u_i \\ v_i\\ 1\end{bmatrix} = \bold{K}(\bold{R}\begin{bmatrix} X_i\\ Y_i \\ Z_i \end{bmatrix}+\bold{t})
si⎣⎡uivi1⎦⎤=K(R⎣⎡XiYiZi⎦⎤+t)
其中,
s
i
s_i
si为地图点到相机的距离,
K
\bold{K}
K为相机内参矩阵。
由于相机位姿未知,该等式存在一个误差。因此,我们将误差求和,构建最小二乘问题,然后寻找最好的相机位姿,使重投影误差最小:
T
∗
=
arg
min
T
1
2
∑
i
=
1
n
∣
∣
p
i
−
1
s
i
K
(
R
P
i
+
t
)
∣
∣
2
2
\bold{T}^*=\arg \min_\bold{T} \frac{1}{2}\sum_{i=1}^n ||\bold{p}_i-\frac{1}{s_i}\bold{K}(\bold{R}\bold{P}_i + \bold{t}) ||^2_2
T∗=argTmin21i=1∑n∣∣pi−si1K(RPi+t)∣∣22
我们用
e
x
p
(
ξ
∧
)
exp( \xi^{\land} )
exp(ξ∧)表示相机的位姿
[
R
∣
t
]
[\bold{R}|\bold{t}]
[R∣t]的李代数,则最小二乘问题变为:
ξ
∗
=
arg
min
ξ
1
2
∑
i
=
1
n
∥
e
i
∥
2
2
=
arg
min
ξ
1
2
∑
i
=
1
n
∥
p
i
−
1
s
i
K
e
x
p
(
ξ
∧
)
P
i
∥
2
2
\xi^{\ast} = \mathop{\arg\min}_{\xi}\frac{1}{2}\sum_{i=1}^{n}\left\|e_i\right\|_2^{2} = \mathop{\arg\min}_{\xi}\frac{1}{2}\sum_{i=1}^{n}\left\|\bold{p}_i - \frac{1}{s_i}\bold{K}exp(\xi^{\land})\bold{P}_i\right\|_2^{2}
ξ∗=argminξ21i=1∑n∥ei∥22=argminξ21i=1∑n∥∥∥∥pi−si1Kexp(ξ∧)Pi∥∥∥∥22
通过链式法则,可以求得误差相对于位姿的雅可比矩阵:
∂
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} = -{\left[ \begin{array}{cccccc}\frac{f_{x}}{Z^{'}} & 0 & -\frac{f_{x}X^{'}}{Z^{'2}} & -\frac{f_{x}X^{'}Y^{'}}{Z^{'2}} & f_{x}+\frac{f_{x}X^{'2}}{Z^{'2}} & -\frac{f_{x}Y^{'}}{Z^{'}} \\ 0 & \frac{f_{y}}{Z^{'}} & -\frac{f_{y}Y^{'}}{Z^{'2}} & -f_{y}-\frac{f_{y}Y^{'2}}{Z^{'2}} & \frac{f_{y}X^{'}Y^{'}}{Z^{'2}} & \frac{f_{y}X^{'}}{Z^{'}} \end{array} \right]}
∂δξ∂e=−⎣⎡Z′fx00Z′fy−Z′2fxX′−Z′2fyY′−Z′2fxX′Y′−fy−Z′2fyY′2fx+Z′2fxX′2Z′2fyX′Y′−Z′fxY′Z′fyX′⎦⎤
通过g2o或者ceres即可求解该最小二乘问题。
EPnP
输入:N对3D-2D匹配关系 [ P i , p i c ] [P_i,p^c_i] [Pi,pic]
输出:相机位姿 T c w T^w_c Tcw
算法步骤:
// PCA选择控制点 c j w c^w_j cjw
cws[4] = choose_control_points()// 计算每个3D点的hb坐标 α i j \alpha_{ij} αij
computeBarycentricCoordinates()// 构建方程 M 2 N × 12 x = 0 M_{2N\times12}x=0 M2N×12x=0,求解控制点在相机坐标系下的坐标 x = [ c 1 c , c 2 c , c 3 c , c 4 c ] T x=[c^c_1,c^c_2,c^c_3,c^c_4]^T x=[c1c,c2c,c3c,c4c]T
M = constructM(K, u, alpha)// 上述方程解为 x = ∑ i = 1 N β i v i x=\sum_{i=1}^N \beta_i \bold{v}_i x=∑i=1Nβivi,v为M的右奇异向量,此处计算beta的近似解
betas = findBetaApprox()
// GN法优化beta
betas = GaussianNewton()
// 将3D点在相机系下的坐标 P i c P^c_i Pic恢复出来: P i c = ∑ j = 1 4 α i j c j c P^c_i=\sum_{j=1}^4 \alpha_{ij}c^c_j Pic=∑j=14αijcjc
P_c = cameraCoord(V, betas, P)
// 使用ICP计算位姿
R, t = ICP(P_c, P_w){
计算质心坐标 p c c , p c w p_c^c,p^w_c pcc,pcw
计算点的去质心坐标 P c , P w \bold{P}^c,\bold{P}^w Pc,Pw
计算R: W 3 × 3 = ( P c ) T P w , W = U S V T , R = U V T , 若 ∣ R ∣ < 0 , 则 R ( 2 , : ) = − R ( 2 , : ) W_{3\times3}=(\bold{P}^c)^T\bold{P}^w, W=USV^T,R=UV^T,若|R|<0,则R(2,:)=-R(2,:) W3×3=(Pc)TPw,W=USVT,R=UVT,若∣R∣<0,则R(2,:)=−R(2,:)
计算t: t = p c c − R p c w t=p^c_c-Rp^w_c t=pcc−Rpcw
}
ICP(3d-3d)
问题:给定两组点
A
=
[
a
1
,
.
.
.
,
a
N
]
∈
R
m
×
N
,
B
=
[
b
1
,
.
.
.
,
b
N
]
∈
R
m
×
N
A=[a_1,...,a_N]\in \mathbb{R}^{m\times N},B=[b_1,...,b_N]\in \mathbb{R}^{m\times N}
A=[a1,...,aN]∈Rm×N,B=[b1,...,bN]∈Rm×N,计算它们之间的刚体变换:
f
(
R
,
t
)
=
1
N
∑
i
=
1
N
∥
b
i
−
R
a
i
−
t
∥
2
=
∥
B
−
R
A
−
t
∥
F
2
min
R
,
t
f
(
R
,
t
)
,
s
.
t
.
R
R
T
=
I
f(R,t)=\frac{1}{N}\sum_{i=1}^N \| b_i-Ra_i-t \|^2 = \| B-RA-t \|^2_F \\ \min_{R,t}f(R,t),s.t. RR^T=I
f(R,t)=N1i=1∑N∥bi−Rai−t∥2=∥B−RA−t∥F2R,tminf(R,t),s.t.RRT=I
算法:
- 对矩阵A、B进行归一化(去质心),得到A’、B’;
- 对 B ′ A ′ T B'A'^T B′A′T进行SVD分解,得到 B ′ A ′ T = U Σ V T B'A'^T=U\Sigma V^T B′A′T=UΣVT;
- 最优解为 R ∗ = U V T , 若 ∣ R ∣ < 0 , 则 R ( 2 , : ) = − R ( 2 , : ) ; t ∗ = 1 N ( B − R ∗ A ) 1 R^*=UV^T,若|R|<0,则R(2,:)=-R(2,:); t^*=\frac{1}{N}(B-R^*A)\bold{1} R∗=UVT,若∣R∣<0,则R(2,:)=−R(2,:);t∗=N1(B−R∗A)1
双目相机标定
ORB-SLAM2中的D,K,R,P分别代表畸变参数向量(5x1)、相机内参(3x3)、相机旋转矩阵(3x3)、相机投影矩阵(3x4)。
对于一个3D点
X
=
(
X
i
,
Y
i
,
Z
i
,
1
)
T
\bold{X}=(X_i,Y_i,Z_i,1)^T
X=(Xi,Yi,Zi,1)T,通过投影矩阵P将其投影到图像坐标x上:
[
x
i
y
i
1
]
=
P
[
X
i
Y
i
Z
i
1
]
\begin{bmatrix} x_i \\ y_i \\ 1\end{bmatrix} = \bold{P} \begin{bmatrix} X_i\\Y_i\\Z_i \\ 1\end{bmatrix}
⎣⎡xiyi1⎦⎤=P⎣⎢⎢⎡XiYiZi1⎦⎥⎥⎤
投影矩阵P维度为3x4,自由度为11,可以分解为:
P
=
K
[
R
∣
t
]
\bold{P}=\bold{K}[\bold{R}|\bold{t}]
P=K[R∣t]
相机标定算法就是为了求解矩阵P和相机的内参K和外参R、t。其主要分为两步:
- 通过已知3D点的3D坐标和像素坐标,最小化重投影误差求解矩阵P。
- 通过QR分解求解K,R,t。
三角化
对于单目SLAM,仅通过单张图像无法获取像素的深度信息,需要通过三角化的方法来估计地图点深度,从而创建该地图点。
三角化是指通过在两处观察同一个3D点的夹角,从而确定该点的距离。
ORB-SLAM的三角化
目标:根据相机的两帧间的位姿及跟踪到的特征点,通过三角化得到这些特征点对应的地图点。
输入:相机位姿、相机内参、两个2D点
输出:地图点
假设地图点为
P
w
=
[
x
,
y
,
z
,
1
]
T
P_w=[x,y,z,1]^T
Pw=[x,y,z,1]T,参考帧的相机位姿为
T
r
w
=
[
R
r
w
∣
t
t
w
]
T_{rw}=[R_{rw}|t_{tw}]
Trw=[Rrw∣ttw],表示从世界坐标系变化到参考帧坐标系,同理,当前帧的相机位姿为
T
c
w
=
[
R
c
w
∣
t
c
w
]
T_{cw}=[R_{cw}|t_{cw}]
Tcw=[Rcw∣tcw]。点
P
w
P_w
Pw在参考帧的归一化平面坐标为
p
r
=
[
x
r
/
z
r
,
y
r
/
z
r
,
1
]
T
p_r=[x_r/z_r,y_r/z_r,1]^T
pr=[xr/zr,yr/zr,1]T,深度为
z
r
z_r
zr,在当前帧归一化平面的坐标为
p
c
=
[
x
c
/
z
c
,
y
c
/
z
c
,
1
]
T
p_c=[x_c/z_c,y_c/z_c,1]^T
pc=[xc/zc,yc/zc,1]T,深度为
z
c
z_c
zc。根据位置变换关系有:
z
r
p
r
=
T
r
w
P
w
z_{r}p_{r} = T_{rw}P_{w}
zrpr=TrwPw
z c p c = T c w P w z_{c}p_{c} = T_{cw}P_{w} zcpc=TcwPw
对上述两式分别叉乘对应的归一化平面坐标,得:
p r × z r p r = p r × T r w P w = 0 p_{r}\times z_{r}p_{r} = p_{r}\times T_{rw}P_{w} = 0 pr×zrpr=pr×TrwPw=0
p c × z c p c = p c × T c w P w = 0 p_{c}\times z_{c}p_{c} = p_{c}\times T_{cw}P_{w} = 0 pc×zcpc=pc×TcwPw=0
整理得:
[
p
r
×
T
r
w
p
c
×
T
c
w
]
P
w
=
A
x
=
0
\begin{bmatrix} p_{r}\times T_{rw} \\p_{c}\times T_{cw} \end{bmatrix} P_{w} = Ax = 0
[pr×Trwpc×Tcw]Pw=Ax=0
由此,通过构建一个齐次方程来求解
P
w
P_w
Pw,其中
A
∈
R
6
×
4
A \in R^{6\times 4}
A∈R6×4,是一个超定方程,因此目标函数为:
J
(
x
)
=
min
∥
A
x
∥
J(x) = \min\|Ax\|
J(x)=min∥Ax∥
可以通过SVD分解,得到
A
=
U
D
V
T
A = UDV^{T}
A=UDVT,
V
4
×
4
V_{4\times4}
V4×4的最后一列的列向量即为所求的
P
w
P_w
Pw,由于齐次坐标的最后一位是1,因此求得的
P
w
P_w
Pw要统一除以最后一位。
输入:两个相机的位姿 [ R c , t c ] [R_c, t_c] [Rc,tc]和 [ R r , t r ] [R_r, t_r] [Rr,tr],特征点的2D像素坐标 p r , p c p_r, p_c pr,pc,相机内参 K K K。
输出:特征点的3D坐标 P w P_w Pw。
算法步骤:
p_rn, p_cn = pixel2Normalized(p_r, p_c) #将像素坐标转换为归一化坐标
A = construtMatrixA(p_rn, p_cn, T_rw, T_cw) #构建矩阵Ax=0
{
A = [ p r n × T r w p c n × T c w ] A=\begin{bmatrix} p_{rn}\times T_{rw} \\ p_{cn}\times T_{cw} \end{bmatrix} A=[prn×Trwpcn×Tcw]
}
P_w = computeBySVD(A) #对A做SVD分解,P_w取最小奇异值的奇异向量,注意需要齐次化
A*算法
A*算法通过代价函数 f ( n ) = g ( n ) + h ( n ) f(n)=g(n)+h(n) f(n)=g(n)+h(n)来计算每个节点n的优先级。其中:
- f(n)为节点n的综合优先级,当旋转下一个要遍历的节点时,总是选取综合优先级最高(f(n)值最小)的节点。
- g(n)为节点n距离起点的代价。
- h(n)为节点n距离终点的预计代价,也即启发函数。
A*算法还使用两个集合来分别表示待遍历的节点和已遍历过的节点,称为open_set和close_set。
算法描述:
* 初始化open_set和close_set;
* 将起点加入open_set中,并设置优先级为0(优先级最高);
* 如果open_set不为空,则从open_set中选取优先级最高的节点n:
* 如果节点n为终点,则:
* 从终点开始逐步追踪parent节点,一直达到起点;
* 返回找到的结果路径,算法结束;
* 如果节点n不是终点,则:
* 将节点n从open_set中删除,并加入close_set中;
* 遍历节点n所有的邻近节点:
* 如果邻近节点m在close_set中,则:
* 跳过,选取下一个邻近节点
* 如果邻近节点m也不在open_set中,则:
* 设置节点m的parent为节点n
* 计算节点m的优先级
* 将节点m加入open_set中
扩展卡尔曼滤波
*prediction
x' = F * x + u
P' = F * P * F^T + Q
*measurement update
y = z - H * x'
S = H * P' * H^T + R
K = P' * H^T * S^(-1)
x = x' + K * y
P = (I - K * H) * P'
分为预测和更新两步:
- 预测:根据状态转移矩阵F预测状态量x’,并进行状态协方差传递,预测不确定度P’。
- 观测:计算观测残差y,并根据测量矩阵H和协方差计算增益K。
- 更新:根据预测x’和观测残差y更新当前状态x,和不确定度P。
激光SLAM
占据栅格地图构建
原理:对于地图里的一个栅格s,使用
O
d
d
(
s
)
=
p
(
s
=
1
)
p
(
s
=
0
)
Odd(s)=\frac{p(s=1)}{p(s=0)}
Odd(s)=p(s=0)p(s=1)表示其状态,s=1表示占据,s=0表示空闲。其后验估计为:
O
d
d
(
s
∣
z
)
=
p
(
s
=
1
∣
z
)
p
(
s
=
0
∣
z
)
=
p
(
z
∣
s
=
1
)
p
(
s
=
1
)
p
(
z
∣
s
=
0
)
p
(
s
=
0
)
=
p
(
z
∣
s
=
1
)
p
(
z
∣
s
=
0
)
∗
O
d
d
(
s
)
Odd(s|z)=\frac{p(s=1|z)}{p(s=0|z)}=\frac{p(z|s=1)p(s=1)}{p(z|s=0)p(s=0)}=\frac{p(z|s=1)}{p(z|s=0)}*Odd(s)
Odd(s∣z)=p(s=0∣z)p(s=1∣z)=p(z∣s=0)p(s=0)p(z∣s=1)p(s=1)=p(z∣s=0)p(z∣s=1)∗Odd(s)
两边取对数为:
log
O
d
d
(
s
∣
z
)
=
log
p
(
z
∣
s
=
1
)
p
(
z
∣
s
=
0
)
+
log
O
d
d
(
s
)
\log Odd(s|z)=\log\frac{p(z|s=1)}{p(z|s=0)} + \log Odd(s)
logOdd(s∣z)=logp(z∣s=0)p(z∣s=1)+logOdd(s)
令激光雷达对栅格的观测结果为:
l
o
f
r
e
e
=
log
p
(
z
=
0
∣
s
=
1
)
p
(
z
=
0
∣
s
=
0
)
l
o
o
c
c
u
=
log
p
(
z
=
1
∣
s
=
1
)
p
(
z
=
1
∣
s
=
0
)
lofree=\log\frac{p(z=0|s=1)}{p(z=0|s=0)} \\ looccu=\log\frac{p(z=1|s=1)}{p(z=1|s=0)}
lofree=logp(z=0∣s=0)p(z=0∣s=1)looccu=logp(z=1∣s=0)p(z=1∣s=1)
则更新规则根据观测变为:
S
+
=
S
−
+
l
o
f
r
e
e
/
l
o
o
c
c
u
S^+=S^-+lofree/looccu
S+=S−+lofree/looccu
线性代数
非线性优化
GN法:
1、构建误差函数 r i j r_{ij} rij
2、计算误差的雅可比 J i j J_{ij} Jij
3、构建增量方程 ( J T J ) δ x = − J T r (J^TJ)\delta x=-J^Tr (JTJ)δx=−JTr,并求解 δ x \delta x δx
4、更新 x k + 1 = x k ⊕ δ x x_{k+1}=x_k\oplus \delta x xk+1=xk⊕δx,并返回1进行迭代
LM法:
输入:最大迭代次数N、顶点 x x x、残差边 r r r
输出:优化后的变量 x ∗ x^* x∗
构建H矩阵makeHessian(); 计算残差 r i j r_{ij} rij和雅可比 J i j J_{ij} Jij,构建H矩阵
LM初始化computeLambdaInit(); 确定收敛阈值和 λ 0 = τ ∗ max ∣ ( J T J ) i , i ∣ \lambda_0=\tau *\max|(J^TJ)_{i,i}| λ0=τ∗max∣(JTJ)i,i∣
while (!stop && iter < N) { //迭代求解
while (!oneStepSuccess) { // 不断尝试lambda,直至成功下降一步
addLambda2Hessian(); // H矩阵加上lambda
solveLinear(); //求解Hx=b
removeLambdaHessian(); // H矩阵减去lambda
判断是否退出:delta_x <= 1e-6
updataStates(); // 更新 x k + 1 = x k ⊕ δ x x_{k+1}=x_k\oplus \delta x xk+1=xk⊕δx
oneStepSucess = isGoodStep(); // 判断当前步是否可行,及lambda的更新
if (oneStepSuccess)
makeHessian(); //在新线性化点构建Hessian
else
rollbackStates(); //误差没下降,回滚
}
}
其中isGoodStep()的流程如下:
近似下降: L ( 0 ) − L ( δ x ) = 1 2 δ x T ( λ δ x + b ) L(0)-L(\delta_x)=\frac{1}{2}\delta x^T(\lambda \delta_x+b) L(0)−L(δx)=21δxT(λδx+b)
实际下降: F ( x ) − F ( x + δ x ) F(x)-F(x+\delta x) F(x)−F(x+δx)
计算 ρ = 实 际 下 降 近 似 下 降 \rho=\frac{实际下降}{近似下降} ρ=近似下降实际下降,并根据 ρ \rho ρ更新 λ \lambda λ:
if rho > 0: //误差下降,则减小阻尼增大步长 lambda := lambda * max(1/3, 1 - pow((2*rho-1), 3)); ni = 2; return true; else //误差没下降,则增大阻尼减小步长 lambda := lambda * ni; ni := ni * 2; return false;
Dogleg法:
begin
k : = 0 ; x : = x 0 ; Δ : = Δ 0 ; b : = J ( x ) T f ( x ) k:=0;\quad x:=x_0; \quad \Delta:=\Delta_0; \quad b:=J(x)^Tf(x) k:=0;x:=x0;Δ:=Δ0;b:=J(x)Tf(x)
f o u n d : = ( ∣ ∣ f ( x ) ∣ ∣ ∞ ≤ ϵ 3 ) o r ( ∣ ∣ b ∣ ∣ ∞ ≤ ϵ 1 ) found:=(||f(x)||_{\infin}\le \epsilon_3) \bold{or} (||b||_{\infin}\le \epsilon_1) found:=(∣∣f(x)∣∣∞≤ϵ3)or(∣∣b∣∣∞≤ϵ1)
while (not found) and (k < k_max):
k : = k + 1 k := k+1 k:=k+1; 最速下降步长 α = ∣ ∣ b ∣ ∣ 2 ∣ ∣ J ( x ) b ∣ ∣ 2 \alpha=\frac{||b||^2}{||J(x)b||^2} α=∣∣J(x)b∣∣2∣∣b∣∣2
最速下降 h s d : = − α b ; h_{sd}:=-\alpha b; hsd:=−αb;
GN下降 h g n : = − H − 1 b ; h_{gn}:=-H^{-1}b; hgn:=−H−1b;
计算dogleg更新量:
{
if (h_gn <= Delta)
h_dl = h_gn
else if (h_sd >= Delta)
h_dl = (Delta / abs(h_sd)) * h_sd
else
h_dl = alpha * h_sd + beta * (h_gn - alpha * h_sd)
}
更新状态 x n e w : = x + h d l x_{new}:=x+h_{dl} xnew:=x+hdl
计算增益比 ρ = 实 际 下 降 近 似 下 降 \rho=\frac{实际下降}{近似下降} ρ=近似下降实际下降
更新信赖域半径:
{
if (rho > 0)
x = x_new; g = Jt * f;
if (rho > 0.75)
Delta = max(Delta, 3 * norm(h_dl));
else if (rho < 0.25)
Delta = Delta / 2;
}
为什么求解Ax=0时取得是SVD分解的最小奇异值的奇异向量?
对于齐次方程Ax=0,可以把问题转化为最小化
∣
∣
A
x
∣
∣
2
||Ax||^2
∣∣Ax∣∣2的非线性优化问题,为避免x=0的特解情况,人为增加约束
∣
∣
x
∣
∣
2
=
1
||x||^2=1
∣∣x∣∣2=1,因此问题变为:
min
x
(
∣
∣
A
x
∣
∣
2
)
,
∣
∣
x
∣
∣
2
=
1
\min_x(||Ax||^2), \quad ||x||^2=1
xmin(∣∣Ax∣∣2),∣∣x∣∣2=1
对A做SVD分解得
∣
∣
A
x
∣
∣
=
∣
∣
U
D
V
T
x
∣
∣
=
∣
∣
D
V
T
x
∣
∣
||Ax||=||UDV^Tx||=||DV^Tx||
∣∣Ax∣∣=∣∣UDVTx∣∣=∣∣DVTx∣∣,令
y
=
V
T
x
y=V^Tx
y=VTx,则问题变为
min
y
(
∣
∣
D
y
∣
∣
)
,
∣
∣
y
∣
∣
=
1
\min_y(||Dy||), \quad||y||=1
ymin(∣∣Dy∣∣),∣∣y∣∣=1
由于D为对角阵,且对角元的元素按递减排序,因此最优解为
y
=
(
0
,
0
,
.
.
.
,
1
)
T
y=(0,0,...,1)^T
y=(0,0,...,1)T,又
x
=
V
y
x=Vy
x=Vy,因此最优解就是V的最小奇异值对应的列向量。
算法框架
ORB-SLAM
ORBSLAM初始化特征匹配策略?
由于初始化阶段,只有2D-2D匹配关系,因此需要尽可能保证匹配正确。在ORB-SLAM中,作者使用“旋转直方图”筛选正确匹配,函数接口为ORBmatcher::SearchForInitialization
。输入参考帧F1和当前帧F2的特征点,其步骤为:
-
构建旋转直方图,将360°划分为30个区间。
-
遍历F1中的所有特征点:
-
对于特征点i1,在半径为100的窗口内搜索F2中所有候选匹配特征点vIndices2;
-
遍历vIndices2,计算i1的最优和次优匹配;
-
对匹配结果进行阈值检查:
- 最优匹配距离 < 次优匹配距离 * 阈值mfNNratio;
- 删除重复匹配;
-
选择次优匹配关系,双向建立;
-
计算匹配特征点的角度差,并加入到相应的直方图区间内;
rot = F1.mvKeysUn[i1].angle-F2.mvKeysUn[bestIdx2].angle;
-
-
筛除旋转直方图中“非主流”部分:选出旋转直方图中最大的前3个bin,将不在这3个bin内的匹配对剔除掉。
VINS-Mono
什么是边缘化?First Estimate Jacobian?一致性?可观性?
边缘化其实简单说就是将滑窗中丢弃的图像帧的信息保留下来传递给剩余变量的方式。
First Estimate Jacobian是为了解决新测量信息和旧的先验信息构建新的系统时,对某一优化变量求雅克比的线性化点不同导致信息矩阵的零空间发生变化,不可观的变量变成可观变量的问题。做法就是保证变量的线性化点不变,“具体来说,位姿采用propagated值而非updated值,landmark使用第一次估计值”。主要是作用在滤波和滑窗法中,具体可以参考First Estimate Jacobian。
一致性指可观性的一致性,也即线性化点的一致不变。同一个变量在同一次优化中,在不同约束项里进行不同地方的线性化,从而导致出现不一致性。例如,相机位姿在边缘化后留在了滑窗中,但是其观测的某个点在k时刻被边缘化掉。这样它的信息矩阵就会出现在先验中,而当我们在k’时刻对该相机位姿进行优化使用的应该是k’的状态计算雅克比。
为了解决这个问题,只能改变用于计算雅克比的状态估计。在当前状态和边缘化状态相连时,使用边缘化时刻k的状态来计算后面的雅克比。这样保证了信息矩阵只有一个状态。注意,旧的状态只用来计算雅克比。
可观性的定义和现代控制理论中能观性定义是一致的,即通过测量获得状态变量的信息,即该变量是能观的。
FEJ
【参考】
msckf中的可观性分析和FEJ
滑窗法的可观性分析和FEJ
滑动窗口的不一致性:
考虑k时刻滑窗中边缘化后保留的相机位姿
c
i
∗
c_{i*}
ci∗,假设特征
p
L
j
∗
p_{L_j*}
pLj∗被
c
i
∗
c_{i*}
ci∗观测到且已在k时被边缘化掉。那么在计算k时的先验信息
A
p
(
k
)
A_p(k)
Ap(k)时使用的是k时刻的状态估计。在k‘时刻做非线性优化时,相机位姿
c
i
∗
c_{i*}
ci∗依然在滑窗中,然而此时观测的雅可比计算使用的是k’时刻的状态估计。该情况会使得估计器错误地认为方向是可观的(信息矩阵的秩增加),从而导致不一致性。
FEJ:
为了避免不一致的问题,对于和边缘化状态(
p
L
j
∗
p_{L_j*}
pLj∗)通过观测相连的滑窗保留状态(
c
i
∗
c_{i*}
ci∗),使用边缘化时刻k的状态估计去计算k’时刻的雅可比。
PS:我们只在计算雅可比时使用“老”的估计,实际的状态量在非线性优化中依然会迭代更新。
VINS-Mono中的可观性分析:
在VINS-Mono中,根据贺博的博客,VINS-Mono中似乎只在计算先验雅可比时使用了FEJ(即固定线性化点),该雅可比通过对边缘化得到的
A
p
A_p
Ap做SVD分解计算得到:
H
p
=
U
S
U
T
=
J
T
J
J
p
=
S
U
T
r
p
=
S
−
1
U
T
b
p
H_{p}=USU^T=J^TJ \\ J_p = \sqrt S U^T \\ r_{p}= \sqrt S ^{-1}U^Tb_p
Hp=USUT=JTJJp=SUTrp=S−1UTbp
代码如下:
linearized_jacobians = S_sqrt.asDiagonal() * saes2.eigenvectors().transpose();
linearized_residuals = S_inv_sqrt.asDiagonal() * saes2.eigenvectors().transpose() * b;
至于imu和视觉观测残差的雅可比,VINS-Mono并没有使用FEJ,其线性化点在迭代优化时是不断更新的。
vins中预积分项如何根据bias进行修正?
α b k + 1 b k = α ^ b k + 1 b k + J δ b a k δ α b k + 1 b k δ b a k + J δ b w k δ α b k + 1 b k δ b w k β b k + 1 b k = β ^ b k + 1 b k + J δ b a k δ β b k + 1 b k δ b a k + J δ b w k δ β b k + 1 b k δ b w k γ b k + 1 b k = γ ^ b k + 1 b k ⊗ [ 1 1 2 J δ b w k δ θ b k + 1 b k δ b w k ] \alpha_{b_{k+1}}^{b_k}=\hat\alpha_{b_{k+1}}^{b_k} + J_{\delta b_{a_k}}^{\delta \alpha_{b_{k+1}}^{b_k}}\delta b_{a_k} + J_{\delta b_{w_k}}^{\delta \alpha_{b_{k+1}}^{b_k}}\delta b_{w_k} \\\beta_{b_{k+1}}^{b_k}=\hat\beta_{b_{k+1}}^{b_k} + J_{\delta b_{a_k}}^{\delta \beta_{b_{k+1}}^{b_k}}\delta b_{a_k} + J_{\delta b_{w_k}}^{\delta \beta_{b_{k+1}}^{b_k}}\delta b_{w_k} \\\gamma_{b_{k+1}}^{b_k} = \hat\gamma_{b_{k+1}}^{b_k} \otimes \begin{bmatrix} 1 \\ \frac{1}{2} J_{\delta b_{w_k}}^{\delta \theta_{b_{k+1}}^{b_k}} \delta b_{w_k} \end{bmatrix} αbk+1bk=α^bk+1bk+Jδbakδαbk+1bkδbak+Jδbwkδαbk+1bkδbwkβbk+1bk=β^bk+1bk+Jδbakδβbk+1bkδbak+Jδbwkδβbk+1bkδbwkγbk+1bk=γ^bk+1bk⊗⎣⎡121Jδbwkδθbk+1bkδbwk⎦⎤
当对加速度计偏置和陀螺仪的偏置发生(微小)改变时,就可以根据等式(2)对预积分项进行线性修正,避免了重复积分。