【转载】OpenCV-Python系列之对极几何实践(六十五)

OpenCV中的对极几何

在上个教程中我们已经简述了对极几何的一些理论知识,本次我们来使用OpenCV中的一些函数来进行实战,为了得到基础矩阵我们应该在两幅图像中找到尽量多的匹配点。我们可以使用 SIFT 描述符,FLANN 匹配器和比值检测。

我们使用示例图片:
在这里插入图片描述

在这里插入图片描述

先看代码:

view plaincopy to clipboardprint?
import numpy as np  
import cv2 as cv  
from matplotlib import pyplot as plt  
   
   
img1 = cv.imread('myleft.jpg', 0)  # queryimage # left image  
img2 = cv.imread('myright.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)  

现在得到了一个匹配点列表,我们就可以使用它来计算基础矩阵了。

retval, mask=cv.findFundamentalMat(points1, points2, method, ransacReprojThreshold, confidence, mask)

· points1:从第一张图片开始的N个点的数组。点坐标应该是浮点数(单精度或双精度)。

· points2:与点1大小和格式相同的第二图像点的数组。

· method:计算基本矩阵的方法。

· cv2.FM_7POINT for a 7-point algorithm. N=7

· cv2.FM_8POINT for an 8-point algorithm. N≥8

· cv2.FM_RANSAC (默认) for the RANSAC algorithm. N≥8

· cv2.FM_LMEDS for the LMedS algorithm. N≥8

· ransacReprojThreshold:仅用于RANSAC方法的参数,默认3。它是一个点到极线的最大距离(以像素为单位),超过这个点就被认为是一个离群点,不用于计算最终的基本矩阵。根据点定位、图像分辨率和图像噪声的准确性,可以将其设置为1-3左右。

· confidence:仅用于RANSAC和LMedS方法的参数,默认0.99。它指定了一个理想的置信水平(概率),即估计矩阵是正确的。

· mask:输出

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]

下一步我们要找到极线。我们会得到一个包含很多线的数组。所以我们要 定义一个新的函数将这些线绘制到图像中。

view plaincopy to clipboardprint?
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  

现在我们两幅图像中计算并绘制极线。

lines = cv.computeCorrespondEpilines(points, whichImage, F, lines)

· points:输入点。类型为CV_32FC2N×1或1×N矩阵。

· whichImage:包含点的图像(1或2)的索引。

· F:基本矩阵,可使用findFundamentalMat或stereoRectify 进行估计。

· lines:对应于另一幅图像中点的极线的输出向量(a,b,c)表示直线ax+by+c=0。

view plaincopy to clipboardprint?
# 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()  

最终整个程序:

view plaincopy to clipboardprint?
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('myleft.jpg', 0)  # queryimage # left image  
img2 = cv.imread('myright.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()  

结果:
在这里插入图片描述

我们可以在左侧图像中看到所有Epilines都在右侧图像的一点处收敛。那个汇合点就是极点。
查看文章汇总页https://blog.csdn.net/weixin_44237705/article/details/107864965
更多openvino技术信息可以入群交流~
申请备注:CSDN
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值