文章目录
- 一、简介
- 二、原理
- 三、实验代码
- 四、实验结果
- 五、小结
-
-
- 引用
-
一、简介
在计算机视觉中,基本矩阵(Fundamental matrix)F是一个3×3的矩阵表达了三维图像对对的图像点之间的对应关系。在对极几何中,对于三维图像对中的一对同名点,其齐次化图像坐标分别为p和p p说明一条必须经过,说明一条必须经过p直线(极线)。这意味着所有同名点对立体像对都满意: F矩阵包含空间几何关系(外部参数)和相机检查参数(内部参数),包括旋转、位移、主坐标和焦距。由于F矩阵的秩序为2,并且可以自由缩放(标准化),因此F值只能通过7对同名点来估计。 基础矩阵的概念由Q. T. Luong在他有影响力的博士论文中提出。 FaugerasF矩阵的定义是在1992年发表的作品中给出的。尽管Longuet-Higgins本质矩阵也符合类似的关系类型,但本质矩阵不包含相机检查参数。基本矩阵和基本矩阵之间的关系可以用以下方式表达: 其中K和K分别是两个相机的内参数矩阵。
二、原理
推导基础矩阵的方法有很多种,下面介绍一种。 在双相机的拍摄场景中建立一个空间直角坐标系,称为世界坐标系(图1中的蓝色坐标系)。物体点是场景中物体表面的点,如世界坐标系中点P的坐标 相机的光心是相机镜头组的光学中心。以光心为原点,主光轴为Z轴建立空间直角坐标系,称为相机坐标系(图1中的绿色和红色坐标系)。相机坐标系中平面的方程是z=f,像点是像平面上物点的投影,是透视投影。 用一句话来概括相机的拍摄模型,即物点、像点、光心三点一线,称为针孔相机模型。在这个模型中,从世界坐标系到左右相机坐标系的转换是刚性转换,即只包括旋转和平移,所以我们分别使用增广矩阵[R|t]和[R’|t其中,R和R’是3*旋转矩阵3,t和t为平移向量。对于P的齐次化坐标,左右相机坐标系下物点P的坐标分别为 以相机为例,如图2所示,C为相机光心,Z轴为主轴。相机坐标系下的物点坐标与照片左下角的像点坐标p有以下关系: 类型是相机坐标系下的坐标,主点为图像。 设两相机内参数矩阵同为: 物点与像点的关系如下: 并令代入上式,得到: 由于物点、像点和光心三点一线,物点、一对同名点和两个光心必须在同一平面上。我们称这个平面为平面。平面和像平面的交叉线称为极线l。显然,左片上的每个像点p对应于右片上的极线l’,且p’一定在l上面。两个相机光心的连接和右图像平面的交点称为极点,使用e’表示。 极线在右图像平面内 l方程可以表示为Ax By C=0.平面直线方程的一般公式可视为: 因此,我们可以使用三维向量 (A,B,C)来表示极线l’,并且 l方程可以简单地理由e坐标向量与 p得到坐标向量做向量积,即 ,其中: 令[e’]x表示向量积矩阵形式,然后替换同名点之间的变换关系,得到极线的方程为: 因为p’在 l所以显然有: 即得到:
三、实验代码
(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('F:/python/pic/7/1.jpg')) sift.process_image('F:/python/pic/7/1.jpg', 'F:/python/pic/7/im1.sift') im2 = array(Image.open('F:/python/pic/7/2.jpg')) sift.process_image('F:/python/pic/7/2.jpg', 'F:/python/pic/7/im2.sift') l1, d1 = sift.read_features_from_file('F:/python/pic/7/im1.sift') l2, d2 = sift.read_features_from_file('F:/python/pic/7/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]<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] print (P1) print (P2)
(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, p2 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('F:/python/pic/7/1.jpg', 0) # queryimage # left image
img2 = cv.imread('F:/python/pic/7/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()
四、实验结果
实验图集: (1)求解基础矩阵 (2)画出极点和极线
五、小结
实验中出现了ValueError: did not meet fit acceptance criteria,经过反复试验,得出是图片匹配点过少,算法无法继续运行,通用的加大阈值也无法解决该问题,只有重新拍摄照片,才得到能够运行出结果的图片。
引用
百度百科:基础矩阵