基于特征的全景图像拼接
一、基本原理
1.特征点匹配(基于特征)
(1)什么样的点是特征点
那些最容易识别的像素点(角点),比如纹理丰富的物体边缘点等。
1)opencv棋盘格角点检测原理总结
findCHESSBOARDcorners 是opencv提供的一种找棋盘格角点的方法,可用来参考
(2)检测特征点
1)定位
标识图像上在图像转换(例如平移(移位),缩放(大小增加/减小)和旋转)下稳定的点。定位器找到这些点的x,y坐标。ORB检测器使用的定位器称为FAST
2)描述
该描述符对点的外观进行编码,以便我们可以区分一个特征点。在特征点评估的描述符只是一个数字数组。理想情况下,两个图像中的相同物理点应具有相同的描述符。ORB使用功能描述符的修改版本,称为BRISK。
例如,为实现人脸识别系统,我们首先需要一个人脸检测器,该检测器输出一个人脸所在的矩形的坐标。检测器不知道或不在乎该人是谁。它唯一的工作就是找到一张脸。系统的第二部分是识别算法。原始图像被裁剪为检测到的脸部矩形,并将此裁剪后的图像馈送到最终识别人的脸部识别算法。特征检测器的定位器的作用类似于面部检测器。它定位有趣的点,但不处理该点的身份。描述符描述了点周围的区域,因此可以在其他图像中再次对其进行识别。
仅当我们知道两个图像中的相应特征时,才能计算出两个图像的单应性。因此,使用匹配算法来查找一个图像中的哪些特征与另一图像中的特征匹配。为此,将一个图像中每个特征的描述符与第二个图像中每个特征的描述符进行比较,以找到良好的匹配。
(3)如何匹配到一起
单应性
观察着三张图的封面中反光,3由1通过单应性变换而来,通过12算单应性,再用单应性把1转化成3
描述子
对于检测出的角点,用一些数学上的特征对其进行描述,如梯度直方图,局部随机二值特征等。检测子和描述子的常用提取方法有:
sift,harris,surf(基于sift改进,速度约是sift3倍),fast,agast,brisk,freak,brisk,brief/orb 等。
surf
取一幅图像中的一个SIFT关键点,并找出其与另一幅图像中欧式距离最近的前两个关键点,在这两个关键点中,如果最近的距离除以次近的距离得到的比率ratio少于某个阈值T,则接受这一对匹配点。
ratio=0. 4:对于准确度要求高的匹配;
ratio=0. 6:对于匹配点数目要求比较多的匹配;
ratio=0. 5:一般情况下
SURF
ORB
匹配
通过各个角点的描述子来判断它们在两张图像中的对应关系
SURF
ORB
ORB速度明显快于SURF,但是提取的特征点也远少于SURF,图像特征是图像拼接质量的关键,在进行图像拼接时,需要在速度与质量之间进行取舍。
对比三幅渐入渐出融合的效果图,其羽化锐度只是一个加权系数,对融合速度并不会造成影响。对两幅原始图像中进行实验,三个羽化锐度参数所对应的融合速度在0.33S~0.36S之间,而其融合效果相差十分明显,羽化锐度越大,线性加权平均效果越好,拼接缝越不明显,图像重合区域的过度看起来更加的自然。实际运用中,通过改变加权系数,找到合适的值,来调整图像重叠区域的平滑过渡,使重叠区域看起来更加自然
3)如何消除一些错误的匹配
消噪:去除错误匹配的外点,保留正确的匹配点。常用方法有KDTREE,BBF,Ransac,GTM等。
2.拼接(图像拼接)
单应性
平移(MOTION_TRANSLATION):可以将第一张图像移位(平移) (x,y)以获得第二张图像。我们仅需要估计两个参数x和y。
欧几里得(MOTION_EUCLIDEAN):第一个图像是第二个图像的旋转和移位版本。因此,存在三个参数-x,y和angle。您会在图4中注意到,当正方形进行欧几里德变换时,大小不变,平行线保持平行,变换后直角保持不变。
仿射(MOTION_AFFINE):仿射变换是旋转,平移(shift),缩放和剪切的组合。该变换具有六个参数。当正方形进行仿射变换时,平行线保持平行,但以直角相交的线不再保持正交。
单应性(MOTION_HOMOGRAPHY):上述所有变换都是2D变换。它们不考虑3D效果。另一方面,单应变换可以解决一些3D效果(但不是全部)。此转换有8个参数。使用同形法转换后的正方形可以更改为任何四边形。
opencv提供的stitch拼接
opencv提供的stitch拼接
#include <iostream>
#include <fstream>
#include <opencv2/core/core.hpp>
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/stitching.hpp"
#include<Windows.h>
using namespace std;
using namespace cv;
bool try_use_gpu = false;
vector<Mat> imgs;
string result_name = "result.jpg";
int main()
{
Mat img1 = imread("images\\L_8.jpg");
Mat img2 = imread("images\\L_9.jpg");
// Mat img3 = imread("images\\18.jpg");
imgs.push_back(img1);
imgs.push_back(img2);
// imgs.push_back(img3);
Mat pano;
Stitcher stitcher = Stitcher::createDefault(try_use_gpu);
Stitcher::Status status = stitcher.stitch(imgs, pano);
if (status != Stitcher::OK)
{
cout << "Can't stitch images, error code = " << status << endl;
return -1;
}
namedWindow(result_name);
imshow(result_name, pano);
imwrite(result_name, pano);
waitKey();
return 0;
}