概述
PnP问题的DLT解法
欢迎关注知乎@司南牧
已知:上一帧相机坐标系下的点的三维齐次坐标
Q
Q
Q,和,那
n
n
n个点在当前帧中的二维齐次坐标
q
q
q, 和相机内参矩阵
K
K
K。
待求解变量 :当前帧相对上一帧的位姿变换矩阵 [ R ∣ t ] [R|t] [R∣t] 。
约束方程:
K
[
R
∣
t
]
Q
=
λ
q
K[R|t]Q = lambda q
K[R∣t]Q=λq
我们记
[ R ∣ t ] = [ a 11 a 12 a 13 a 14 a 21 a 22 a 23 a 24 a 31 a 32 a 33 a 34 ] [R|t]= begin{bmatrix} a_{11}&a_{12}&a_{13}&a_{14}\ a_{21}&a_{22}&a_{23}&a_{24}\ a_{31}&a_{32}&a_{33}&a_{34} end{bmatrix} [R∣t]=⎣⎡a11a21a31a12a22a32a13a23a33a14a24a34⎦⎤
DLT的思路就是把 a i j a_{ij} aij代入式 ( 1 ) (1) (1),然后求出 a i j a_{ij} aij就可以求出 [ R ∣ t ] [R|t] [R∣t]。可以看到]现在我们有12个未知数一对点只能提供两个方程,所以需要6对点。
目前已知相机内参矩阵
K
=
[
f
x
0
c
x
0
f
y
c
y
0
0
1
]
K= begin{bmatrix} f_x&0&c_x\ 0&f_y&c_y\ 0&0&1 end{bmatrix}
K=⎣⎡fx000fy0cxcy1⎦⎤
还已知在上一帧相机坐标系下的三维齐次坐标
Q
=
[
x
y
z
1
]
Q=begin{bmatrix}x\y\z\ 1end{bmatrix}
Q=⎣⎢⎢⎡xyz1⎦⎥⎥⎤
还已知对应点在当前帧的二维坐标
q
=
[
u
v
1
]
q=begin{bmatrix}u\v\1end{bmatrix}
q=⎣⎡uv1⎦⎤
将式子
(
2
)
,
(
3
)
,
(
4
)
,
(
5
)
(2),(3),(4),(5)
(2),(3),(4),(5)代入到式
(
1
)
(1)
(1)中得到:
K
[
R
∣
t
]
Q
=
[
f
x
0
c
x
0
f
y
c
y
0
0
1
]
[
a
11
a
12
a
13
a
14
a
21
a
22
a
23
a
24
a
31
a
32
a
33
a
34
]
[
x
y
z
1
]
=
λ
[
u
v
1
]
K[R|t]Q = begin{bmatrix} f_x&0&c_x\ 0&f_y&c_y\ 0&0&1 end{bmatrix} begin{bmatrix} a_{11}&a_{12}&a_{13}&a_{14}\ a_{21}&a_{22}&a_{23}&a_{24}\ a_{31}&a_{32}&a_{33}&a_{34} end{bmatrix} begin{bmatrix} x\ y\ z\ 1 end{bmatrix} =lambda begin{bmatrix}u\ v\1end{bmatrix}
K[R∣t]Q=⎣⎡fx000fy0cxcy1⎦⎤⎣⎡a11a21a31a12a22a32a13a23a33a14a24a34⎦⎤⎣⎢⎢⎡xyz1⎦⎥⎥⎤=λ⎣⎡uv1⎦⎤
进行矩阵乘法得到:
[
f
x
a
11
+
c
x
a
31
f
x
a
12
+
c
x
a
32
f
x
a
13
+
c
x
a
33
f
x
a
14
+
c
x
a
34
f
y
a
21
+
c
y
a
31
f
y
a
22
+
c
y
a
32
f
y
a
23
+
c
y
a
33
f
y
a
24
+
c
y
a
34
a
31
a
32
a
33
a
34
]
[
x
y
z
1
]
=
[
x
(
f
x
a
11
+
c
x
a
31
)
+
y
(
f
x
a
12
+
c
x
a
32
)
+
z
(
f
x
a
13
+
c
x
a
33
)
+
(
f
x
a
14
+
c
x
a
34
)
x
(
f
y
a
21
+
c
y
a
31
)
+
y
(
f
y
a
22
+
c
y
a
32
)
+
z
(
f
y
a
23
+
c
y
a
33
)
+
(
f
y
a
24
+
c
y
a
34
)
x
a
31
+
y
a
32
+
z
a
33
+
a
34
]
=
λ
[
u
v
1
]
begin{bmatrix} f_xa_{11}+c_xa_{31}&f_xa_{12}+c_xa_{32}&f_xa_{13}+c_xa_{33}&f_xa_{14}+c_xa_{34}&\ f_ya_{21}+c_ya_{31}&f_ya_{22}+c_ya_{32}&f_ya_{23}+c_ya_{33}&f_ya_{24}+c_ya_{34}&\ a_{31}&a_{32}&a_{33}&a_{34} end{bmatrix} begin{bmatrix} x\ y\ z\ 1 end{bmatrix}\ =begin{bmatrix} x(f_xa_{11}+c_xa_{31})+y(f_xa_{12}+c_xa_{32})+z(f_xa_{13}+c_xa_{33})+(f_xa_{14}+c_xa_{34})\ x(f_ya_{21}+c_ya_{31})+y(f_ya_{22}+c_ya_{32})+z(f_ya_{23}+c_ya_{33})+(f_ya_{24}+c_ya_{34})\ xa_{31}+ya_{32}+za_{33}+a_{34} end{bmatrix} =lambda begin{bmatrix} u\ v\ 1 end{bmatrix}
⎣⎡fxa11+cxa31fya21+cya31a31fxa12+cxa32fya22+cya32a32fxa13+cxa33fya23+cya33a33fxa14+cxa34fya24+cya34a34⎦⎤⎣⎢⎢⎡xyz1⎦⎥⎥⎤=⎣⎡x(fxa11+cxa31)+y(fxa12+cxa32)+z(fxa13+cxa33)+(fxa14+cxa34)x(fya21+cya31)+y(fya22+cya32)+z(fya23+cya33)+(fya24+cya34)xa31+ya32+za33+a34⎦⎤=λ⎣⎡uv1⎦⎤
根据式子
(
7
)
(7)
(7)我们就得到了三个方程。我们将最后一行代入前两行消除
λ
lambda
λ可以得到:
[
x
(
f
x
a
11
+
c
x
a
31
)
+
y
(
f
x
a
12
+
c
x
a
32
)
+
z
(
f
x
a
13
+
c
x
a
33
)
+
(
f
x
a
14
+
c
x
a
34
)
x
(
f
y
a
21
+
c
y
a
31
)
+
y
(
f
y
a
22
+
c
y
a
32
)
+
z
(
f
y
a
23
+
c
y
a
33
)
+
(
f
y
a
24
+
c
y
a
34
)
]
=
[
u
x
a
31
+
u
y
a
32
+
u
z
a
33
+
u
a
34
v
x
a
31
+
v
y
a
32
+
v
z
a
33
+
v
a
34
]
begin{bmatrix} x(f_xa_{11}+c_xa_{31})+y(f_xa_{12}+c_xa_{32})+z(f_xa_{13}+c_xa_{33})+(f_xa_{14}+c_xa_{34})\ x(f_ya_{21}+c_ya_{31})+y(f_ya_{22}+c_ya_{32})+z(f_ya_{23}+c_ya_{33})+(f_ya_{24}+c_ya_{34})\ end{bmatrix}= begin{bmatrix} uxa_{31}+uya_{32}+uza_{33}+ua_{34}\ vxa_{31}+vya_{32}+vza_{33}+va_{34}\ end{bmatrix}
[x(fxa11+cxa31)+y(fxa12+cxa32)+z(fxa13+cxa33)+(fxa14+cxa34)x(fya21+cya31)+y(fya22+cya32)+z(fya23+cya33)+(fya24+cya34)]=[uxa31+uya32+uza33+ua34vxa31+vya32+vza33+va34]
整理得到:
x
f
x
a
11
+
y
f
x
a
12
+
z
f
x
a
13
+
f
x
a
14
+
x
(
c
x
−
u
)
a
31
+
y
(
c
x
−
u
)
a
32
+
z
(
c
x
−
u
)
a
33
+
(
c
x
−
u
)
a
34
=
0
x
f
y
a
21
+
y
f
y
a
22
+
z
f
y
a
23
+
f
y
a
24
+
x
(
c
y
−
v
)
a
31
+
y
(
c
y
−
v
)
a
32
+
z
(
c
y
−
v
)
a
33
+
(
c
y
−
v
)
a
34
=
0
begin{matrix} xf_xa_{11}+yf_xa_{12}+zf_xa_{13}+f_xa_{14}+x(c_x-u)a_{31}+y(c_x-u)a_{32}+z(c_x-u)a_{33}+(c_x-u)a_{34}=0\ xf_ya_{21}+yf_ya_{22}+zf_ya_{23}+f_ya_{24}+x(c_y-v)a_{31}+y(c_y-v)a_{32}+z(c_y-v)a_{33}+(c_y-v)a_{34}=0\ end{matrix}
xfxa11+yfxa12+zfxa13+fxa14+x(cx−u)a31+y(cx−u)a32+z(cx−u)a33+(cx−u)a34=0xfya21+yfya22+zfya23+fya24+x(cy−v)a31+y(cy−v)a32+z(cy−v)a33+(cy−v)a34=0
所以一对点对应两个方程。需要6对点才能解该方程。
式子
(
9
)
(9)
(9)写成矩阵的形式得到:
[
x
f
x
y
f
x
z
f
x
f
x
0
0
0
0
x
(
c
x
−
u
)
y
(
c
x
−
u
)
z
(
c
x
−
u
)
(
c
x
−
u
)
0
0
0
0
x
f
y
y
f
y
z
f
y
f
y
x
(
c
y
−
v
)
y
(
c
y
−
v
)
z
(
c
y
−
v
)
(
c
y
−
v
)
]
[
a
11
a
12
a
13
a
14
a
21
a
22
a
23
a
24
a
31
a
32
a
33
a
34
]
=
0
begin{bmatrix} xf_x&yf_x&zf_x&f_x&0&0&0&0&x(c_x-u)&y(c_x-u)&z(c_x-u)&(c_x-u)\ 0&0&0&0&xf_y&yf_y&zf_y&f_y&x(c_y-v)&y(c_y-v)&z(c_y-v)&(c_y-v)\ end{bmatrix} begin{bmatrix} a_{11}\a_{12}\a_{13}\a_{14}\ a_{21}\a_{22}\a_{23}\a_{24}\ a_{31}\a_{32}\a_{33}\a_{34} end{bmatrix} =bold 0
[xfx0yfx0zfx0fx00xfy0yfy0zfy0fyx(cx−u)x(cy−v)y(cx−u)y(cy−v)z(cx−u)z(cy−v)(cx−u)(cy−v)]⎣⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎢⎡a11a12a13a14a21a22a23a24a31a32a33a34⎦⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎥⎤=0
这就变成了求解
A
x
=
0
Ax=0
Ax=0问题。在线性代数里面有很多方式可以求解这个方程。
在SLAM中常用的方法是这样看 A x = 0 x Ax=0x Ax=0x,所以只用求矩阵 A A A特征值为0所对应的特征向量。用SVD对矩阵A分解得到 A = U D V A=UDV A=UDV,其中 V V V的最后一列就是 A x = 0 Ax=0 Ax=0的解。
根据此时求出的x可以算出
[
R
′
∣
t
′
]
[R'|t']
[R′∣t′],但是Ax=0它也可以看做是Acx=c0,所以此时求出的x它是真实的[R|t]乘上一个常数后得到的结果。我们需要计算出那个常数。而且求出的
R
′
R'
R′并不是一个正交矩阵。而我们的约束条件要求
R
′
R'
R′是一个正交矩阵。为了将它变成一个正交矩阵需要对求得的
R
′
R'
R′进行SVD分解让让其变成正交矩阵
U
′
D
′
V
′
=
s
v
d
(
R
′
)
U'D'V'=svd(R')
U′D′V′=svd(R′)
其中
U
′
,
V
′
U',V'
U′,V′都是正交矩阵,
D
′
D'
D′是对角矩阵,为了让
R
′
R'
R′变成正交矩阵我们需要让
D
′
D'
D′对角线元素全部相等。
E
′
=
d
i
a
(
t
r
(
D
′
)
3
)
R
′
=
U
′
E
′
V
′
E' = dia(frac{tr(D')}{3})\ R' = U'E'V'
E′=dia(3tr(D′))R′=U′E′V′
而且旋转矩阵R还有一个性质就是行列式为1.所以放缩因子就是
c
=
±
t
r
(
D
′
)
3
c=pm frac{tr(D')}{3}
c=±3tr(D′)。到底取正还是负有两种方式:
- 代入式子 ( 12 ) (12) (12)计算 R ′ R' R′的行列式看是否大于0
- λ lambda λ它是点在相机坐标系下的z轴方向的坐标值,而点肯定是在相机的前方,所以 λ > 0 lambda>0 λ>0。我们计算下面这个式子看是否大于0.(推荐使用这个,因为计算量相对较小)
c ( x a 31 + y a 32 + z a 33 + a 34 ) = λ > 0 c(xa_{31}+ya_{32}+za_{33}+a_{34})=lambda>0 c(xa31+ya32+za33+a34)=λ>0
编程实践
Python代码
import numpy as np
fx = 1
fy = 1
cx = 0
cy= 0
K = np.array([
[fx,0,cx],
[0,fy,cy],
[0,0,1]
])
Rt_groundtruth = np.array([
[1,0,0,3],
[0,1,0,3],
[0,0,1,3]
])
Qn = np.random.rand(4,6)
qn = K @ Rt_groundtruth @ Qn
#对qn 归一化
qn = qn/qn[-1]
zeros_nx4 = np.zeros((Qn.shape[1],4))
A_up = np.column_stack((fx*Qn.T,zeros_nx4, Qn.T * np.expand_dims((cx-qn[0]).T,1)))
A_below = np.column_stack((zeros_nx4,fy*Qn.T, Qn.T * np.expand_dims((cy-qn[1]).T,1)))
A = np.row_stack((A_up,A_below))
U,D,V=np.linalg.svd(A)
x = V[-1]
Rt = x.reshape((3,4))
R = Rt[:3,:3]
t = Rt[:3,-1]
U,D,V = np.linalg.svd(R)
c=1/(np.sum(D)/3)
# 验证c的正负是否正确
Q_verify = np.random.rand(4,1)
q_verify = K @ Rt_groundtruth @ Q_verify
if np.sum(c*(Q_verify.T*Rt[-1]))<0:
c = -c
D = np.diag(D*c)
R = U @ D @ V
print(R)
print(t*c)
最后
以上就是俏皮钢笔为你收集整理的如何理解PnP问题的DLT解法以及Python编程实践PnP问题的DLT解法编程实践的全部内容,希望文章能够帮你解决如何理解PnP问题的DLT解法以及Python编程实践PnP问题的DLT解法编程实践所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复