开发环境:VS2013+OpenCV3.0
一、Preparation
在学习图像识别中特征点检测与匹配时,需要用到OpenCV中的SIFT和SURF算法,如SiftFeatureDetector或SiftFeatureExtractor,在OpenCV2中SIFT和SURF算法被写在文件#include
SIFT算法详解:SIFT算法详解
SIFT算法译文:SIFT算法译文
下载opencv和opencv_contrib: https://github.com/opencv
opencv3.0+opencv_contrib在Windows上的配置和编译可参考:
https://blog.csdn.net/linshuhe1/article/details/51221015
Note:这里opencv和opencv_contrib的版本要一致,否则后面编译的时候会报错。
二、RANSAC Algorithm
RANSAC(RANdom SAmple Consensus), 随机抽样一致性,它可以从一组包含“局外点”的观测数据,通过迭代的方式训练最优的参数模型,不符合最优参数模型的被定义为“局外点”。
1. RANSAC消除误匹配点可以分为三部分:
(1)根据matches将特征点对齐,将坐标转换为float类型
(2)使用求基础矩阵的方法,findFundamentalMat,得到RansacStatus
(3)根据RansacStatus来删除误匹配点,即RansacStatus[0]=0的点。
2.函数说明
findFundamentalMat()得到基础矩阵,基础矩阵对应三维图像中像点之间的对应关系。
findHomography()得到变换矩阵。
2. 优点与缺点
优点是对模型参数的估计具有鲁棒性,能从具有大量局外点的观测数据中估计出高精度的模型参数,缺点就是迭代次数没有上限,如果设置迭代次数很可能得不到最优的参数模型,甚至得到错误的模型。RANSAC只有一定的概率得到可信模型,迭代次数越大,概率越高,两者成正比。
RANSAC只能从数据集中得到一个模型,如果有多个模型,该算法不能实现。
三. 代码实现与效果
#include
#include
#include
#include
#include
#include
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;//只有加上这句命名空间,SiftFeatureDetector and SiftFeatureExtractor才可以使用
int main()
{
//Create SIFT class pointer
Ptr f2d = xfeatures2d::SIFT::create();
//SiftFeatureDetector siftDetector;
//Loading images
Mat img_1 = imread("101200.jpg");
Mat img_2 = imread("101201.jpg");
if (!img_1.data || !img_2.data)
{
cout << "Reading picture error!" << endl;
return false;
}
//Detect the keypoints
double t0 = getTickCount();//当前滴答数
vector keypoints_1, keypoints_2;
f2d->detect(img_1, keypoints_1);
f2d->detect(img_2, keypoints_2);
cout << "The keypoints number of img1 is:" << keypoints_1.size() << endl;
cout << "The keypoints number of img2 is:" << keypoints_2.size() << endl;
//Calculate descriptors (feature vectors)
Mat descriptors_1, descriptors_2;
f2d->compute(img_1, keypoints_1, descriptors_1);
f2d->compute(img_2, keypoints_2, descriptors_2);
double freq = getTickFrequency();
double tt = ((double)getTickCount() - t0) / freq;
cout << "Extract SIFT Time:" < matches;
matcher.match(descriptors_1, descriptors_2, matches);
cout << "The number of match:" << matches.size()<max_dist)
{
max_dist = matches[m].distance;
}
}
cout << "min dist=" << min_dist << endl;
cout << "max dist=" << max_dist << endl;
//筛选出较好的匹配点
vector goodMatches;
for (int m = 0; m < matches.size(); m++)
{
if (matches[m].distance < 0.6*max_dist)
{
goodMatches.push_back(matches[m]);
}
}
cout << "The number of good matches:" < m_Matches;
m_Matches = goodMatches;
int ptCount = goodMatches.size();
if (ptCount < 100)
{
cout << "Don't find enough match points" << endl;
return 0;
}
//坐标转换为float类型
vector RAN_KP1, RAN_KP2;
//size_t是标准C库中定义的,应为unsigned int,在64位系统中为long unsigned int,在C++中为了适应不同的平台,增加可移植性。
for (size_t i = 0; i < m_Matches.size(); i++)
{
RAN_KP1.push_back(keypoints_1[goodMatches[i].queryIdx]);
RAN_KP2.push_back(keypoints_2[goodMatches[i].trainIdx]);
//RAN_KP1是要存储img01中能与img02匹配的点
//goodMatches存储了这些匹配点对的img01和img02的索引值
}
//坐标变换
vector p01, p02;
for (size_t i = 0; i < m_Matches.size(); i++)
{
p01.push_back(RAN_KP1[i].pt);
p02.push_back(RAN_KP2[i].pt);
}
/*vector img1_corners(4);
img1_corners[0] = Point(0,0);
img1_corners[1] = Point(img_1.cols,0);
img1_corners[2] = Point(img_1.cols, img_1.rows);
img1_corners[3] = Point(0, img_1.rows);
vector img2_corners(4);*/
////求转换矩阵
//Mat m_homography;
//vector m;
//m_homography = findHomography(p01, p02, RANSAC);//寻找匹配图像
//求基础矩阵 Fundamental,3*3的基础矩阵
vector RansacStatus;
Mat Fundamental = findFundamentalMat(p01, p02, RansacStatus, FM_RANSAC);
//重新定义关键点RR_KP和RR_matches来存储新的关键点和基础矩阵,通过RansacStatus来删除误匹配点
vector RR_KP1, RR_KP2;
vector RR_matches;
int index = 0;
for (size_t i = 0; i < m_Matches.size(); i++)
{
if (RansacStatus[i] != 0)
{
RR_KP1.push_back(RAN_KP1[i]);
RR_KP2.push_back(RAN_KP2[i]);
m_Matches[i].queryIdx = index;
m_Matches[i].trainIdx = index;
RR_matches.push_back(m_Matches[i]);
index++;
}
}
cout << "RANSAC后匹配点数" <
运行效果:
完整的工程文件链接:https://download.csdn.net/download/lindamtd/10798831