计算机视觉——求解图像之间的基础矩阵
文章目录
1. 外极几何
1.1 基础矩阵
- 概述:
1)两幅图像之间的约束关系使用代数的方式表示出来即为基本矩阵。
2)基础矩阵F满足:
3)基础矩阵可以用于简化匹配和去除错配特征。
-
原理
基本矩阵体现了两视图几何(对极几何,epipolar geometry)的内在射影几何(projective geometry)关系,基本矩阵只依赖于摄像机的内参KK和外参R,tR,t。
上图是一个两视图的几何描述,其中OO、O′O′是两个相机的光心,两点连线OO′OO′称为基线,基线与图像平面的交点ee、e′e′称为对极点,其中ll、l′l′分别是图像点x′x′、xx对应的对极线。上图的左侧相机的图像平面上的一个点xx,反向投影得到射线OXOX。由于点的深度未知,图像平面上的点xx可能是射线上某一深度的3D点XX。而射线OXOX在第二个相机的图像平面上的投影为l′l′。也就是说,给定一对图像,第一幅图像上的每个点xx,在另外一幅图像上存在一条直线l′l′与之对应。换言之,第二幅图像上与点xx对应的点x′x′必定在线l′l′上。
我们可以看到这里存在一个从一副图像上的点到另外一幅图像与之对应的对极线的映射x→l′x→l′。而基本矩阵就表示了这种从点到直线的射影映射关系。
设X在C,C′ 坐标系中的相对坐标分别为p,p′则有 :
其中,
根据三线共面,有:
转换为:
本质矩阵描述的是:空间中的点在两 个坐标系中的坐标对应关系。
根据前述,K和K′分别为两个相机的内参矩阵,有:
基础矩阵描述的是: 空间中的点在两个相平面中的坐标对应关系。
1.2 基础矩阵估算方法
1.2.1 八点估算法
基本矩阵是由该方程定义的:
其中x↔x′是两幅图像的任意一对匹配点。由于每一组点的匹配提供了计算F系数的一个线性方程,当给定至少7个点(3×3的齐次矩阵减去一个尺度,以及一个秩为2的约束),方程就可以计算出未知的F。我们记点的坐标为x=(x,y,1)T,x′=(x′,y′,1)T
又因为F为
F =
所以可得到方程:
即相应方程式为
给定n组点的集合,我们有如下方程:
如果存在确定(非零)解,则系数矩阵A的秩最多是8。由于F是齐次矩阵,所以如果矩阵A的秩为8,则在差一个尺度因子的情况下解是唯一的。可以直接用线性算法解得。
最终的解:
2. 实验部分
2.1 代码
# -*- coding: utf-8 -*-
from PIL import Image
from numpy import *
from pylab import *
import numpy as np
from PCV.geometry import camera
from PCV.geometry import homography
from PCV.geometry import sfm
from PCV.localdescriptors import sift
from importlib import reload
camera = reload(camera)
homography = reload(homography)
sfm = reload(sfm)
sift = reload(sift)
# Read features
im1 = array(Image.open('E:/python/picture/y1/c1.jpg'))
sift.process_image('E:/python/picture/y1/c1.jpg', 'im1.sift')
im2 = array(Image.open('E:/python/picture/y1/c2.jpg'))
sift.process_image('E:/python/picture/y1/c2.jpg', 'im2.sift')
l1, d1 = sift.read_features_from_file('im1.sift')
l2, d2 = sift.read_features_from_file('im2.sift')
matches = sift.match_twosided(d1, d2)
ndx = matches.nonzero()[0]
x1 = homography.make_homog(l1[ndx, :2].T)
ndx2 = [int(matches[i]) for i in ndx]
x2 = homography.make_homog(l2[ndx2, :2].T)
d1n = d1[ndx]
d2n = d2[ndx2]
x1n = x1.copy()
x2n = x2.copy()
figure(figsize=(16,16))
sift.plot_matches(im1, im2, l1, l2, matches, True)
show()
def F_from_ransac(x1, x2, model, maxiter=5000, match_threshold=1e-6):
from PCV.tools import ransac
data = np.vstack((x1, x2))
d = 10 # 20 is the original
# compute F and return with inlier index
F, ransac_data = ransac.ransac(data.T, model,
8, maxiter, match_threshold, d, return_all=True)
return F, ransac_data['inliers']
# find F through RANSA43C
model = sfm.RansacModel()
F, inliers = F_from_ransac(x1n, x2n, model, maxiter=5000, match_threshold=1e-2)
print ('F',F)
P1 = array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]])
P2 = sfm.compute_P_from_fundamental(F)#Computes the second camera matrix
# triangulate inliers and remove points not in front of both cameras
X = sfm.triangulate(x1n[:, inliers], x2n[:, inliers], P1, P2)
# plot the projection of X
cam1 = camera.Camera(P1)
cam2 = camera.Camera(P2)
x1p = cam1.project(X)
x2p = cam2.project(X)
figure(figsize=(16, 16))
imj = sift.appendimages(im1, im2)
imj = vstack((imj, imj))
imshow(imj)
cols1 = im1.shape[1]
rows1 = im1.shape[0]
for i in range(len(x1p[0])):
if (0<= x1p[0][i]<cols1) and (0<= x2p[0][i]<cols1) and (0<=x1p[1][i]<rows1) and (0<=x2p[1][i]<rows1):
plot([x1p[0][i], x2p[0][i]+cols1],[x1p[1][i], x2p[1][i]],'c')
axis('off')
show()
d1p = d1n[inliers]
d2p = d2n[inliers]
print ('P1',P1)
print ('P2',P2)
2.2 实验结果
F, ransac_data = ransac.ransac(data.T, model,
7, maxiter, match_threshold, d, return_all=True)
通过改变这一行就能实现7,8,10点法的运算。
2.2.1 左右
原图:
八点法:
七点法:
十点法:
基础矩阵为:
小结
如果是像下图这种的话:
代码会出现如下错误:
ValueError: did not meet fit acceptance criteria
在试了三组图片都出现了这个结果,应该是图片问题,不可以直接将图片镜像。
2.2.2 前后
原图:
八点法运行结果:
计算得出的基础矩阵,即通过直线拟合得到摄像机的外参矩阵P:
七点法:
十点法:
小结
如果想找到符合点可以改变RABSAC算法的阈值大小,如下句代码:
F, inliers = F_from_ransac(x1n, x2n, model, maxiter=5000, match_threshold=1e-2)
阈值的值变大可以让特征点尽量缩小计算到拟合直线的范围区域内,但是阈值范围的变大,回导致后面计算精度降低。
基础矩阵用RABSAC算法计算原始的点是否满足的到的基础矩阵F,在设置的域之内则满足,反之。
2.2.3 平移
原图:
八点法:
七点法:
十点法:
基础矩阵为:
2.3 实验总结与问题
- 如果两种图片角度差异过大,那么可匹配点就很少,导致阈值内的值很少,匹配出来的结果就不能进行下一步。
- 左右的匹配效果要比其它两个的效果差很多,而且有些错误的点并没有剔除,甚至又将良好的点剔除,由此可见,这个算法还值得改进。但是在其他特征点能匹配很多及符合阈值的点多的情况表现还是良好。
- 遇到的问题:ValueError: did not meet fit acceptance criteria
室内的场景图片都出现了这个问题但是室外都不会,原因可能是水平落差太大。
解决方法:重新拍摄一组图片即可。
或者将图片由右往左的顺序运行。 - 由于较远的目标适配的点对数量多,所以越容易增加错配而无法提出的点对。