一,什么是对极几何?
立体成像的基本几何就是对极几何。如下图:
C和C'为两个相机(也有可能是一个相机在不同时刻的位置)的主点,X为空间中一个物点,两个相对的白色平面是像面(严格按照光路应该是在C,C'点的后方,与X点相反方向,CV中默认采用这种往前画的方式节省空间)。x和x'是X点在像面上的对应点,e1 e2为像面和C,C'的交点。CC'为基线,也被称作相机的移动方向。在对极几何中,e1和e2被称作极点,COC'平面为极面,l,l'为极线.
二,基础矩阵
1,基础矩阵用来做什么?
基础矩阵可以用来描述空间中的点在两个像平面中的坐标对应关系,可以表征两个相机的相对位置及相机内参数。。即如果已知基础矩阵F,以及一个3D点在一个像面上的像素坐标p,则可以求得在另一个像面上的像素坐标p'。
2,基础矩阵推导
以C为原点,光轴方向为z轴,另外两个方向为x, y轴可以得到一个坐标系,在这个坐标系下,可以对X ,p(即图中的x),p'(即图中的x')得到三维坐标,同理,对C'也可以得到一个三维坐标,这两个坐标之间的转换矩阵为[R T],即通过旋转R和平移T可以将C坐标系下的点p(x1, y1, z1), 转换成C'坐标系下的p'(x2, y2, z2)。则可知,p=Rp'+T
根据三线共面可知: 即
其中,p, p'分别为P点的像点在两个坐标系下分别得到的坐标(非二维像素坐标)。Rp'为极面上一矢量,T为极面上一矢量,则两矢量一叉乘为极面的法向量, 这个法向量与极面上一矢量p一定是垂直的,所以上式一定成立。(这里采用转置是因为p会表示为列向量的形式,此处需要为行向量)
采用叉乘矩阵的方法:
所以:
E为本质矩阵(本质矩阵描述了空间中的点在两个坐标系中的坐标对应关系)
又有:
上式中, K'K'-1为相机的校准矩阵, 描述相机的内参数 p,p'为相机的像素坐标
代入中可得
所以,F为基础矩阵
3,基础矩阵的性质
F有什么样的性质呢?简单说来, 3x3的矩阵,理论上9个自由度,但是需要符合以下两个约束
a)如果F为基础矩阵,那么kF也为基础矩阵
b)秩为2
所以减去两个自由度,F有7个自由度
4,怎么求基础矩阵?
一般采用八点算法对F进行求解,得知F后就可以对任意像面1上点找像面2上对应点了。
三,基于基础阵的实现
(1)计算图像对的特征匹配,并估计基础矩阵。使用外极限作为第二个输入,通过在极限上对每个特征点寻找最佳匹配来找到更多的匹配。
(2)制作一个包含三幅或更多图像的数据集(本文中用三张不同视角拍摄的图像)。挑选一对图像,计算三维点和照相机矩阵。匹配特征到剩下的图像中以获得对应。然后利用这些对应的三维点使用后方交汇法,计算其他图像的照相机矩阵。绘制这些三维点和照相机的位置。
from PIL import Image
from numpy import *
from pylab import *
import numpy as np
from imp import reload
import camera
import homography
import sfm
import sift
camera = reload(camera)
homography = reload(homography)
sfm = reload(sfm)
sift = reload(sift)
im1 = array(Image.open('D:/img/1.jpg'))
sift.process_image('D:/img/1.jpg', 'im1.sift')
im2 = array(Image.open('D:/img/2.jpg'))
sift.process_image('D:/img/2.jpg', 'im2.sift')
l1, d1 = sift.read_features_from_file('im1.sift')
l2, d2 = sift.read_features_from_file('im2.sift')
# In[5]:
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):
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']
model = sfm.RansacModel()
F, inliers = F_from_ransac(x1n, x2n, model, maxiter=5000, match_threshold=1e-3)
print (F)
P1 = array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]])
P2 = sfm.compute_P_from_fundamental(F)
print (P2)
print (F)
X = sfm.triangulate(x1n[:, inliers], x2n[:, inliers], P1, P2)
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]
im3 = array(Image.open('D:/img/3.jpg'))
sift.process_image('D:/img/3.jpg', 'im3.sift')
l3, d3 = sift.read_features_from_file('im3.sift')
matches13 = sift.match_twosided(d1p, d3)
ndx_13 = matches13.nonzero()[0]
x1_13 = homography.make_homog(x1p[:, ndx_13])
ndx2_13 = [int(matches13[i]) for i in ndx_13]
x3_13 = homography.make_homog(l3[ndx2_13, :2].T)
figure(figsize=(16, 16))
imj = sift.appendimages(im1, im3)
imj = vstack((imj, imj))
imshow(imj)
cols1 = im1.shape[1]
rows1 = im1.shape[0]
for i in range(len(x1_13[0])):
if (0<= x1_13[0][i]<cols1) and (0<= x3_13[0][i]<cols1) and (0<=x1_13[1][i]<rows1) and (0<=x3_13[1][i]<rows1):
plot([x1_13[0][i], x3_13[0][i]+cols1],[x1_13[1][i], x3_13[1][i]],'c')
axis('off')
show()
P3 = sfm.compute_P(x3_13, X[:, ndx_13])
print (P3)
print(P1)
print (P2)
print (P3)
室内场景:
SIFT特征匹配的对数:67 经过RANSAC优化后的对数32
得到的基础矩阵:
[[ 1.10787002e-06 -1.45971695e-05 2.67369589e-03]
[ 1.76206687e-05 6.63552270e-07 -9.48007658e-03]
[-5.23106854e-03 7.92605311e-03 1.00000000e+00]]
图1
图2
图3
图1 为SIFT特征匹配结果的图片,图2的第二张是从左边拍摄的图像,图3是从右边拍摄的图像
得到的基础矩阵为:
[[ 2.33123074e-06 -2.45579217e-05 4.17333890e-03]
[ 2.40517243e-05 4.93419016e-06 -1.05135189e-02]
[-7.15370993e-03 8.78841456e-03 1.00000000e+00]]
室外场景:
上图分别为SIFT特征匹配后的结果,对应的匹配点以及经过RANSAC优化后的结果,匹配对数为99,使用对数为34
基础矩阵为:
[[ 4.49590331e-07 -1.35466609e-05 5.00402429e-03]
[ 1.26761166e-05 2.99171656e-07 -1.17463640e-02]
[-5.78323529e-03 1.07657062e-02 1.00000000e+00]]
三张图像的结果:
对应的基础矩阵为:
[[ 3.17642070e-08 -1.65684714e-05 5.45557999e-03]
[ 1.61239775e-05 5.89842379e-07 -1.30096467e-02]
[-5.99829140e-03 1.13880245e-02 1.00000000e+00]]
x,x',X的位置分别为:
[[1 0 0 0]
[0 1 0 0]
[0 0 1 0]]
[[ 2.02202155e+00 -4.82177398e+00 3.70619230e+02 7.00525589e+02]
[-3.82177335e+00 9.11360651e+00 -7.00531587e+02 3.70630618e+02]
[-1.16184109e-02 -5.56284008e-03 1.02007530e+01 1.00000000e+00]]
[[-2.45990524e-03 3.51760030e-03 4.39539285e-01 -4.84808537e-01]
[ 2.55275822e-03 -6.70441888e-03 7.05224806e-01 -2.72558248e-01]
[ 8.31063232e-06 3.04387329e-06 -6.89270145e-03 -7.64176057e-04]]