1、SURF简介
Speeded Up Robust Features(SURF,加速稳健特征),是一种稳健的局部特征点检测和描述算法。最初由Herbert Bay发表在2006年的欧洲计算机视觉国际会议(Europen Conference on Computer Vision,ECCV)上,并在2008年正式发表在Computer Vision and Image Understanding期刊上。
Surf是对David Lowe在1999年提出的Sift算法的改进,提升了算法的执行效率,为算法在实时计算机视觉系统中应用提供了可能。与Sift算法一样,Surf算法的基本路程可以分为三大部分:局部特征点的提取、特征点的描述、特征点的匹配。
2、SURF匹配代码
// 读入你所要匹配的图片
Mat image1 = imread("D:/test2-1.jpg", 0);
Mat image2 = imread("D:/test2-2.jpg", 0);
if (!image1.data || !image2.data)
return 0;
// 声明两个vector变量存放两张图的关键点
vector<KeyPoint> keypoints1;
vector<KeyPoint> keypoints2;
// 声明一个SURF特征检测器
Ptr<SurfFeatureDetector> surf = SurfFeatureDetector::create(3000);
// 检测 SURF 特征关键点
surf->detect(image1, keypoints1);
surf->detect(image2, keypoints2);
if (keypoints1.size() == 0 || keypoints2.size() == 0) {
return -1;
} else {
cout << "Number of SURF points (1): " << keypoints1.size() << endl;
cout << "Number of SURF points (2): " << keypoints2.size() << endl;
}
// 声明一个SURF特征点描述子抽取器
Ptr<SURF> surfDesc = SURF::create();
// 抽取特征点描述子(以向量矩阵形式存入Mat中,用于匹配两特征点是否相似)
Mat descriptors1, descriptors2;
surfDesc->compute(image1, keypoints1, descriptors1);
surfDesc->compute(image2, keypoints2, descriptors2);
// 声明一个匹配器
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce");
// 匹配两图描述子(也即看特征向量像不像)
vector<cv::DMatch> matches;
matcher->match(descriptors1, descriptors2, matches);
// 采用RANSAC计算单应矩阵,然后通过单应矩阵提纯得到好的特征点
vector<Point2f> object;
vector<Point2f> scene;
for (size_t i = 0; i < matches.size(); i++)
{
//从好的匹配中获取关键点: 匹配关系是两组关键点间具有的一一对应关系,可以根据此匹配关系获得关键点的索引
//这里的goodMatches[i].queryIdx和goodMatches[i].trainIdx是匹配中一对关键点的索引
object.push_back(keypoints1[matches[i].queryIdx].pt);
scene.push_back(keypoints2[matches[i].trainIdx].pt);
}
Mat H;
float reprojectionThreshold = 3;
vector<DMatch> inliers;
vector<unsigned char> inliersMask(object.size());
H = findHomography(object, scene, CV_RANSAC, reprojectionThreshold, inliersMask);
for (size_t i = 0; i < inliersMask.size(); i++)
{
if (inliersMask[i])
inliers.push_back(matches[i]);
}
matches.swap(inliers);
其中,findHomography()我们单独拿出来解析,这个函数的参数中:
- object和scene是好点在两张图中分别的坐标集合,且他们是一一对应的,其中既有正确的匹配,也有错误的匹配,正确的称为内点,错误的称为外点,RANSAC方法就是从这些包含错误匹配的数据中,分离出正确的匹配,并且求得单应矩阵(H就是我们要求的单应矩阵)。
- reprojThreshold为阈值,当某一个匹配小于阈值时,则被认为是一个内点。
- inliersMask即为掩膜,它的长度和object、scene一样长,当一个object和scene中的点为内点时,inliersMask的相应位置标记为1,反之为0,说白了,通过inliersMask我们最终可以知道序列中哪些是内点,哪些是外点。
匹配效果示例:
目标检测示例图
后期我会将完整代码上传github,欢迎关注,github地址:https://github.com/JunJieDing666