python实现图像全景拼接

作者:Zhansijing 时间:2023-05-08 13:29:24 

图像的全景拼接包括三大部分:特征点提取与匹配、图像配准、图像融合。

1、基于SIFT的特征点的提取与匹配

利用Sift提取图像的局部特征,在尺度空间寻找极值点,并提取出其位置、尺度、方向信息。

具体步骤:

1). 生成高斯差分金字塔(DOG金字塔),尺度空间构建

2). 空间极值点检测(关键点的初步查探)

3). 稳定关键点的精确定位

4). 稳定关键点方向信息分配

5). 关键点描述

6). 特征点匹配

2、图像配准

图像配准是一种确定待拼接图像间的重叠区域以及重叠位置的技术,它是整个图像拼接的核心。本节采用的是基于特征点的图像配准方法,即通过匹配点对构建图像序列之间的变换矩阵,从而完成全景图像的拼接。

变换矩阵H求解是图像配准的核心,其求解的算法流程如下。

1)检测每幅图像 * 征点。

2)计算特征点之间的匹配。

3)计算图像间变换矩阵的初始值。

4)迭代精炼H变换矩阵。

5)引导匹配。用估计的H去定义对极线附近的搜索区域,进一步确定特征点的对应。

6)重复迭代4)和5)直到对应点的数目稳定为止。

设图像序列之间的变换为投影变换

可用4组最佳匹配计算出H矩阵的8 个自由度参数hi=( i=0,1,...,7),并以此作为初始值。

为了提高图像配准的精度,本节采用RANSAC算法对图像变换矩阵进行求解与精炼,达到了较好的图像拼接效果。RANSAC算法的思想简单而巧妙:首先随机地选择两个点,这两个点确定了一条直线,并且称在这条直线的一定范围内的点为这条直线的支撑。这样的随机选择重复数次,然后,具有最大支撑集的直线被确认为是样本点集的拟合。在拟合的误差距离范围内的点被认为是内点,它们构成一致集,反之则为外点。根据算法描述,可以很快判断,如果只有少量外点,那么随机选取的包含外点的初始点集确定的直线不会获得很大的支撑,值得注意的是,过大比例的外点将导致RANSAC算法失败。在直线拟合的例子中,由点集确定直线至少需要两个点;而对于透视变换,这样的最小集合需要有4个点。

3、图像融合

因为相机和光照强度的差异,会造成一幅图像内部,以及图像之间亮度的不均匀,拼接后的图像会出现明暗交替,这样给观察造成极大的不便。 亮度与颜色均衡处理,通常的处理方式是通过相机的光照模型,校正一幅图像内部的光照不均匀性,然后通过相邻两幅图像重叠区域之间的关系,建立相邻两幅图像之间直方图映射表,通过映射表对两幅图像做整体的映射变换,最终达到整体的亮度和颜色的一致性。

具体实现:


import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt

if __name__ == '__main__':
top, bot, left, right = 100, 100, 0, 500
img1 = cv.imread('1.jpg')
img2 = cv.imread('2.jpg')
srcImg = cv.copyMakeBorder(img1, top, bot, left, right, cv.BORDER_CONSTANT, value=(0, 0, 0))
testImg = cv.copyMakeBorder(img2, top, bot, left, right, cv.BORDER_CONSTANT, value=(0, 0, 0))
img1gray = cv.cvtColor(srcImg, cv.COLOR_BGR2GRAY)
img2gray = cv.cvtColor(testImg, cv.COLOR_BGR2GRAY)
sift = cv.xfeatures2d_SIFT().create()
# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1gray, None)
kp2, des2 = sift.detectAndCompute(img2gray, 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)

# Need to draw only good matches, so create a mask
matchesMask = [[0, 0] for i in range(len(matches))]

good = []
pts1 = []
pts2 = []
# ratio test as per Lowe's paper
for i, (m, n) in enumerate(matches):
if m.distance < 0.7*n.distance:
good.append(m)
pts2.append(kp2[m.trainIdx].pt)
pts1.append(kp1[m.queryIdx].pt)
matchesMask[i] = [1, 0]

draw_params = dict(matchColor=(0, 255, 0),
singlePointColor=(255, 0, 0),
matchesMask=matchesMask,
flags=0)
img3 = cv.drawMatchesKnn(img1gray, kp1, img2gray, kp2, matches, None, **draw_params)
plt.imshow(img3, ), plt.show()

rows, cols = srcImg.shape[:2]
MIN_MATCH_COUNT = 10
if len(good) > MIN_MATCH_COUNT:
src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)
dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)
M, mask = cv.findHomography(src_pts, dst_pts, cv.RANSAC, 5.0)
warpImg = cv.warpPerspective(testImg, np.array(M), (testImg.shape[1], testImg.shape[0]), flags=cv.WARP_INVERSE_MAP)

for col in range(0, cols):
if srcImg[:, col].any() and warpImg[:, col].any():
left = col
break
for col in range(cols-1, 0, -1):
if srcImg[:, col].any() and warpImg[:, col].any():
right = col
break

res = np.zeros([rows, cols, 3], np.uint8)
for row in range(0, rows):
for col in range(0, cols):
if not srcImg[row, col].any():
res[row, col] = warpImg[row, col]
elif not warpImg[row, col].any():
res[row, col] = srcImg[row, col]
else:
srcImgLen = float(abs(col - left))
testImgLen = float(abs(col - right))
alpha = srcImgLen / (srcImgLen + testImgLen)
res[row, col] = np.clip(srcImg[row, col] * (1-alpha) + warpImg[row, col] * alpha, 0, 255)

# opencv is bgr, matplotlib is rgb
res = cv.cvtColor(res, cv.COLOR_BGR2RGB)
# show the result
plt.figure()
plt.imshow(res)
plt.show()
else:
print("Not enough matches are found - {}/{}".format(len(good), MIN_MATCH_COUNT))
matchesMask = None

实验结果:

1、室内场景:

python实现图像全景拼接

原图1

python实现图像全景拼接

原图2

拼接后:

python实现图像全景拼接

2、室外场景:

场景1:

python实现图像全景拼接

原图1

python实现图像全景拼接

原图2

拼接后:

python实现图像全景拼接

场景2:

python实现图像全景拼接

原图1

python实现图像全景拼接

原图2

拼接后:

python实现图像全景拼接

场景3:

python实现图像全景拼接

原图1

python实现图像全景拼接

原图2

拼接后:

python实现图像全景拼接

总结:

本文分别针对室内和室外两种情况对两张图像做全景拼接,发现室内情况下拼接的效果较为好。在室外场景1情况下,两张图像有近景和远景结合,两张图像拼接后近景的图像被放大并有一定程度的倾斜;在场景2中,两张图像都是远景,拼接后的效果还不错但是在拼接后图像的中上方出现了拼接缝;场景3是在不同明亮程度下图像的拼接可以发现拼接后的图像出现明显的明暗差距,并且拼接缝明显两张图像没有很好的拼接在一起,出现很多没有重合的地方。

本实验最初是用opencv-contrib3.4.5版本,但是由于sift的专利限制无法使用,随后用opencv-contriv3.4.2代码可以运行,不会出现问题。方法:先卸载当前版本的opencv并安装:

pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv-contrib-python==3.4.2.16

本文已被收录到专题《python图片处理操作》 ,欢迎大家点击学习更多精彩内容。

来源:https://blog.csdn.net/weixin_37592611/article/details/88921001

标签:python,图像,拼接
0
投稿

猜你喜欢

  • Python实现C#代码生成器应用服务于Unity示例解析

    2023-01-18 00:33:44
  • python实现根据图标提取分类应用程序实例

    2022-07-23 16:22:39
  • python 正则表达式 概述及常用字符

    2023-03-03 07:16:15
  • PHP OPP机制和模式简介(抽象类、接口和契约式编程)

    2023-11-21 10:53:53
  • MYSQL教程:服务器优化和硬件优化

    2009-02-27 15:43:00
  • python实现随机漫步方法和原理

    2023-06-26 19:32:02
  • SQL Server中通过reverse取某个最后一次出现的符号后面的内容(字符串反转)

    2024-01-23 14:19:39
  • JS实现判断有效的数独算法示例

    2024-02-25 08:22:15
  • MySQL数据库基于sysbench实现OLTP基准测试

    2024-01-28 11:07:14
  • php 时间计算问题小结

    2023-11-03 14:37:06
  • python的迭代器与生成器实例详解

    2021-06-21 15:36:41
  • Python读取本地文件并解析网页元素的方法

    2022-01-10 08:06:27
  • python 查找文件名包含指定字符串的方法

    2021-05-03 08:54:21
  • vue2 利用echarts 单独绘制省份的步骤

    2024-04-09 10:45:42
  • 深入了解Python中pop和remove的使用方法

    2021-02-14 00:32:43
  • django实现后台显示媒体文件

    2023-07-26 15:03:23
  • 教你如何在pycharm中使用less

    2021-08-12 13:59:32
  • Python全栈之文件函数和函数参数

    2023-05-11 02:28:21
  • Go每日一库之quicktemplate的使用

    2023-06-28 01:03:15
  • 如何解决“cint和clng的溢出出错”问题?

    2009-12-03 20:21:00
  • asp之家 网络编程 m.aspxhome.com