最近学习了图像拼接的一些知识,在这里记录一下,方便以后的学习, 博客中的代码均基于python,目前只能用于左右拼接
基于sift特征点的图像拼接包括以下几个步骤:
1.sift特征点的提取
2.利用快速最近邻算法进行特征点粗匹配,并利用阈值设置和双向交叉检查方法进行初步的筛选
3.利用RANSAC 算法进行精匹配
4.图像变换,使不同图像映射到同一坐标系下
5.图像融合,融合规则包括取大,最佳缝合线发,Laplace金字塔法
1.sift特征点的提取
sift特征点的提取原理网上有很多的介绍,在这里不再赘述
具体看参考网址:https://blog.youkuaiyun.com/lingyunxianhe/article/details/79063547
在python中,已经集成了sift特征点提取的算法
# 创建sift特征提取器
sift = cv2.xfeatures2d.SIFT_create()
# 计算sift特征点的关键点和相应的描述子。注意,img为灰度图像
keypoints, des = sift.detectAndCompute(img, None)
keypoints参数是一个关键字列表,有以下几个属性:
pt: 表示图像中关键点的X坐标和Y坐标
size: 表示特征的直径
angle:表示特征的方向
response:表示关键点的强度。某些特征会通过SIFT来分类,因为它得到的特征比其他特征更好,通过查看response属性可以评估特征强度
octave:表示特征所在金字塔的层级。SIFT算法与人脸检测算法类似,即只通过改变计算参数来依次处理相同的图像。例如算法在每次迭代(octave)时,作为参数的图像尺寸和相邻像素都会发生变化,因此,octave属性表示的是检测到的关键点所在的层级。
class_id: 表示关键点的ID
2.利用快速最近邻算法进行特征点粗匹配,并利用阈值设置和双向交叉检查方法进行初步的筛选
快速最近邻算法特征匹配算法使用快速近似最近邻搜索算法寻找,适合在大量数据中查找匹配图像。
另一种常用的匹配算法是暴力匹配法(Brute-force match)会尝试所有可能的匹配,使得它总能够找到最佳匹配同时导致消耗的时间远大于快速最近邻算法,Flann匹配的速度远远快于Blute-Force,大约是10倍,因此只适合于少量图像的匹配。
具体实现:
1.快速最近邻算法特征匹配算法实现步骤:利用K-D 树( KDimensional Tree)数据结构来有序存放特征描述向量,再用快速近似 k 最近邻(FLANN)算法找出最近邻点和次近邻点。
2.找出特征点后, 由于匹配的特征点之间不仅要求特征描述向量距离最近,而且应该与其它特征点能够区分开来, 因此采用最近邻点与次近邻点距离比值来限制特征点匹配。 计算最近邻点的距离和次近邻点的距离的比值,若小于阈值则保留,反之,则剔除。
3.双向交叉检查方法:通过单一方向搜索匹配的特征点对易出现图像中单个特征点与另一幅图像多个特征点匹配的问题, 当图像匹配特征点对较少时,这一问题会严重影响空间变换矩阵的估计精度。通过双向交叉检查方法可以解决这一问题
# K-D tree建立索引方式的常量参数
FLANN_INDEX_KDTREE = 0
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50) # checks指定索引树要被遍历的次数
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches_1 = flann.knnMatch(des1, des2, k=2) # 进行匹配搜索,参数k为返回的匹配点对数量
# 把保留的匹配点放入good列表
good1 = []
T = 0.5 # 阈值
# 筛选特征点
for i, (m, n) in enumerate(matches_1):
if m.distance < T * n.distance: # 如果最近邻点的距离和次近邻点的距离比值小于阈值,则保留最近邻点
matchesMask[i] = [1, 0]
good1.append(m)
# 双向交叉检查方法
matches_2 = flann.knnMatch(des2, des1, k=2) # 进行匹配搜索
# 把保留的匹配点放入good2列表
good2 = []
for (m, n) in matches_2:
if m.distance