图像的极线校正

目录

1.基本概念

2.模型

3.基础矩阵

4.八点算法 + RANSAC

5.数据集

6.代码

7.结果截图与分析


1.基本概念

对极几何(Epipolar Geometry)是Structure from Motion问题中,在两个相机位置产生的两幅图像的之间存在的一种特殊几何关系,是sfm问题中2D-2D求解两帧间相机姿态的基本模型。

2.模型

图像的极线校正_第1张图片

其中C、C'为两个相机中心,X为空间中一点,X在C、C'对应像平面上的投影分别为x、x'。C、C'连线与像平面的交点e、e'称为极点(Epipoles),l'称为极线(Epipolar Lines),C、C'、X三点组成的平面称为极平面(Epipolar Plane)

3.基础矩阵

用于描述两个图像中像素点之间的坐标对应关系。即内外参数已知的情况下,如何知道当前点在另一个平面的那条直线上。

(1)设X在C,C'坐标系中的相对坐标分别为p,p',则有p=Rp'+T

其中      T=C'-C,即T为C'到C的位移。R为两个平面的旋转关系,即为旋转矩阵。

(2)x=Kp表示以C为空间坐标中心点,p到C的映射过程,  x'=K'p'表示以C'为空间坐标中心点,p'到C'的映射过程

故可推出p=K^{-1}x,p'=K'^{-1}x'

(3)根据三线共面:

(p-T)^{^{T}}(T*p)=0

注:p-T表示C'到p'的那条线,T*p表示同时垂直于T和p的那条线

(4)由以上可以得到(R^{T}p')^{T}(T*p)=0

(5)由于T*P=SpS=\begin{bmatrix} 0 &-T_{z}&T_{y}\\ T_{z}&0&-T_{x}\\ -T_{y}&T_{x}&0 \end{bmatrix},所以可以得到(R^{T}p')^{T}(Sp)=0 ,再从而得到(p'^{T}R)(Sp)=0,由此再得到p'^{T}Ep=0

注:E为本质矩阵,用于描述空间中同一个点在不同坐标系下的坐标之间的对应关系。

(6)K和K'分别为两个相机的内参矩,故有p=K^{-1}x,p'=K'^{-1}x'

(7)由以上可得(K'^{-1}x')^{T}E(K^{-1}x)=0,从而再得到x'^{T}K'^{-T}EK^{-1}x=0,最终得到x'^{T}Fx=0

注,其中的F即为基础矩阵,即描述空间中的点在两个像平面中的坐标对应关系

4.八点算法 + RANSAC

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

\begin{bmatrix} x & y & 1 \end{bmatrix}\begin{bmatrix} f11 & f12& f13\\ f21& f22 &f23 \\ f31&f32 & f33 \end{bmatrix}\begin{bmatrix} x'\\ y'\\ 1\end{bmatrix}=0

展开后有x'xf_{11}+x'yf_{12}+x'f_{13}+y'xf_{21}+y'yf_{22}+y'f_{23}+xf_{31}+yf_{32}+f_{33}=0

把矩阵F写成列向量的形式,则有:

\begin{bmatrix} x'x & x'y & x'& y'x & y'y& y'&x & y&1 \end{bmatrix}f=0

给定n组点的集合,我们有如下方程:

Af=\begin{bmatrix} x'_{1}x_{1} & x'_{1}y_{1} & x'_{1} &y'_{1}x_{1} & y'_{1}y_{1} & y'_{1} &x_{1} &y_{1} &1 \\ . & . & . &. & . & .& .&. & .\\ . & . & . &. & . & .& .&. & .\\ . & . & . &. & . & .& .&. & .\\ x'_{n}x_{n} & x'_{n}y_{n} & x'_{n} &y'_{n}x_{n} & y'_{n}y_{n} & y'_{n} &x_{n} &y_{n} &1 \end{bmatrix}f=0

如果存在确定(非零)解,则系数矩阵A的秩最多是8。由于F是齐次矩阵,所以如果矩阵A的秩为8,则在差一个尺度因子的情况下解是唯一的。可以直接用线性算法解得。

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

以上算法是求解基本矩阵的基本方法,称为八点算法。

由于匹配点众多,而取出的八对匹配点计算出的基础矩阵可能不太准确。所以需要用RANSAC算法进一步挑选出正确的点,从而计算出更准确的基础矩阵。
 

5.数据集

(1)左右拍摄,极点位于图像平面上

图像的极线校正_第2张图片

(2)像平面接近平行,极点位于无穷远

图像的极线校正_第3张图片

(3)图像拍摄位置位于前后

图像的极线校正_第4张图片

6.代码

(1)八点算法

from PIL import Image
from numpy import *
from pylab import *
import numpy as np

import PCV.geometry.camera as camera
import PCV.geometry.homography as homography
import PCV.geometry.sfm as sfm
import PCV.localdescriptors.sift as sift

im1 = array(Image.open('D:/JMU/computer_vision/SIFTcode/SFM/LR/1.jpg'))
sift.process_image('D:/JMU/computer_vision/SIFTcode/SFM/LR/1.jpg', 'im1.sift')

im2 = array(Image.open('D:/JMU/computer_vision/SIFTcode/SFM/LR/2.jpg'))
sift.process_image('D:/JMU/computer_vision/SIFTcode/SFM/LR/2.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-3):
    """ 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. """

    import PCV.tools.ransac as ransac
    data = np.vstack((x1, x2))
    d = 10 # 20 is the original
    F, ransac_data = ransac.ransac(data.T, model,
                                   7, 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)

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]

(2)极点代码

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt


def drawlines(img1, img2, lines, pts1, pts2):
    ''' img1 - image on which we draw the epilines for the points in img2
        lines - corresponding epilines '''
    r, c = img1.shape
    img1 = cv.cvtColor(img1, cv.COLOR_GRAY2BGR)
    img2 = cv.cvtColor(img2, cv.COLOR_GRAY2BGR)
    for r, pt1, pt2 in zip(lines, pts1, pts2):
        color = tuple(np.random.randint(0, 255, 3).tolist())
        x0, y0 = map(int, [0, -r[2] / r[1]])
        x1, y1 = map(int, [c, -(r[2] + r[0] * c) / r[1]])
        img1 = cv.line(img1, (x0, y0), (x1, y1), color, 1)
        img1 = cv.circle(img1, tuple(pt1), 5, color, -1)
        img2 = cv.circle(img2, tuple(pt2), 5, color, -1)
    return img1, img2


img1 = cv.imread('D:/JMU/computer_vision/SIFTcode/SFM/PA/1.jpg', 0)  # queryimage # left image
img2 = cv.imread('D:/JMU/computer_vision/SIFTcode/SFM/PA/2.jpg', 0)  # trainimage # right image
sift = cv.xfeatures2d.SIFT_create()
# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)
# FLANN parameters
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50)
flann = cv.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(des1, des2, k=2)
good = []
pts1 = []
pts2 = []
# ratio test as per Lowe's paper
for i, (m, n) in enumerate(matches):
    if m.distance < 0.8 * n.distance:
        good.append(m)
        pts2.append(kp2[m.trainIdx].pt)
        pts1.append(kp1[m.queryIdx].pt)

pts1 = np.int32(pts1)
pts2 = np.int32(pts2)
F, mask = cv.findFundamentalMat(pts1, pts2, cv.FM_LMEDS)
# We select only inlier points
pts1 = pts1[mask.ravel() == 1]
pts2 = pts2[mask.ravel() == 1]

# Find epilines corresponding to points in right image (second image) and
# drawing its lines on left image
lines1 = cv.computeCorrespondEpilines(pts2.reshape(-1, 1, 2), 2, F)
lines1 = lines1.reshape(-1, 3)
img5, img6 = drawlines(img1, img2, lines1, pts1, pts2)
# Find epilines corresponding to points in left image (first image) and
# drawing its lines on right image
lines2 = cv.computeCorrespondEpilines(pts1.reshape(-1, 1, 2), 1, F)
lines2 = lines2.reshape(-1, 3)
img3, img4 = drawlines(img2, img1, lines2, pts2, pts1)
plt.subplot(121), plt.imshow(img5)
plt.subplot(122), plt.imshow(img3)
plt.show()

7.结果截图与分析

(1)像平面接近平行,极点位于无穷远

图像的极线校正_第5张图片

(2)图像拍摄位置位于前后

图像的极线校正_第6张图片

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(图像的极线校正)