本博客内容来源于网络以及其他书籍,结合自己学习的心得进行重编辑,因为看了很多文章不便一一标注引用,如图片文字等侵权,请告知删除。
前言
前几天看的东西的数学计算较多,这篇文章讲一下RANSAC,细心地话能在我们前几篇将特征点时,里面有特征点的匹配效果,可以看出来经过RANSAC之后匹配的准确率有很大的提升。RANSAC主要还是一种匹配算法的思想,很简单,而且也很有效,在很多方面都有使用,下面我们看一下。
RANSAC简介
RANSAC(RANdom SAmple Consensus)随机抽样一致算法,是一种在包含离群点在内的数据集里,通过迭代的方式估计模型的参数。举个例子,我们计算单应性矩阵时,初始匹配有很多的误匹配即是一个有离群点的数据集,然后我们估计出单应性矩阵。
RANSAC是一种算法的思路,在计算机视觉中应用较多。它是一种不确定的算法,即有一定的概率得出一个合理的结果,当然也会出现错误的结果。如果要提高概率,一个要提高迭代的次数,在一个就是减少数据集离群点的比例。
RANSAC 在视觉中有很多的应用,比如2D特征点匹配,3D点云匹配,在图片或者点云中识别直线,识别可以参数化的形状。RANSAC还可以用来拟合函数等。
下面我们来看一下RANSAC的具体的思路
RANSAC 思路
RANSAC核心思想就是随机性和假设性,随机性用于减少计算,循环次数是利用正确数据出现的概率。而假设性,就是说随机抽出来的数据都认为是正确的,并以此去计算其他点,获得其他满足变换关系的点,然后利用投票机制,选出获票最多的那一个变换。
可能没看懂,我们来看一下具体的流程:
1、在可以有(也可以没有,主要看应用场景)条件限制(比如选的子集里的点不能过远等)的情况下,随机选取子集,并假设为局内点。子集的大小,主要取决于要拟合模型的复杂度。
2、用局内点拟合一个模型,此模型适应于假设的局内点,所有的未知参数都能从假设的局内点计算得出。
3、 用2中得到的模型去测试整个数据中其他数据,如果某个点适用于估计的模型,认为它也是局内点,将局内点扩充。
4、如果有足够多的点被归类为假设的局内点,那么估计的模型就足够合理。
5、用所有扩充后的局内点去重新估计模型。
6、通过估计局内点与模型的错误率来评估模型。
7、如果当前模型效果比最好模型更好而被选用为最好模型,否则抛弃当前模型。至此完成一个迭代,然后从第1步开始一个新的迭代。
其实我们看完这个流程,其实RANSCA的思路通俗的说,就是在一定的条件下(不是没有限制的随机),去试,试的多了找到正确或者好的可能行就大了。整个思路很朴素,其实通过概率分析,其实他的得到好的结果的计算量,没有你想想的那么大,当然其还是有一定的概率会计算错。
OpenCV RANSAC效果展示[代码]
偷懒直接用了ORB的代码和效果
#include <opencv2/opencv.hpp>
#include <iostream>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/features2d/features2d.hpp>
void extracte_orb(cv::Mat input,std::vector<cv::KeyPoint> &keypoint,cv::Mat &descriptor){
cv::Ptr<cv::ORB> f2d = cv::ORB::create(500);
f2d->detect(input,keypoint);
cv::Mat image_with_kp;
f2d->compute(input,keypoint,descriptor);
cv::drawKeypoints(input, keypoint, image_with_kp, cv::Scalar::all(-1),cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
cv::imwrite("orb"+std::to_string(random())+".png",image_with_kp);
}
void match_two_image(cv::Mat image1,cv::Mat image2, std::vector<cv::KeyPoint> keypoint1,std::vector<cv::KeyPoint> keypoint2,cv::Mat descriptor1,cv::Mat descriptor2){
cv::BFMatcher matcher(cv::NORM_HAMMING);
std::vector<cv::DMatch> matches;
matcher.match(descriptor1,descriptor2, matches);
cv::Mat good_matches_image;
cv::drawMatches(image1, keypoint1, image2, keypoint2,
matches, good_matches_image, cv::Scalar::all(-1), cv::Scalar::all(-1),
std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
cv::imwrite("good_matches_image.png",good_matches_image);
{
std::vector <cv::KeyPoint> RAN_KP1, RAN_KP2;
std::vector<cv::Point2f> keypoints1, keypoints2;
for (int i = 0; i < matches.size(); i++) {
keypoints1.push_back(keypoint1[matches[i].queryIdx].pt);
keypoints2.push_back(keypoint2[matches[i].trainIdx].pt);
RAN_KP1.push_back(keypoint1[matches[i].queryIdx]);
RAN_KP2.push_back(keypoint2[matches[i].trainIdx]);
}
std::vector<uchar> RansacStatus;
cv::findFundamentalMat(keypoints1, keypoints2, RansacStatus, cv::FM_RANSAC);
std::vector <cv::KeyPoint> ransac_keypoints1, ransac_keypoints2;
std::vector <cv::DMatch> ransac_matches;
int index = 0;
for (size_t i = 0; i < matches.size(); i++)
{
if (RansacStatus[i] != 0)
{
ransac_keypoints1.push_back(RAN_KP1[i]);
ransac_keypoints2.push_back(RAN_KP2[i]);
matches[i].queryIdx = index;
matches[i].trainIdx = index;
ransac_matches.push_back(matches[i]);
index++;
}
}
cv::Mat after_ransac_sift_match;
cv::drawMatches(image1, ransac_keypoints1, image2, ransac_keypoints2,
ransac_matches, after_ransac_sift_match, cv::Scalar::all(-1), cv::Scalar::all(-1),
std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
cv::imwrite("after_ransac_orb_match.png",after_ransac_sift_match);
}
}
int main(int argc, char *argv[])
{
cv::Mat image1 = cv::imread(argv[1]);
cv::Mat image2 = cv::imread(argv[2]);
std::vector<cv::KeyPoint> keypoint1,keypoint2;
cv::Mat descriptor1, descriptor2;
extracte_orb(image1,keypoint1,descriptor1);
extracte_orb(image2,keypoint2,descriptor2);
match_two_image(image1,image2,keypoint1,keypoint2,descriptor1,descriptor2);
return 0;
}
初步匹配效果 | ransac后匹配效果 |
---|---|
总结
从上面的结果来看,经过ransac后的效果还会很好的,剔除了很多错误的匹配结果。
RANSAC的优点是它能鲁棒的估计模型参数。例如,它能从包含大量局外点的数据集中估计出较高精度的参数,较少了离群点对模型结果的影响。
RANSAC的缺点是它计算参数的迭代次数没有上限;如果设置迭代次数的上限,得到的结果可能不是最优的结果,甚至可能得到错误的结果。RANSAC只有一定的概率得到可信的模型,概率与迭代次数成正比。RANSAC的另一个缺点是它要求设置跟问题相关的阀值。RANSAC只能从特定的数据集中估计出一个模型,如果存在两个(或多个)模型,RANSAC不能找到别的模型。
虽然缺点不少,但是我还是不能失去他。
重要的事情说三遍:
如果我的文章对您有所帮助,那就点赞加个关注呗 ( * ^ __ ^ * )
如果我的文章对您有所帮助,那就点赞加个关注呗 ( * ^ __ ^ * )
如果我的文章对您有所帮助,那就点赞加个关注呗 ( * ^ __ ^ * )
任何人或团体、机构全部转载或者部分转载、摘录,请保留本博客链接或标注来源。博客地址:开飞机的乔巴
作者简介:开飞机的乔巴(WeChat:zhangzheng-thu),现主要从事机器人抓取视觉系统以及三维重建等3D视觉相关方面,另外对slam以及深度学习技术也颇感兴趣,欢迎加我微信或留言交流相关工作。