程序大概流程就是输入两幅图像,转化成灰度图,提取特征点,对特征点进行描述,描述后的特征点进行匹配,选取几个最优的来获取投影映射矩阵,图像配准显示图像。
从提取特征点开始。计算机先是构造了尺度空间,尺度空间就是计算机在不同尺度下看某一个物体。差不都就是在模拟人观察一个物体,从模糊到清晰到内部结构那种感觉。从第0层塔的最底层你的原始灰度图开始,first Octave(0层塔)中从第二层到顶层为止,每一层是对下一层进行Laplacian变换,图像越来越模糊。然后next Octave(1层塔)第底层就是first Octave(0层塔)最底层长宽取一半,面积为它的四分之一。塔中各层间只是越来越模糊,它的分辨率没有变,而塔间的分辨率确实越来越低。右边相减就构成了左边的高斯差分尺度空间。上中下三层找绝对值极值
。
然后是对特征点进行描述。就是给他加方向,匹配的时候要用。如图每个特征点都有三个描述信息(尺度空间,模长,方向)。然后是进行匹配我们采用关键点特征向量的欧式距离来作为两幅图像中关键点的相似性判定度量。先找出图像1中的某个关键点,再找出其与图像2中欧式距离最近的前两个关键点,在这两个关键点中,如果最近的距离除以次近的距离少于某个比例阈值,则接受这一对匹配点。然后是求单应型矩阵,可以这样理解。两架相机拍同一空间上得到两幅图像AB,其中一幅A在另一幅B存在一种变换而且是一一对应的关系,他们之间可以用矩阵表示 这个矩阵用单应矩阵。最后按照这个单应型矩阵进行配准就可以了。
#include <highgui.h>
#include <nonfree\nonfree.hpp>
#include <cv.h>
#include "opencv2/legacy/legacy.hpp"
#include <iostream>
using namespace std;
using namespace cv;
Point2f getTransformPoint(const Point2f originalPoint, const Mat &transformMaxtri);
int main(int argc,char** argv){
Mat ima1=imread(argv[1]);
Mat ima2=imread(argv[2]);
if(ima1.empty()||ima2.empty()){
return 0;
}
Mat ima01,ima02;
cvtColor(ima1,ima01,CV_RGB2GRAY);
cvtColor(ima2,ima02,CV_RGB2GRAY);
//提取特征点
SiftFeatureDetector siftdetector(800);
vector<KeyPoint> keypoint1,keypoint2;
siftdetector.detect(ima01,keypoint1);
siftdetector.detect(ima02,keypoint2);
//找到特征点后就进行描述
SiftDescriptorExtractor siftextractor;
Mat imadesc1,imadesc2;
siftextractor.compute(ima01,keypoint1,imadesc1);
siftextractor.compute(ima02,keypoint2,imadesc2);
//对特征点进行匹配
FlannBasedMatcher matcher;
vector<DMatch> matchpoints;//两个函数queryIdx表示输入图像的特征描述子,trainIdx表示训练图像的特征描述子
matcher.match(imadesc1,imadesc2,matchpoints,Mat());
//选取前面几个最优匹配点
sort(matchpoints.begin(),matchpoints.end());
vector<Point2f> imagepoints1,imagepoints2;//point2f浮点数x,y。point2d单精度x,y
for(int i=0;i<10;i++){
imagepoints1.push_back(keypoint1[matchpoints[i].queryIdx].pt);//push_back在vector类尾部加一个数据
imagepoints2.push_back(keypoint2[matchpoints[i].trainIdx].pt);
}
//获取投影映射矩阵
Mat homo=findHomography(imagepoints1,imagepoints2,CV_RANSAC);//求单应型矩阵 理解在两视几何中,可以这样理解,两架相机拍同一空间上得到两幅图像AB,其中一幅A在另一幅B存在一种变换而且是一一对应的关系,他们之间可以用矩阵表示 这个矩阵用单应矩阵
Mat adjustMat=(Mat_<double>(3,3)<<1.0,0,ima01.cols,0,1.0,0,0,0,1.0);
Mat adjustHomo=adjustMat*homo;
//获取最强匹配点在原图,矩阵变换后的图的位置
Point2f originalLinkePoint,targetLinkPoint,basedImagePoint;
originalLinkePoint=keypoint1[matchpoints[0].queryIdx].pt;
targetLinkPoint=getTransformPoint(originalLinkePoint,adjustHomo);
basedImagePoint=keypoint2[matchpoints[0].trainIdx].pt;
//图像配准
Mat imageTransform1;
warpPerspective(ima1,imageTransform1,adjustHomo,Size(ima2.cols+ima01.cols+10,ima2.rows));
namedWindow("拼接结果");
imshow("拼接结果",imageTransform1);
waitKey(0);
destroyAllWindows();
return 0;
}
Point2f getTransformPoint(const Point2f originalPoint, const Mat &transformMaxtri)
{
Mat originelP, targetP;
originelP = (Mat_<double>(3, 1) << originalPoint.x, originalPoint.y, 1.0);
targetP = transformMaxtri*originelP;
float x = targetP.at<double>(0, 0) / targetP.at<double>(2, 0);
float y = targetP.at<double>(1, 0) / targetP.at<double>(2, 0);
return Point2f(x, y);
}
借鉴了
http://blog.csdn.net/abcjennifer/article/details/7639681
http://blog.csdn.net/jinshengtao/article/details/50043797?locationNum=3&fps=1
http://blog.csdn.net/dcrmg/article/details/52578732
请批评指教。另外不懂不同塔不同层的特征点他怎么汇总到原始图像的?