多视几何

多视图几何是主要研究用几何的方法,通过若干幅多视图几何二维图像,来恢复三维物体。间言之就是研究三维重构。
1.对极几何基础概念
核点(epipole):基线(baseline)与成像平面的交点。同时极点也可以理解为相邻影像成像中心在本影像上的像,因为基线是两个相邻影像成像中心的连线。
核平面(epipolar plane):含有基线的平面,是一簇平面。可以看做是由基线与空间中任意一点构成的平面。
核线(epipolar line):核平面与成像平面的交线。可以看做是成像平面上的任意一点(非核点)与核点所定义的直线。
多视几何
2. 基础矩阵 F
基础矩阵可以看做是将点投影(转换)为直线,将左影像上的一个点投影到右影像上形成一条核线。
基础矩阵表示的是图像中的像点p1到另一幅图像对极线l2的映射,有如下公式:
多视几何
而和像点P1P1匹配的另一个像点p2必定在对极线l2上,所以就有:
多视几何

这样仅通过匹配的点对,就可以计算出两视图的基础矩阵F。
基础矩阵FF是一个3×3的矩阵,有9个未知元素,由于尺度是任意的,所以只需要8个方程。因为算法中需要8个对应点来计算基础矩阵F,所以该算法叫做八点法。

3.8点法估算基础矩阵F
由于基础矩阵 F 定义为
多视几何
任给两幅图像中的匹配点 x 与 x’,令
多视几何
多视几何
有相应方程:
多视几何
最后得到AF=0.

4.实验过程

#!/usr/bin/env python
# coding: utf-8

# In[1]:
from PIL import Image
from numpy import *
from pylab import *
import numpy as np
from imp import reload



# In[2]:
import importlib
from PCV.geometry import camera
from PCV.geometry import homography
from PCV.geometry import sfm
from PCV.localdescriptors import sift

camera = importlib.reload(camera)
homography = importlib.reload(homography)
sfm = importlib.reload(sfm)
sift =importlib.reload(sift)


# In[3]:


# Read features
im1 = array(Image.open('image5/1.jpg'))
sift.process_image('image5/1.jpg', 'im1.sift')
l1, d1 = sift.read_features_from_file('im1.sift')

im2 = array(Image.open('image5/2.jpg'))
sift.process_image('image5/2.jpg', 'im2.sift')
l2, d2 = sift.read_features_from_file('im2.sift')


# In[9]:


matches = sift.match_twosided(d1, d2)


# In[10]:


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)

x1n = x1.copy()
x2n = x2.copy()


# In[11]:


print (len(ndx))


# In[12]:


figure(figsize=(16,16))
sift.plot_matches(im1, im2, l1, l2, matches, True)
show()


# In[13]:


# Chapter 5 Exercise 1
# Don't use K1, and K2

#def F_from_ransac(x1, x2, model, maxiter=5000, match_threshold=1e-6):
def F_from_ransac(x1, x2, model, maxiter=5000, match_threshold=1e-6):
    """ Robust estimation of a fundamental matrix F from point
    correspondences using RANSAC (ransac.py from
    http://www.scipy.org/Cookbook/RANSAC).

    input: x1, x2 (3*n arrays) points in hom. coordinates. """

    from PCV.tools import ransac
    data = np.vstack((x1, x2))
    d = 20 # 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']


# In[15]:


# find E through RANSAC
model = sfm.RansacModel()
F, inliers = F_from_ransac(x1n, x2n, model, maxiter=5000, match_threshold=1e-3)


# In[16]:


print (len(x1n[0]))
print (len(inliers))


# In[17]:


P1 = array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0]])
P2 = sfm.compute_P_from_fundamental(F)


# In[18]:


# triangulate inliers and remove points not in front of both cameras
X = sfm.triangulate(x1n[:, inliers], x2n[:, inliers], P1, P2)


# In[19]:


# plot the projection of X
cam1 = camera.Camera(P1)
cam2 = camera.Camera(P2)
x1p = cam1.project(X)
x2p = cam2.project(X)


# In[20]:


figure()
imshow(im1)
gray()
plot(x1p[0], x1p[1], 'o')
#plot(x1[0], x1[1], 'r.')
axis('off')

figure()
imshow(im2)
gray()
plot(x2p[0], x2p[1], 'o')
#plot(x2[0], x2[1], 'r.')
axis('off')
show()


# In[21]:


figure(figsize=(16, 16))
im3 = sift.appendimages(im1, im2)
im3 = vstack((im3, im3))

imshow(im3)

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()


# In[22]:


print (F)


# In[23]:


# Chapter 5 Exercise 2

x1e = []
x2e = []
ers = []
for i,m in enumerate(matches):
    if m>0: #plot([locs1[i][0],locs2[m][0]+cols1],[locs1[i][1],locs2[m][1]],'c')
        
        p1 = array([l1[i][0], l1[i][1], 1])
        p2 = array([l2[m][0], l2[m][1], 1])

       
        
        # Use Sampson distance as error
        Fx1 = dot(F, p1)
        Fx2 = dot(F, p2)
        denom = Fx1[0]**2 + Fx1[1]**2 + Fx2[0]**2 + Fx2[1]**2
        e = (dot(p1.T, dot(F, p2)))**2 / denom
        x1e.append([p1[0], p1[1]])
        x2e.append([p2[0], p2[1]])
        ers.append(e)
x1e = array(x1e)
x2e = array(x2e)
ers = array(ers)


# In[24]:


indices = np.argsort(ers)
x1s = x1e[indices]
x2s = x2e[indices]
ers = ers[indices]
x1s = x1s[:20]
x2s = x2s[:20]


# In[25]:


figure(figsize=(16, 16))
im3 = sift.appendimages(im1, im2)
im3 = vstack((im3, im3))

imshow(im3)

cols1 = im1.shape[1]
rows1 = im1.shape[0]
for i in range(len(x1s)):
    if (0<= x1s[i][0]<cols1) and (0<= x2s[i][0]<cols1) and (0<=x1s[i][1]<rows1) and (0<=x2s[i][1]<rows1):
        plot([x1s[i][0], x2s[i][0]+cols1],[x1s[i][1], x2s[i][1]],'c')
axis('off')
show()


# In[ ]:

室外结果如下:
多视几何
注:拍摄照片时要注意图片的景深,否则运行中很容易出现问题。
室外结果如下图
多视几何
多视几何
多视几何
多视几何
得到的基础矩阵为
多视几何

参考博客:https://www.cnblogs.com/wangguchangqing/p/8214032.html
https://www.cnblogs.com/JingeTU/p/6390915.html