使用Python实现RANSAC图像拼接算法(应用广角图片)

2021年9月18日 1点热度 0条评论 来源: EMB看灯夜

进算计视觉课程,图像处理实例共享。

 

文章目录

  • 第一、文章实现内容及Ransac算法步骤简介
  • 第二、SIFT特征提取方法简介及效果
  • 第三、BFMatcher与Flann特征点匹配方法效果对比
  • 第四、RANSAC算法详解
  • 第五、Py实例代码实现

 

第一、文章实现内容及Ransac算法步骤简介

使用两张自己拍摄的横向位移差图像,验证RANSAC算法,实现步骤如下:

  1. 使用高斯滤波器对图像进行滤噪图像预处理。

  2. 分别对图像进行特征点提取。特征点提取方法主要有FAST、SURF、Harris、BRIEF, 在本例中使用SIFT提取方法。

  3. 根据提取的特征点,使用特征点匹配方法和条件得到两张图片的特征点对。本 例主要对BFMatcher特征点匹配方法和Flann特征点匹配方法进行效果比较和 运用。

  4. 根据得到特征点对使用鲁棒方法对特征点对进行筛选,排除错误的特征点对, 提高两张图像相似特征对的正确匹配度。常用的鲁棒方法主要有LMEDS、 RHO(PROSAC)和RANSAC算法,本例中使用RANSAC算法来进行特征点对筛选。

  5. 写出邻近点匹配列表,并且校正漂移。

  6. 读取变形图像做透视变换,将变形图像和原图像进行融合拼接。

  7. 特征点匹配对图像显示,拼接图像结果显示。

 

第二、SIFT特征提取方法简介及效果

        SIFT(Scale-invariant feature transform)尺度不变特征变换,其对刚体变换、光照强度、物体尺度变化和遮挡的情况时稳定性较好,可用于检测图像局部特征描述子即特征点。SIFT特征提取方法的主要走实现步骤主要包括:特征点提取、特征点方向获取、对特征点进行描述、特征点匹配。SIFT特征提取方法具体实现效果如图1所示。


                                                   图1 SIFT特征点提取效果显示图

第三、BFMatcher与Flann特征点匹配方法效果对比

        BFMatcher特征点匹配是一种常见的二维特征点段匹配方法,因其总是尝试所有可能特征点对匹配的算法运行特性,又俗称为“暴力匹配法”,虽算法实现简单但也具有运行速度慢、错误率高的特点。BFMatcher方法的运作过程大致分成三步:第一步,发现两幅图片分别提取出来N,M个特征向量;第二步,对N和M的特征向量进行匹配,根据用户设定的限制条件,找到最佳匹配特征点对;第三步,画出特征匹配结果。BFMatcher方法的特征匹配效果如图2所示(仅显示10个特征点)。

                                                                               图2 BFMatcher特征点提取效果显示

       Flann(Fast Library forApproximate Nearest Neighbors)快速最近邻特征点匹配,找到的是最近邻近特征匹配,具有算法快速但易受到失真、缩放的影响的特点。Flann算法的实现步骤如下:第一步,首先训练一个匹配器,以提高匹配速度;第二步,建立特征集的索引树,将图片每一个特征点和 该匹配器进行匹配;第三步,找出最佳匹配特征点对。Flann算法可以通过设置截断值来去除误差大的匹配,其特征匹配效果如图3所示(仅显示10个特征点)。

                                                                                   图3 Flann特征点提取效果显示图

        从图2和图3的特征点匹配效果进行对比,不难得到Flann算法比BFMatcher算法匹配效果更好的结论。由于本例核心为RANSAC算法,所以本例最后选择错误率高,更能够体现RANSAC算法筛选性能的BFMatcher特征匹配方法。

 

第四、RANSAC随机采样一致性算法详解

        RANSAC(RAndom SAmple Consensus)算法,是一种利用一组以“外点”构成的特征点对数据组中,进行正确估计并得到“内点”的数学模型迭代方法。其中,“外点”指数据组中的噪声或者离群点,在本例中值匹配错误的特征点对;“内点”指组成模型参数的数据即目标数据,在本例中指图像边缘正确匹配特征点对。RANSAC算法是一种较为不稳定的算法,是一种基于概率不断极性迭代的算法,算法具体实现原理如下:

  1. 假设内点在总数据集中的占比r。

  2. 得到取n个点时取到错误点即外点的概率1-pow(r,n)。

  3. 若进行k次迭代寻找正确点即内点,则最后能够得到正确模型的概率为      1-pow((1-pow(r,n),k)。

  4. 经过1~3步,最终可以得到内点占比为r的条件下,需要迭代次数

      

     上述RANSAC算法在原图中特征点对的分类效果如下图4所示,可一看到分类线旁边的点占总数据集的大部分,即离散程度最小。

      

 

第五、RANSAC算法Python代码实现
2.读入数据

代码如下(示例):

import random
import math
import cv2
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
from PIL import Image
import numpy as np
"""
https://zhuanlan.zhihu.com/p/62238520

RANSAC是通过反复选择数据集去估计出模型,一直迭代到估计出认为比较好的模型。
具体的实现步骤可以分为以下几步:
1.选择出可以估计出模型的最小数据集;(对于直线拟合来说就是两个点,对于计算Homography矩阵就是4个点)
2.使用这个数据集来计算出数据模型;
3.将所有数据带入这个模型,计算出“内点”的数目;(累加在一定误差范围内的适合当前迭代推出模型的数据)
4.比较当前模型和之前推出的最好的模型的“内点“的数量,记录最大“内点”数的模型参数和“内点”数;
5.重复1-4步,直到迭代结束或者当前模型已经足够好了(“内点数目大于一定数量”)。
"""
#设置一个至少10个匹配的条件(有MinMatchNum指定)来找目标
MinMatchNum = 20
#读取照片
L = cv2.imread('D:/MyTechnology/Python/2.jpg')          # queryImage
R = cv2.imread('D:/MyTechnology/Python/3.jpg')          # trainImage
#高斯滤波
L = cv2.GaussianBlur(L,(3,3),0)
R = cv2.GaussianBlur(R,(3,3),0)
#创建sift检测器
sift = cv2.xfeatures2d.SIFT_create()
# 计算所有特征点的特征值kp和特征向量des并获取
left_kp, left_des = sift.detectAndCompute(R, None)
righ_kp, righ_des = sift.detectAndCompute(L, None)
# BFMatcher爆力解决匹配,但是不好的特征值匹配较多
bf = cv2.BFMatcher()
matches = bf.knnMatch(left_des, righ_des, k=2)
# 进行特征点匹配筛选
BetterChoose1 = []
for m, n in matches:
    #认为第一近的点小于第二近的点一倍以上是好的匹配BetterChoose1
    if m.distance < 0.5 * n.distance:
        BetterChoose1.append(m)
# 但是由于爆力匹配的较好结果BetterChoose1匹配效果仍然不理想。
# 所以我们想到用Ransat的方法优化匹配结果
BetterChoose2 = np.expand_dims(BetterChoose1, 1)
match = cv2.drawMatchesKnn(L, left_kp, R, righ_kp, BetterChoose2[:30], None, flags=2)
# 判断是否当前模型已经符合超过MinMatchNum个点
if len(BetterChoose1) > MinMatchNum:
    # 获取关键点的坐标
    src_pts = np.float32([left_kp[m.queryIdx].pt for m in BetterChoose1]).reshape(-1, 1, 2)
    dst_pts = np.float32([righ_kp[m.trainIdx].pt for m in BetterChoose1]).reshape(-1, 1, 2)
    #在这里调用RANSAC方法得到解H
    H, modle = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
    wrap = cv2.warpPerspective(R, H, (R.shape[1] + R.shape[1], R.shape[0] + R.shape[0]))
    wrap[0:R.shape[0], 0:R.shape[1]] = L
    #得到新的位置
    rows, cols = np.where(wrap[:, :, 0] != 0)
    min_row, max_row = min(rows), max(rows) + 1
    min_col, max_col = min(cols), max(cols) + 1
    # 去除黑色无用部分
    LeftAndRight = wrap[min_row:max_row, min_col:max_col, :]
# 将图片结果进行显示
scal = 0.7 #蹄片显示比例控制
cv2.imshow('connect', cv2.resize(match, (0, 0), fx=scal, fy=scal, interpolation=cv2.INTER_NEAREST))
cv2.imshow('LeftAndRightg',cv2.resize(LeftAndRight, (0, 0), fx=scal, fy=scal, interpolation=cv2.INTER_NEAREST))
cv2.waitKey(0)
cv2.destroyAllWindows()








 

    原文作者:EMB看灯夜
    原文地址: https://blog.csdn.net/weixin_41094315/article/details/109563057
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。