随机抽样一致算法(RANdom SAmple Consensus),简称RANSAC算法 ,采用迭代的方式从一组包含离群的被观测数据中估算出数学模型的参数。其广泛应用在计算机视觉领域和数学领域,例如直线拟合、平面拟合、计算图像或点云间的变换矩阵、计算基础矩阵等方面。
RANSAC算法基本思想:
从数据集中随机选出一组局内点(其数目要保证能够求解出模型的所有参数),计算出一套模型参数。
用得到的模型去测试其他所有的数据点,如果某点的误差在设定的误差阈值之内,就判定其为局内点,否则为局外点,只保留目前为止局内点数目最多的模型,将其记录为最佳模型。
重复执行1,2步足够的次数(即达到预设的迭代次数)后,使用最佳模型对应的局内点来最终求解模型参数。
最后可以通过估计局内点与模型的错误率来评估模型。
为了更好的理解我们举个栗子:
首先随机取两个点,计算直线模型,根据设定的误差阈值判断局内点和局外点。
如果想要对RANSAC算法有更多了解请参见维基百科。
这里我们用RANSAC算法实现对特征点匹配的优化。
#include
#include "opencv2/opencv.hpp"
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
//读取图片
Mat img_1 = imread("1.png");
Mat img_2 = imread("2.png");
if (img_1.empty() || img_2.empty())
{
cout << "Can't open the picture!\n";
return 0;
}
vector img_1_keypoints, img_2_keypoints;
Mat img_1_descriptors, img_2_descriptors;
Ptr detector=ORB::create(); //采用ORB算法提取特征点
//检测FAST角点位置
detector->detect(img_1, img_1_keypoints);
detector->detect(img_2, img_2_keypoints);
//根据角点位置计算BRIEF描述子
detector->compute(img_1, img_1_keypoints, img_1_descriptors);
detector->compute(img_2, img_2_keypoints, img_2_descriptors);
//汉明距离做为相似度度量
BFMatcher matcher(NORM_HAMMING, true);
vector matches;
matcher.match(img_1_descriptors, img_2_descriptors, matches);
Mat match_img;
drawMatches(img_1, img_1_keypoints, img_2, img_2_keypoints, matches, match_img);
imshow("所有匹配", match_img);
//采用RANSAC算法优化
//保存匹配对序号
vector<int> queryIdxs(matches.size()), trainIdxs(matches.size());
for (size_t i = 0; i < matches.size(); i++)
{
queryIdxs[i] = matches[i].queryIdx;
trainIdxs[i] = matches[i].trainIdx;
}
Mat homography_matrix; //变换矩阵
vector points1; KeyPoint::convert(img_1_keypoints, points1, queryIdxs);
vector points2; KeyPoint::convert(img_2_keypoints, points2, trainIdxs);
int ransacReprojThreshold = 5; //拒绝阈值
homography_matrix = findHomography(Mat(points1), Mat(points2), CV_RANSAC, ransacReprojThreshold);
vector<char> matchesMask(matches.size(), 0);
Mat points1t;
perspectiveTransform(Mat(points1), points1t, homography_matrix);
for (size_t i = 0; i < points1.size(); i++) //保存‘局内点’
{
if (norm(points2[i] - points1t.at((int)i, 0)) <= ransacReprojThreshold) //给局内点做标记
{
matchesMask[i] = 1;
}
}
Mat match_img2; //滤除‘局外点’后
drawMatches(img_1, img_1_keypoints, img_2, img_2_keypoints, matches, match_img2, Scalar(0, 0, 255), Scalar::all(-1), matchesMask);
imshow("优化后的匹配", match_img2);
waitKey(0);
return 0;
}
这里在openCV的findHomography函数中使用RANSAC来优化。在VS上面运行结果如下:
特征点匹配的还可以按照汉明距离小于最小汉明距离两倍的筛选原则优化。