对极几何与基础矩阵

一,什么是对极几何?

   立体成像的基本几何就是对极几何。如下图:

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-T)^{^{T}}(T\times p)=0  即 (R^{T}p')^{T}(T\times p)=0(R^{T}p^{'})^{T}(T\times p)=0

其中,p, p'分别为P点的像点在两个坐标系下分别得到的坐标(非二维像素坐标)。Rp'为极面上一矢量,T为极面上一矢量,则两矢量一叉乘为极面的法向量, 这个法向量与极面上一矢量p一定是垂直的,所以上式一定成立。(这里采用转置是因为p会表示为列向量的形式,此处需要为行向量)

采用叉乘矩阵的方法:

        T\times p=Sp

所以:

                                         (R^{T})(R^{T}p')^{T}(Sp)=0                 (p'^{T}{\color{Red} R)(S}p)=0             p'^{T}{\color{Red} E}p=0

E为本质矩阵(本质矩阵描述了空间中的点在两个坐标系中的坐标对应关系)

 又有:

                                        p=K^{-}x        p'=K'^{-1}x'

  上式中, K'K'-1为相机的校准矩阵, 描述相机的内参数 p,p'为相机的像素坐标

代入p'^{T}E}p=0中可得x'^{T}{\color{Red} K'^{-T}EK^{-1}}x=0

所以x'^{T}Fx=0,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]]

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值