python实现图像全景拼接


Posted in Python onMarch 27, 2020

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

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图片处理操作》 ,欢迎大家点击学习更多精彩内容。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
用Python编写一个国际象棋AI程序
Nov 28 Python
Python SQL查询并生成json文件操作示例
Aug 17 Python
在Pycharm中项目解释器与环境变量的设置方法
Oct 29 Python
python flask框架实现传数据到js的方法分析
Jun 11 Python
python对文件目录的操作方法实例总结
Jun 24 Python
pytorch自定义二值化网络层方式
Jan 07 Python
pytorch-神经网络拟合曲线实例
Jan 15 Python
pandas使用之宽表变窄表的实现
Apr 12 Python
python将字典内容写入json文件的实例代码
Aug 12 Python
pycharm 复制代码出现空格的解决方式
Jan 15 Python
python中的被动信息搜集
Apr 29 Python
 分享一个Python 遇到数据库超好用的模块
Apr 06 Python
如何在Python 游戏中模拟引力
Mar 27 #Python
Python 实现平台类游戏添加跳跃功能
Mar 27 #Python
django配置app中的静态文件步骤
Mar 27 #Python
使用卷积神经网络(CNN)做人脸识别的示例代码
Mar 27 #Python
django实现HttpResponse返回json数据为中文
Mar 27 #Python
python对XML文件的操作实现代码
Mar 27 #Python
Python Socketserver实现FTP文件上传下载代码实例
Mar 27 #Python
You might like
星际争霸中的热键
2020/03/04 星际争霸
用PHP创建PDF中文文档
2006/10/09 PHP
PHP5.4中json_encode中文转码的变化小结
2013/01/30 PHP
php小经验:解析preg_match与preg_match_all 函数
2013/06/29 PHP
php调用MySQL存储过程的方法集合(推荐)
2013/07/03 PHP
基于php数组中的索引数组和关联数组详解
2018/03/12 PHP
JavaScript 特殊字符
2007/04/05 Javascript
javascript 哈希表(hashtable)的简单实现
2010/01/20 Javascript
javascript实现简单的分页特效
2015/08/12 Javascript
JavaScript获取图片像素颜色并转换为box-shadow显示
2016/03/11 Javascript
BootStrap的alert提示框的关闭后再显示怎么解决
2016/05/17 Javascript
jQuery 3 中的新增功能汇总介绍
2016/06/12 Javascript
javascript加载xml 并解析各节点的值(实现方法)
2016/10/12 Javascript
Bootstrap基本模板的使用和理解1
2016/12/14 Javascript
AngularJS路由实现页面跳转实例
2017/03/03 Javascript
Angular CLI 安装和使用教程
2017/09/13 Javascript
jquery validate 实现动态增加/删除验证规则操作示例
2019/10/28 jQuery
讲解Python中fileno()方法的使用
2015/05/24 Python
Python使用urllib2模块实现断点续传下载的方法
2015/06/17 Python
详解python string类型 bytes类型 bytearray类型
2017/12/16 Python
Python yield与实现方法代码分析
2018/02/06 Python
多个应用共存的Django配置方法
2018/05/30 Python
Python全面分析系统的时域特性和频率域特性
2020/02/26 Python
Python文本文件的合并操作方法代码实例
2020/03/31 Python
详解python with 上下文管理器
2020/09/02 Python
Django URL参数Template反向解析
2020/11/24 Python
html5 自定义播放器核心代码
2013/12/20 HTML / CSS
美国著名的婴儿学步鞋老品牌:Robeez
2016/08/20 全球购物
英国乡村时尚和宠物用品专家:Pet & Country
2018/07/02 全球购物
安全生产宣传标语
2014/06/06 职场文书
家庭贫困证明书(3篇)
2014/09/15 职场文书
秦始皇兵马俑导游词
2015/02/02 职场文书
个人培训总结
2015/03/05 职场文书
《平移和旋转》教学反思
2016/02/19 职场文书
2016年中学清明节活动总结
2016/04/01 职场文书
CentOS下安装Jenkins的完整步骤
2022/04/07 Servers