基于单应矩阵的图像拼接

首先我们看看这个方法的图像拼接的效果:

依次这是我们的左图和右图,和最后拼接的效果图:

基于单应矩阵的图像拼接

看了图片如果感兴趣的话,就可以接着往下看了。

目录

一、单应矩阵

二、ORB特征点提取和匹配

三、计算单应矩阵进行图像拼接

一、单应矩阵

Homography单应矩阵通常描述处于共同平面上的一些点在两种图像之间的变换关系,来以此描述了两个平面之间的映射关系。用公式表示的话就是:

x = H*x</p> <p>x为一张图像上的特征点位置,H为两种图像的单应矩阵,x是同一个特征点在另一张图像上的位置。同一平面被两个处于不同位置的相机观测,或者同一个相机观测到的两个相同的,但位置不同的物体,可以通过单应性进行运动估计相机的运动或物体的运动。

Homography指用同一个源得到的图像,中文译过来就是”单应”,当我们得到了一个相机移动拍的两个对应的图像的单应矩阵,我们就可以用它来将其中一张图像里的点全部转换到另一张图像的”视角”,”视角”我觉得可以理解为以相机为原点的3维空间坐标系,然后又转到图像平面坐标系上,对应的坐标拼接起来,就可以将两种图片比较好的拼接起来了,达到了一个广角相机的效果。

那么这个单应矩阵怎么求喃?我们一般用两张图像里的相同特征点来对它进行估计。简单来说就是获得x和x`后,求出我们的H。

二、ORB特征点提取和匹配

获取特征点的方法有很多,SIFT、ORB等等,这里我选择了ORB,因为它的时间消耗更少一些,ORB特征检测还具有尺度和旋转不变性,对于噪声及其透视变换也具有不变性,良好的性能使的利用ORB在进行特征描述时的应用场景十分广泛。(原理网上到处都有,我就不说了)

在opencv里也有对应的接口

import cv2 as cv
import numpy as np
left = cv.imread("./2020327121640383.jpg")
right = cv.imread("./2020327121732853.jpg")

orb = cv.ORB_create()

keypoint_left = orb.detect(left)
keypoint_right = orb.detect(right)
keypoint_left, describetion_left = orb.compute(left, keypoint_left)
keypoint_right, describetion_right = orb.compute(right,keypoint_right)

show_keypoint_left = cv.drawKeypoints(left, keypoints=keypoint_left, outImage=None)
show_keypoint_right = cv.drawKeypoints(right, keypoints=keypoint_right,outImage=None)

基于单应矩阵的图像拼接

得到特征点后,我们要找出左右相似的特征点作为特征点对,认为这是同一个物体的特征点,这时就需要对他们进行匹配。这里我选择了BF特征匹配算法,以hamming距离作为度量,BF简单来说就是拿图像中的一个特征点与另一张图像中的还没有匹配上的特征点做比较来找出最匹配的特征点。当然这样就会导致最后不相似的特征点也会匹配到一起,这时,我们就需要做一下过滤,根据实际情况设置匹配成功条件,我这儿设置的是特征点hamming距离不能低于最小距离的2倍,不能超过最大距离的1/3。效果如下所示,连线的就是匹配成功的特征点。

基于单应矩阵的图像拼接
matcher = cv.BFMatcher(cv.NORM_HAMMING)
match_result = matcher.match(describetion_left, describetion_right)

min_distance = match_result[0].distance
max_distance = match_result[0].distance
for i in match_result:
    if i.distance < min_distance:
        min_distance = i.distance
    if i.distance > max_distance:
        max_distance = i.distance

filter_result = []
for j in match_result:
    if j.distance >= max(min_distance*2, 10):
        if j.distance

三、计算单应矩阵进行图像拼接

得到特征点对后,就是计算单应矩阵了,注意因为单应矩阵是具有矩阵模||H|| = 1的约束,所以至少要有4对特征点才能计算出来,我们可以用opencv的cv.findHomography()来计算它,还可以得到一个mask是它验证得到你给的特征点对是否可用的掩码。计算得到单应矩阵H后,就可以对图像进行映射了,最后将两个图像拼接在一起就大功告成了。图像的拼接有重叠部分,我选择了用右图对左图进行覆盖,填充部分全为0。简单粗暴,这也是后面可以优化的点,对拼接部分的平滑处理以及填充部分的背景处理都是值得思考的地方。

if len(filter_result) > 3:
    keypoint_left = np.float32([keypoint_left[k.queryIdx].pt for k in filter_result]).reshape(-1,1,2)
    keypoint_right = np.float32([keypoint_right[k.trainIdx].pt for k in filter_result]).reshape(-1,1,2)
    # M,MASK = cv.findFundamentalMat(keypoint_left, keypoint_right, cv.FM_RANSAC, 5)
    matrix, mask = cv.findHomography(keypoint_right, keypoint_left,cv.RANSAC, 3.0)
    print("trans matrix: ",matrix)
    print("++++++++++++++++++++++++++++++")
    # print("len of mask: ", len(mask))
    print(mask)

    match_mask = mask.ravel().tolist()
    points = np.float32([[0,0],[0,h-1],[w-1,h-1],[w-1,0]]).reshape(-1,1,2)
    dest_point = cv.perspectiveTransform(points, matrix)
    print("dest points: ",dest_point)
    final_image = np.zeros([h,2*w,3],dtype = "uint8")
    warp_image = cv.warpPerspective(right, matrix, (2*w, h), flags=cv.INTER_LINEAR)
    # cv.imshow("warp image",warp_image)
    final_image[0:h,0:w] = left
    for i in range(h):
        for j in range(2*w):
            if (warp_image[i][j].any() != 0):
                final_image[i][j] = warp_image[i][j]

参考代码gitee地址:Image Stitchin: 基于单应(Homography)矩阵的图像拼接

Original: https://blog.csdn.net/qq_45819091/article/details/125492246
Author: 在努力的松鼠
Title: 基于单应矩阵的图像拼接

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/703327/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球