+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2019-07(2)

2019-08(106)

2019-09(110)

2019-10(14)

2019-11(8)

外极几何与基础矩阵

发布于2020-04-23 09:34     阅读(232)     评论(0)     点赞(12)     收藏(4)


0

1

2

3

4

5

6

7

8

9

一、实验原理

1.1 外极几何

外极几何是研究两幅图像之间存在的几何。它和场景结构无关,只依赖于摄像机的内外参数。研究这种几何可以用在图像匹配、三维重建方面。
在这里插入图片描述如上图所示,C1 C_1C2 C_2是两个摄像头的光心,X为空间中的一点,x1 x_1x2 x_2是点X在两个摄像头成的像中的投影。

基本概念:
基线: 连接两个摄像机光点C1 C_1C2 C_2的直线。
外极点: 基线与图像平面的交点e1 e_1e2 e_2
外极平面: 过基线的平面C1 C_1C2 C_2X
外极线: 对极平面与图像平面的交线l1 l_1l2 l_2
外极线约束: 假设x1 x_1x2 x_2分别是空间中同一点在两个不同视平面上的像点,则x1 x_1一定在l1 l_1上,x2 x_2一定在l2 l_2
如果已经知道相机的参数,那么在重建过程中遇到的问题就是两幅图像之间的关系,外极线约束的主要作用就是限制对应特征点的搜索范围,将对应特征点的搜索限制在极线上。

1.2 基础矩阵

在计算机视觉中,基础矩阵(Fundamental matrix)F是一个3×3的矩阵,表达了立体像对的像点之间的对应关系。在对极几何中,对于立体像对中的一对同名点,它们的齐次化图像坐标分别为x与 x’,Fx F_x表示一条必定经过x’的直线(极线)。这意味着立体像对的所有同名点对都满足:xT x'^TFx F_x=0

F矩阵中蕴含了立体像对的两幅图像在拍摄时相互之间的空间几何关系(外参数)以及相机检校参数(内参数),包括旋转、位移、像主点坐标和焦距。因为F矩阵的秩为2,并且可以自由缩放(尺度化),所以只需7对同名点即可估算出F的值。

基础矩阵性质
(1)基础矩阵是秩为2、自由度为7的齐次矩阵。
(2)若x与 x’是两幅图上的对应点,那么xT x'^TFx F_x=0
(3)l’是对应于x的对极线,l′=Fx F_x
(4)若e是第二个摄像机光心在第一幅图像上的极点,那么Fe=0 。

1.1 八点算法

八点法是通过对应点来计算基础矩阵的算法。

基本矩阵是由该方程定义的:xT x'^TFx F_x=0

其中x↔x′是两幅图像的任意一对匹配点。由于每一组点的匹配提供了计算F系数的一个线性方程,当给定至少7个点(3×3的齐次矩阵减去一个尺度,以及一个秩为2的约束),方程就可以计算出未知的F。我们记点的坐标为x=(x,y,1)T x=(x,y,1)^Tx=(x,y,1)T x′=(x′,y′,1)^T

又因为F为:
在这里插入图片描述
所以可得到方程:
)
即相应方程式为:
在这里插入图片描述给定nn组点的集合,我们有如下方程:
在这里插入图片描述如果存在确定(非零)解,则系数矩阵A的秩最多是8。由于F是齐次矩阵,所以如果矩阵A的秩为8,则在差一个尺度因子的情况下解是唯一的。可以直接用线性算法解得。

如果由于点坐标存在噪声则矩阵A的秩可能大于8(也就是等于9,由于A是n×9的矩阵)。这时候就需要求最小二乘解,这里就可以用SVD来求解,f的解就是系数矩阵A最小奇异值对应的奇异向量,也就是A奇异值分解后A=UDVT A=UDV^T中矩阵V的最后一列矢量,这是在解矢量f在约束 ||f|| 下取 ||Af|| 最小的解。以上算法是解基本矩阵的基本方法,称为8点算法。

上述求解后的F不一定能满足秩为2的约束,因此还要在F的基础上加以约束。通过SVD分解可以解决,令F=UΣVT F=UΣV^T,则
在这里插入图片描述
因为要秩为2,所以取最后一个元素设置为0,则
在这里插入图片描述
最终的解为:F=UΣVT F'=UΣ'V^T

二、代码

# coding: utf-8
from PIL import Image
from numpy import *
from pylab import *
import numpy as np
from PCV.geometry import homography, camera, sfm
from PCV.localdescriptors import sift

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

# 提取特征
im1 = array(Image.open('E:/code/image/five/5.jpg'))
sift.process_image('E:/code/image/five/5.jpg', 'im1.sift')

im2 = array(Image.open('E:/code/image/five/6.jpg'))
sift.process_image('E:/code/image/five/6.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()

import sfm111
## 计算 F
F = sfm111.compute_fundamental(x1n,x2n)
print(F)


def F_from_ransac(x1, x2, model, maxiter=5000, match_threshold=1e-6):
    """
    使用RANSAC从点对应中稳健估计基本矩阵F.
  (来自http://www.scipy.org/Cookbook/RANSAC的ransac.py)。
    input: x1, x2 (3*n arrays) points in hom. coordinates. """

    from PCV.tools import ransac
    data = np.vstack((x1, x2))
    d = 10  # 20 is the original
    # 计算F并返回inlier索引
    F, ransac_data = ransac.ransac(data.T, model,
                                   7, maxiter, match_threshold, d, return_all=True)
    return F, ransac_data['inliers']


# 通过RANSAC找到F.
model = sfm.RansacModel()
F, inliers = F_from_ransac(x1n, x2n, model, maxiter=5000, match_threshold=1e-3)

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 is'
print F

X = sfm.triangulate(x1n[:, inliers], x2n[:, inliers], P1, P2)

# 绘制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')
#
#for i in range(5):
#    plot([x1p[0,i],x2p[0][i],x1p[1,i],x2p[1][i]],'o')
#axis('off')
#show()

def compute_epipole(F):
 """ 从基础矩阵 F 中计算右极点(可以使用 F.T 获得左极点)"""
 # 返回 F 的零空间(Fx=0)
 U,S,V = linalg.svd(F)
 e = V[-1]
 return e/e[2]



def plot_epipolar_line(im,F,x,epipole=None,show_epipole=True):
 """ 在图像中,绘制外极点和外极线 F×x=0。F 是基础矩阵,x 是另一幅图像中的点 """
 m,n = im.shape[:2]
 line = dot(F,x)
 # 外极线参数和值
 t = linspace(0,n,100)
 lt = array([(line[2]+line[0]*tt)/(-line[1]) for tt in t])
 # 仅仅处理位于图像内部的点和线
 ndx = (lt>=0) & (lt<m)
 plot(t[ndx],lt[ndx],linewidth=2)
 if show_epipole:
     if epipole is None:
         epipole = compute_epipole(F)
     plot(epipole[0]/epipole[2],epipole[1]/epipole[2],'r*')

e = compute_epipole(F)
for i in range(len(x1p[0])):
    plot_epipolar_line(im1,F,x2[:,i],e,False)
axis('off')
#figure()
#imshow(im2)
# 分别绘制每个点,这样会绘制出和线同样的颜色
for i in range(len(x1p[0])):
    plot(x2[0,i],x2[1,i],'o')
axis('off')



d1p = d1n[inliers]
d2p = d2n[inliers]



三、实验内容及分析

3.1求解图像之间的基础矩阵

3.1.1 实验结果
  1. 左右变换
    在这里插入图片描述在这里插入图片描述

  2. 平移变换
    在这里插入图片描述在这里插入图片描述

  3. 前后变换
    在这里插入图片描述在这里插入图片描述

3.2画出极点和极线

3.2.1 实验结果
  1. 左右变换

在这里插入图片描述

  1. 平移变换

在这里插入图片描述

  1. 前后变换
    在这里插入图片描述
3.2.2 分析
  1. 在左右不同角度拍摄的图中,极线最终会汇集到一点上,交汇点在图片外,在平行拍摄的两张图上,极线整体上体现的也是平行关系,从前后位拍摄的图中可以看出,极线从四面八方汇集到中心,交汇点在图片中。
  2. 以上实验结果显示,极点大部分都会落在极线上,在最后一组上会存在误差。

四、问题总结

  1. 在处理左右不同角度的图片时,运行出现错误,这是由于图像sift特征匹配的匹配点数过少,可能是因为图像水平落差比较大,经过多次实验发现,拍摄图片时角度选择不能过大
    在这里插入图片描述

原文链接:https://blog.csdn.net/weixin_45255372/article/details/105668085

0

1

2

3

4

5



所属网站分类: 技术文章 > 博客

作者:9384vfnv

链接: https://www.pythonheidong.com/blog/article/339311/3fed0e07f85224fff222/

来源: python黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

12 0
收藏该文
已收藏

评论内容:(最多支持255个字符)