图像拼接整体流程
根据给定图像,实现特征匹配
详情参见python计算机视觉编程(三)Harris角点 SIFT 匹配地理标记图像: https://blog.csdn.net/qq_41409331/article/details/88618847.
通过匹配特征计算图像之间的变换结构
详情参见python计算机视觉编程(四)图像到图像的映射前半部分: https://blog.csdn.net/qq_41409331/article/details/88662767.
利用图像变换结构,实现图像映射
详情参见python计算机视觉编程(四)图像到图像的映射后半部分: https://blog.csdn.net/qq_41409331/article/details/88662767.
利用叠加后的图像,采用算法,对齐特征点
这里介绍两种常用的方法
APAP
- 提取两张图片的sift特征点
- 对两张图片的特征点进行匹配
- 使用RANSAC算法进行特征点对的筛选。筛选后的特征点基本能够对应。
RANSAC的基本假设是:
(1)数据由“局内点”组成,例如:数据的分布可以用一些模型参数来解释;
(2)“局外点”是不能适应该模型的数据;
(3)除此之外的数据属于噪声。
局外点产生的原因有:噪声的极值;错误的测量方法;对数据的错误假设。
RANSAC也做了以下假设:给定一组(通常很小的)局内点,存在一个可以估计模型参数的过程;而该模型能够解释或者适用于局内点。
可以参考 https://www.cnblogs.com/weizc/p/5257496.html. - 使用DLT算法,将剩下的特征点对进行透视变换矩阵的估计。
- 因为得到的透视变换矩阵是基于全局特征点对进行的,即一个刚性的单应性矩阵完成配准。为提高配准的精度,Apap将图像切割成无数多个小方块,对每个小方块的变换矩阵逐一估计。
效果展示
Lowe’s算法
为了排除因为图像遮挡和背景混乱而产生的无匹配关系的关键点,SIFT的作者Lowe提出了比较最近邻距离与次近邻距离的SIFT匹配方式:取一幅图像中的一个SIFT关键点,并找出其与另一幅图像中欧式距离最近的前两个关键点,在这两个关键点中,如果最近的距离除以次近的距离得到的比率ratio少于某个阈值T,则接受这一对匹配点。因为对于错误匹配,由于特征空间的高维性,相似的距离可能有大量其他的错误匹配,从而它的ratio值比较高。显然降低这个比例阈值T,SIFT匹配点数目会减少,但更加稳定,反之亦然。
Lowe推荐ratio的阈值为0.8,但作者对大量任意存在尺度、旋转和亮度变化的两幅图片进行匹配,结果表明ratio取值在0. 4~0. 6 之间最佳,小于0. 4的很少有匹配点,大于0. 6的则存在大量错误匹配点,所以建议ratio的取值原则如下:
ratio=0.4:对于准确度要求高的匹配;
ratio=0.6:对于匹配点数目要求比较多的匹配;
ratio=0.5:一般情况下。
效果十分明显
由于这部分以前做过,当时使用的是C++和opencv库,所以这里给出的是C++的代码
#include "stdafx.h"
#include "highgui/highgui.hpp"
#include "opencv2/nonfree/nonfree.hpp"
#include "opencv2/legacy/legacy.hpp"
#include <iostream>
using namespace cv;
using namespace std;
void OptimizeSeam(Mat& img1, Mat& trans, Mat& dst);
typedef struct
{
Point2f left_top;
Point2f left_bottom;
Point2f right_top;
Point2f right_bottom;
}four_corners_t;
four_corners_t corners;
int main(int argc, char *argv[])
{
Mat image01 = imread("D:\\Univ2.jpg", 1); //右图
Mat image02 = imread("D:\\Univ3.jpg", 1); //左图
imshow("p2", image01);
imshow("p1", image02);
//灰度图转换
Mat image1, image2;
cvtColor(image01, image1, CV_RGB2GRAY);
cvtColor(image02, image2, CV_RGB2GRAY);
//提取特征点
SurfFeatureDetector Detector(2000);
vector<KeyPoint> keyPoint1, keyPoint2;
Detector.detect(image1, keyPoint1);
Detector.detect(image2, keyPoint2);
//特征点描述,为下边的特征点匹配做准备
SurfDescriptorExtractor Descriptor;
Mat imageDesc1, imageDesc2;
Descriptor