计算机视觉——基于RANSAC的图像全景拼接

本文介绍了基于RANSAC的图像全景拼接技术,详细阐述了RANSAC算法原理,包括随机抽样、单应矩阵计算、内点外点判断等,并探讨了APAP算法用于消除“鬼影”,以及最大流问题在拼接缝隙消除中的应用。通过实验分析,讨论了光照、角度等因素对拼接效果的影响,并总结了实施过程中遇到的问题与解决办法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

基于RANSAC的图像全景拼接

1、实验需求

  1. 针对固定点位拍摄多张图片,以中间图片为中心,实现图像的拼接融合
  2. 针对同一场景(需选取视差变化大的场景,也就是有近景目标),更换拍摄位置,分析拼接结果

2、语言和平台

语言:python2.7.13 (anaconda2)
平台:pycharm 2018.2

3、算法简介

RANSAC的全称是“RANdom SAmple Consensus(随机抽样一致)”。它可以从一组包含“局外点”的观测数据集中,通过迭代方式估计数学模型的参数。
1.随机选择四对匹配特征
2.根据DLT计算单应矩阵 H (唯一解)
3. 对所有匹配点,计算映射误差ε= || p i p_i pi,H p i p_i pi||
4. 根据误差阈值,确定inliers(例如3-5像素)
5. 针对最大inliers集合,重新计算单应矩阵 H

4、算法原理

1、RANSAC
对于ransac的简介,在这边博客中:https://blog.youkuaiyun.com/XYYHHH11/article/details/104635373
2、APAP
因同源序列图像的内容不仅随时间的变化会产生变化,而且可能受到配准和几何变换的影响,两幅图像间的重叠区域存在差异,直接拼接融合后图像会出现“鬼影”和拼接缝隙现象,所以经过配准的图像在融合过程中如何去除鬼影及拼接缝隙是两个非常重要的环节。其中可以用APAP来消除“鬼影”。
在这里插入图片描述
算法流程:
1.SIFT得到两幅图像的匹配点对
2.通过RANSAC剔除外点,得到N对内点
3.利用DLT和SVD计算全局单应性
4.将源图划分网格,取网格中心点,计算每个中心点和源图上内点之间的欧式距离和权重
5.将权重放到DLT算法的A矩阵中,构建成新的W*A矩阵,重新SVD分解,自然就得到了当前网格的局部单应性矩阵
6.遍历每个网格,利用局部单应性矩阵映射到全景画布上,就得到了APAP变换后的源图
7.最后就是进行拼接线的加权融合

3、最小割问题(最大流问题)
如何消除或弱化拼接缝隙就可以用最小割来解决。
在这里插入图片描述
3.1最小割问题
一个割就是一组边的集合,将给集合边从图中边集合中移除,那么图被分割为两个部分,这两个部分之间没有任何边连接。如果说得有点绕口,那么最简单来说,一块肉被从中间隔开,分成两个部分,中间断开的连接的集合就是割。最小割就是将图切割为两个部分时,代价最小的割的集合,代价就是边上容量的和(S部分到T部分边的容量)。

在这里插入图片描述
在这里插入图片描述
3.2最大流问题
假设现在有一个地下水管道网络,有m根管道,n个管道交叉点,现在自来水厂位于其中一个点,向网络中输水,隔壁老王在另外一个点接水,已知由于管道修建的年代不同,有的管道能承受的水流量较大,有的较小,现在求在自来水厂输入的水不限的情况下,能接到的水的最大值?
以上就是最大流问题。
在这里插入图片描述
以下是最大流问题的一些概念
1、残存网络与增广路径
根据图和各条边上的流可以画出一幅图的残存网络如下所示。上图为流网络,下图为残存网络,其中流网络中边上的数字分别是流量和容量,如10/12,那么10为边上的流量,12为边的容量。残存网络中可能会存在一对相反方向的边,与流网络中相同的边代表的是流网络中该边的剩余容量,在流网络中不存在的边代表的则是其在流网络中反向边的已有流量,这部分流量可以通过“回流”减少。例如,下图残存网络中,边<s,v1>的剩余容量为4,其反向边<v1.s>的值为12,即上图流网络中的边<s,v1>的流量。在残存网络中,值为0的边不会画出,如边<v1,v2>。
在这里插入图片描述
残存网络描述了图中各边的剩余容量以及可以通过“回流”删除的流量大小。在Ford-Fulkerson方法中,正是通过在残存网络中寻找一条从s到t的增广路径,并对应这条路径上的各边对流网络中的各边的流进行修改。如果路径上的一条边存在于流网络中,那么对该边的流增加,否则对其反向边的流减少。增加或减少的值是确定的,就是该增广路径上值最小的边。
2、Ford-Fulkerson方法
Ford-Fulkerson方法的正确性依赖于这个定理:当残存网络中不存在一条从s到t的增广路径,那么该图已经达到最大流。
Ford-Fulkerson方法的伪代码如下。其中<u,v>代表顶点u到顶点v的一条边,<u,v>.f表示该边的流量,c是边容量矩阵,c(i,j)表示边<i,j>的容量,当边<i,j>不存在时,c(i,j)=0。e为残存网络矩阵,e(i,j)表示边<i,j>的值,当边<i,j>不存在时,e(i,j)=0。E表示边的集合。f表示流网络。

Ford-Fulkerson
    for <u,v> ∈ E
        <u,v>.f = 0
    while find a route from s to t in e
        m = min(<u,v>.f
### 使用Python进行多图图像全景拼接和配准 #### 导入所需库 为了完成多张图片的全景拼接与配准,需要先安装并导入必要的库。这些库包括`cv2`用于计算机视觉操作以及`numpy`来支持数组运算。 ```python import cv2 import numpy as np from matplotlib import pyplot as plt ``` #### 准备工作 确保拥有足够的输入图像文件,并将其加载到程序中以便后续处理。这里假设已经准备好了一组待拼接的照片列表。 ```python images = [] for i in range(1, n+1): # 假设有n张照片 img_path = f'path_to_images/image_{i}.jpg' images.append(cv2.imread(img_path)) ``` #### 提取SIFT特征点及描述符 对于每一对相邻的图像,利用SIFT算法检测关键点并计算对应的描述向量。这一步骤有助于找到不同视图之间的对应关系[^2]。 ```python sift = cv2.SIFT_create() keypoints_list = [] descriptors_list = [] for image in images: gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) keypoints, descriptors = sift.detectAndCompute(gray_image, None) keypoints_list.append(keypoints) descriptors_list.append(descriptors) ``` #### 特征匹配 采用暴力匹配器(BFMatcher)来进行两两间的特征点对比,寻找最佳匹配对。考虑到效率问题,在实际应用中可以考虑FLANN-based matcher作为替代方案。 ```python bf = cv2.BFMatcher() matches_lists = [] for idx in range(len(images)-1): matches = bf.knnMatch(descriptors_list[idx], descriptors_list[idx+1], k=2) good_matches = [] for m,n in matches: if m.distance < 0.7*n.distance: good_matches.append([m]) matches_lists.append(good_matches) ``` #### 计算单应性矩阵(Homography Matrix) 一旦获得了足够数量的良好匹配点,则可以通过RANSAC算法估计两个连续帧之间存在的几何转换——即单应性矩阵H。此过程会重复执行直到遍历所有相邻图像对为止。 ```python homographies = [] for idx in range(len(matches_lists)): src_pts = np.float32([keypoints_list[idx][m.queryIdx].pt for m in matches_lists[idx]]).reshape(-1, 1, 2) dst_pts = np.float32([keypoints_list[idx+1][m.trainIdx].pt for m in matches_lists[idx]]).reshape(-1, 1, 2) H, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0) homographies.append(H) ``` #### 图像融合 最后一步就是将所有的变换应用于原始图像序列上,并依次叠加形成最终的结果。注意要妥善处理边界填充等问题以获得更好的效果。 ```python result = images[-1] for idx in reversed(range(len(homographies))): h_inv = np.linalg.inv(homographies[idx]) result = cv2.warpPerspective(result, h_inv, (images[idx].shape[1]+result.shape[1], max(images[idx].shape[0], result.shape[0]))) # 将当前图像粘贴到变形后的结果之上 rows, cols = images[idx].shape[:2] roi = result[0:rows, 0:cols] # 创建掩膜 img_mask = np.zeros((rows, cols), dtype=np.uint8)+255 ret, thresh = cv2.threshold(img_mask, 127, 255, cv2.THRESH_BINARY_INV) # 应用掩膜 masked_img = cv2.bitwise_and(roi, roi, mask=thresh) final_result = cv2.add(masked_img, images[idx]) # 更新ROI部分 result[0:rows, 0:cols] = final_result plt.imshow(cv2.cvtColor(result, cv2.COLOR_BGR2RGB)), plt.show() ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值