⚠申明: 未经许可,禁止以任何形式转载,若要引用,请标注链接地址。 全文共计6757字,阅读大概需要3分钟
🌈更多学习内容, 欢迎👏关注👀【文末】我的个人微信公众号:不懂开发的程序猿
个人网站:https://jerry-jy.co/❗❗❗知识付费,🈲止白嫖,有需要请后台私信或【文末】个人微信公众号联系我
基于OpenCv的图像全景拼接
- 基于OpenCv的图像全景拼接
- 任务需求
- 任务目标
- 1、掌握基于OpenCv提取SIFT特征点
- 2、掌握基于OpenCv使用SIFT描述子进行Brute-Force蛮力匹配
- 3、掌握基于OpenCv计算单应性矩阵
- 任务环境
- 1、jupyter开发环境
- 2、OpenCv
- 3、python3.6
- 任务实施过程
- 一、图像全景拼接
- 1.导入所需要的工具包和图像
- 2.提取A、B图片SIFT特征描述子
- 3.Brute-Force蛮力匹配两张图片所有特征点
- 4当筛选后的匹配对大于4时,计算视角变换矩阵
- 5.图片A进行视角变换并与B图结合
- 6.可视化配对关键点
- 二、拼接图像黑边去除
- 1.定义图像黑边去除函数
- 2.去除拼接后图像黑边
- 三、多张图像全景拼接
- 1.两张图像全景拼接
- 2.多张图像全景拼接
- 四、任务小结
- 说明
基于OpenCv的图像全景拼接
任务需求
图像拼接的主要目的是为了解决相机视野限制,生成更宽的图像场景。简单来说图像拼接技术就是把若干幅有重叠部分的图像合成一幅大视角宽幅面的图像。图像拼接技术已普遍出现在海洋和矿产勘测、卫星遥感探索、医学成像、计算机特效生成以及近期热门的虚拟现实等领域。
本次实验是基于特征点匹配的全景图像拼接算法,首先提取各图像中的SIFT特征,通过特征点匹配完成两幅图像的配准;再根据图像配准结果计算出图像间的变换矩阵;最后通过视角变换矩阵变换图像进行拼接。
任务目标
1、掌握基于OpenCv提取SIFT特征点
2、掌握基于OpenCv使用SIFT描述子进行Brute-Force蛮力匹配
3、掌握基于OpenCv计算单应性矩阵
任务环境
1、jupyter开发环境
2、OpenCv
3、python3.6
任务实施过程
一、图像全景拼接
图像全景拼接具体地说就是使用多个摄像机对同一个场景在不同角度拍摄,把得到的多个图像进行校正、去噪、匹配、融合,最终构建成一个质量高、清晰、边缘平滑、分辨率高的图像。
1.导入所需要的工具包和图像
import cv2 # 导入opencv
import matplotlib.pyplot as plt # 导入绘图模块
import numpy as np # 导入numpy库
from utils import im_show # 导入显示图像函数
# 绘制图像直接展示,不用调用plt.show()
%matplotlib inline
# 用来正常显示中文标签
plt.rc('font',family="SimHei")
# 读取拼接图像(右边,左边)
imgA = cv2.imread(r'./experiment/data/2.jpg')
imgB = cv2.imread(r'./experiment/data/1.jpg')
# 设置画布大小
plt.figure(figsize=(15,12))
# 显示图像
im_show('原图像',np.hstack((imgA,imgB)))
2.提取A、B图片SIFT特征描述子
# 先将两张照片转换成灰度图
grayA = cv2.cvtColor(imgA, cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(imgB, cv2.COLOR_BGR2GRAY)
# 建立SIFT生成器
descriptor = cv2.SIFT_create()
# 检测两个图像的SIFT特征点,并计算描述子
kpsA, featuresA = descriptor.detectAndCompute(grayA, None)
kpsB, featuresB = descriptor.detectAndCompute(grayB, None)
print('图像A和B的提取的SIFT关键点个数:',len(kpsA),len(kpsB))
# 将得到的关键点坐标转换成NumPy数组
# kpsA = np.float32([kpA.pt for kpA in kpsA])
# kpsB = np.float32([kpB.pt for kpB in kpsB])
3.Brute-Force蛮力匹配两张图片所有特征点
# 创建BFMatcher对象,使用默认参数做蛮力匹配
matcher = cv2.BFMatcher()
# 使用KNN检测来自A、B图的SIFT特征匹配对,K=2表示一个特征点对应与它最佳匹配的2个特征点
rawMatches = matcher.knnMatch(featuresA, featuresB, k=2)
# 应用比率测试
# 使用for循环,设一个特征点对应的两个特征点的距离m和n
# 如果m<0.75n(m和n表示距离)表示距离相对较近,将满足条件的匹配保留下来
# queryIdx是一组关键点的索引,trainIdx是另一组关键点的索引
good = []
matches = []
for m, n in rawMatches:
if m.distance < 0.75 * n.distance:
matches.append((m.trainIdx, n.queryIdx))
good.append([m])
print('两张图片一共匹配了{}对关键点'.format(np.array(matches).shape[0]))
# 使用KNN方法绘制匹配点,flags=0表示画特征点和连线,flags=2表示不画特征点。
img = cv2.drawMatchesKnn(imgA,kpsA,imgB,kpsB,good,None,flags=2)
# 设置画布大小
plt.figure(figsize=(15,12))
im_show('使用SIFT描述子的蛮力匹配的关键点',img)
4当筛选后的匹配对大于4时,计算视角变换矩阵
视角变换矩阵也被称为单应性矩阵(H矩阵)。图像拼接之前要先对图像进行角度变换的操作。得到H矩阵(3*3)最少需要4对配对点(x,y)。
# 将得到的关键点坐标转换成NumPy数组
kpsA = np.float32([kpA.pt for kpA in kpsA])
kpsB = np.float32([kpB.pt for kpB in kpsB])
if len(matches) > 4:
# 获取匹配对的点坐标
ptsA = np.float32([kpsA[i] for (_, i) in matches])
ptsB = np.float32([kpsB[i] for (i, _) in matches])
# findHomography()函数计算视角变换矩阵
# ptsA, ptsB表示两幅图的sift特征点坐标
# cv2.RANSAC表示用RANSAC选择最适合的配对特征点
H, status = cv2.findHomography(ptsA, ptsB, cv2.RANSAC, 4.0)
# 得到的返回值H就是视角变换矩阵H(3*3)
print(H.shape,H)
5.图片A进行视角变换并与B图结合
# 获取两个图像的高(h)和宽(w)
hA, wA = imgA.shape[:2]
print((hA, wA))
hB, wB = imgB.shape[:2]
print((hB, wB))
# warpPerspective()透视变换函数,放入源图像,H矩阵,设置变换后图像的形状
result = cv2.warpPerspective(imgA, H, (wA+wB, hA))
# 查看A图片变换后图像
plt.figure(figsize=(15,12))
im_show('图像A变换后', result)
# 将图片B传入result图片最左端
result[:hB, :wB] = imgB
# 查看拼接后的图像
plt.figure(figsize=(15,12))
im_show('图像拼接后', result)
6.可视化配对关键点
# 创建一个两个图像宽度的全是0的数组
vis = np.zeros((hA, wA+wB, 3), dtype=np.uint8)
# 对数组的切片赋值,左边为imgA,右边为imgB
vis[0:hA, 0:wA] = imgA
vis[0:hB, wA:] = imgB
# 联合遍历,画出匹配对
# status是计算h矩阵返回的掩码,值为1认为是匹配点,0认为是离群点
# queryIdx,trainIdx是两组关键点的索引
for ((trainIdx, queryIdx), s) in zip(matches, status):
# 当点对匹配成功时,画到可视化图上
if s == 1:
# 画出匹配关键点对
ptA = (int(kpsA[queryIdx][0]), int(kpsA[queryIdx][1]))
ptB = (int(kpsB[trainIdx][0]) + wA, int(kpsB[trainIdx][1]))
# line()绘制直线,放入直线起点和终点坐标,设置绘制颜色为绿色
cv2.line(vis, ptA, ptB, (0, 255, 0))
plt.figure(figsize=(15,12))
im_show('图像拼接关键点配对', vis)
二、拼接图像黑边去除
因为设置拼接后的图像宽度是两张图像的宽度和,当两个图像拼接后可能会留下黑边,接下来定义函数去除黑边
1.定义图像黑边去除函数
def change_size(image):
'''
图像黑边去除函数
image:源图像
'''
img = cv2.medianBlur(image, 5) # 中值滤波,去除黑色边际中可能含有的噪声干扰
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 转换成灰度图
a,binary_image = cv2.threshold(gray, 15, 255, cv2.THRESH_BINARY) # 调整裁剪效果,阈值二值化来分离出前景和背景
indexes = np.where(binary_image == 255) # 提取白色像素点的坐标,输出的是宽(w)和高(h)
# 获取得到的高和宽的最小值和最大值,得到上下左右四个边界和宽度和高度
left = min(indexes[0]) # 左边界
right = max(indexes[0]) # 右边界
width = right - left # 宽度
bottom = min(indexes[1]) # 底部
top = max(indexes[1]) # 顶部
height = top - bottom # 高度
# 根据得到的边界对图像切片截取,去除黑边,这里列数减50是为了完全去除黑边
pre1_picture = image[left:left + width, bottom:bottom + height-50]
# 返回图像截取后的结果
return pre1_picture
2.去除拼接后图像黑边
result = change_size(result)
# 查看黑边去除后的图像
plt.figure(figsize=(15,12))
im_show('图像拼接(黑边去除)', result)
三、多张图像全景拼接
1.两张图像全景拼接
将之前两张图像全景拼接的代码放入Stitcher.py文件中。注意我们之前的代码imgA是拼接的右边图像,imgB是拼接的左边图像,Stitcher.py文件中是按照拼接从左到右放入图像。
from Stitcher import Stitcher
imageA = cv2.imread(r'./experiment/data/1.jpg')
imageB = cv2.imread(r'./experiment/data/2.jpg')
stitcher = Stitcher() # 实例化Stitcher类
# 放入两张图像,设置showMatches=True表示返回两个图像配对点可视化
(result, vis) = stitcher.stitch([imageA, imageB], showMatches=True)
# 去除黑边
result = change_size(result)
plt.figure(figsize=(15,12))
im_show('全景图像拼接(两张)', result)
# 将拼接图像保存
cv2.imwrite(r'./experiment/data/12.jpg',result)
plt.figure(figsize=(15,12))
im_show('图像配对关键点', vis)
2.多张图像全景拼接
# 导入第三和第四张照片,将其依次拼接到上面两个图像拼接的结果中
imageC = cv2.imread(r'./experiment/data/3.jpg')
imageD = cv2.imread(r'./experiment/data/4.jpg')
stitcher = Stitcher() # 实例化Stitcher类
# 放入两张图像,设置showMatches=True表示返回两个图像配对点可视化
result = stitcher.stitch([result, imageC], showMatches=False)
result = change_size(result) # 去除黑边
result = stitcher.stitch([result, imageD], showMatches=False)
result = change_size(result) # 去除黑边
plt.figure(figsize=(15,12))
im_show('全景图像拼接(四张)', result)
# 将图像保存
cv2.imwrite(r'./experiment/data/1234.jpg',result)
四、任务小结
本次实验主要完成基于OpenCv根据两张图像的SIFT特征点进行全景拼接。
通过本次实验需要掌握以下内容:
- 掌握基于OpenCv提取SIFT特征点
- 掌握基于OpenCv使用SIFT描述子进行Brute-Force蛮力匹配
- 掌握基于OpenCv计算单应性矩阵
–end–
说明
本实验(项目)/论文若有需要,请后台私信或【文末】个人微信公众号联系我