基础矩阵和照相机矩阵
目录
- 基础矩阵
- 三维点和照相机矩阵
- 代码和调试问题
基础矩阵
原理
通过对极几何一幅图像上的点可以确定另外一幅图像上的一条直线,可以用基本矩阵来表示;
设X在C,C’坐标系中的相对坐标分别p,p’,则有
p
=
R
p
′
+
T
p=Rp'+T
p=Rp′+T
x
=
K
p
x=Kp
x=Kp
x
′
=
K
′
p
′
x'=K'p'
x′=K′p′
p
=
K
−
1
x
p=K^{-1}x
p=K−1x
p
′
=
K
′
−
1
x
′
p'=K'^{-1}x'
p′=K′−1x′
根据三线共面:
(
p
−
T
)
T
(
T
×
p
)
=
0
(p-T)^{T}(T\times p)=0
(p−T)T(T×p)=0
(
(
R
T
p
′
)
T
(
T
×
p
)
=
0
((R^{T}p')^{T}(T\times p)=0
((RTp′)T(T×p)=0
T
×
p
=
S
p
T\times p=Sp
T×p=Sp
所以:
(
(
R
T
p
′
)
T
(
S
p
)
=
0
((R^{T}p')^{T}(Sp)=0
((RTp′)T(Sp)=0
其中
R
×
S
=
E
R\times S=E
R×S=E,也就是本质矩阵
p
′
T
E
p
=
0
p'^{T}Ep=0
p′TEp=0
本质矩阵描述了空间中的点在两个坐标系中的坐标对应的关系。
如上一篇文章讲到的相机标定问题,
K
K
K和
K
′
K'
K′分别为两个相机的内参矩阵,有:
p
=
K
−
1
x
p=K^{-1}x
p=K−1x
p
′
=
K
′
−
1
x
′
p'=K'^{-1}x'
p′=K′−1x′
sssso:
(
(
K
′
−
1
x
′
)
T
E
(
K
−
1
x
)
=
0
((K'^{-1}x')^{T}E(K^{-1}x)=0
((K′−1x′)TE(K−1x)=0
其中,
K
′
−
T
E
K
−
1
=
F
K'^{-T}EK^{-1}=F
K′−TEK−1=F,这个
F
F
F就是基础矩阵,它描述了空间中的点在两个像平面中的坐标对应的关系。
x
′
T
F
x
=
0
x'^{T}Fx=0
x′TFx=0
- 基础矩阵是对极几何的代数表达式
- 基础矩阵描述了图像中任意对应点 x < − > x ′ x<->x' x<−>x′之间的约束关系。
F
F
F为
3
×
3
3\times 3
3×3矩阵,秩为2,,对任意匹配点
x
x
x和
x
′
x'
x′满足:
x
T
F
X
′
=
0
x^{T}FX'=0
xTFX′=0
得到两张图的基础矩阵
拍摄的角度不同的建筑的sift匹配结果:
匹配的特征点只有133,需要通过调整阈值
得到基础矩阵如下:
三角剖分:恢复这些点的三维位置
移出一些不对的点:
可以看出来有些点明显偏移出去了
移除之后的效果:
不同拍摄距离的两张图片:
匹配点106,得到的基础矩阵:
进行三角剖分:
并去除不在两个摄像机前面的点:
角度差距较大的图片:
匹配点只有17个,还出现了错配,已经不适合再继续往下实验了。
结果分析:
可以看出来在室内,场景物体比较复杂的时候,可匹配的特征点更多一些,使用三角刨分得到的点就越多。而对于室外较为简单的建筑物,可匹配的点就相对少,匹配的正确率也会降低,使用三角刨分得到的点就相对来说很少,而且正确率也不高。
三维点和照相机矩阵
实验目的:
制作一个包含三幅或更多图像的数据集。挑选一对图像,计算三维点和照相机矩阵。匹配特征到剩下的图片中以获得对应。然后利用这些对应的三维点使用后方交汇法,计算其他图像的照相机矩阵。
这本质上是一个三角刨分的逆问题。
数据集:
实验结果1:
gym1.jpg和gym3.jpg的sift特征匹配:
处理过后的:
gym1.jpg和gym3.jpg的基础矩阵为:
gym3.jpg的照相机矩阵为:
P1 = array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]])
P2 = sfm.compute_P_from_fundamental(F)#P2是四个解的列表
交汇产生不同的点
X = sfm.triangulate(x1n[:, inliers], x2n[:, inliers], P1, P2)
把得到的参数作为新的参数计算gym2.jpg:
cam1 = camera.Camera(P1)
cam2 = camera.Camera(P2)
x1p = cam1.project(X)
x2p = cam2.project(X)
gym2.jpg和gym1.jpg匹配的效果:
计算gym2.jpg的照相机矩阵:
P3 = sfm.compute_P(x3_13, X[:, ndx_13])
所以三张照片的照相机矩阵是:
这时候我们看一下如果直接用gym1.jpg和gym2.jpg按第一部分实验的形式进行处理,结果应该如下:
发现其中大部分点的匹配都出现了错误,而第二部分实验结果中的点的匹配基本都是正确的。
实验结果2
数据集:
实验结果
三张图片的相机矩阵:
实验分析
多试图重建的效果还是取决于特征点的匹配情况,算法使用的是八点算法,如果所有景点都位于平面上,算法就会失效,所以第一组实验的效果并不是很好,因为整张图片的物体没有明显的景深差距。对于第二组图片的效果就相对好了很多。
代码及调试问题
上述网址的文件是.ipynb,可以使用下面这样的方式把其换成.py文件。
- 首先打开cmd
- 把cmd中的文件地址定位到你存文件的文加夹下:
3.再输入:jupyter nbconvert --to script *.ipynb
就可以把该文件夹下的所有.ipynb文件都转变成.py文件了。
jupyter是anaconda自带的。
调试过程还可能遇到以下问题:
only integers, slices (
:
), ellipsis (...
), numpy.newaxis (None
) and integer or boolea
需要对数据进行数据类型的强制转化。
可能出错的代码是以下这两个地方:
第一个地方:
plot([locs1[i,0], locs2[matchscores[i,0],0]+cols1], [locs1[i,1], locs2[matchscores[i,0],1]], 'c')
改成
ma = int(matchscores[i, 0])
x1 = int(locs1[i, 0])
y1 = int(locs2[ma, 0] + cols1)
x2 = int(locs1[i, 1])
y2 = int(locs2[ma, 1])
plot([x1, y1], [x2, y2], 'c')
第二地方:
p1 = array([l1[i][0], l1[i][1], 1])
p2 = array([l2[m][0], l2[m][1], 1])
改成:
if m>0:
x1 = int(l1[i][0])
y1 = int(l1[i][1])
a = int(m)
x2 = int(l2[a][0])
y2 = int(l2[a][1])
p1 = array([x1, y1, 1])
p2 = array([x2, y2, 1])