1.RANSAC算法介绍
RANSAC是一种常用的参数估计方法,全称为Random Sample Consensus(随机抽样一致性)。它的主要思想是通过随机选择一部分数据样本,构建模型并评估其拟合程度,迭代过程中逐步优化模型,最终得到一个拟合较好的模型。
其基本流程如下:
- 随机取样,计算规律(特征点匹配中计算单应矩阵)
- 测试规律是否满足大多数数据
- 循环前两步
- 选取最佳规律,并输出满足数据的点
2.RANSAC优化特征点匹配结果的函数findHomography()
Mat cv::findHomography ( InputArray srcPoints,
InputArray dstPoints,
int method = 0,
double ransacReprojThreshold =3,
OutputArray mask = noArray(),
const intmaxlters = 2000,
const double confidence = 0.995
)
- SrcPoints:原始图像中特征点的坐标
- dstPoints:目标图像中特征点的坐标
- method:计算单应矩阵方法的标志
- ransacReprojThreshold; 重投影的最大误差
- mask:掩码矩阵,使用RANSAC算法时表示满足单应矩阵的特征点
- maxIters:RANSAC算法迭代的最大次数
- confidence:置信区间,取值范围0-1
3.示例代码
void orb_fearures(Mat &gray,vector<KeyPoint> &keypoints,Mat &descriptions){
Ptr<ORB> orb=ORB::create(1000,1.2f);
orb->detect(gray,keypoints);
orb->compute(gray,keypoints,descriptions);
}
//RANSAC算法实现
void ransac(vector<DMatch> matches,vector<KeyPoint> queryKeyPoint,vector<KeyPoint> trainKeyPoint,vector<DMatch> &matches_ransac){
//定义保存匹配点对坐标
vector<Point2f> srcPoints(matches.size()),dstPoints(matches.size());
//保存从关键点中提取到的匹配点对坐标
for(int i=0;i<matches.size();i++){
srcPoints[i]=queryKeyPoint[matches[i].queryIdx].pt;
dstPoints[i]=trainKeyPoint[matches[i].trainIdx].pt;
}
//匹配点对进行RANSAC过滤
vector<int> inliersMask(srcPoints.size());
findHomography(srcPoints,dstPoints,RANSAC,5,inliersMask);
//手动的保留RANSAC过滤的匹配点对
for(int i=0;i<inliersMask.size();i++){
if(inliersMask[i]){
matches_ransac.push_back(matches[i]);
}
}
}
void Ransac_f(Mat img1,Mat img2){
//提取特征点
vector<KeyPoint> keypoints1,keypoints2;
Mat descriptions1,descriptions2;
//计算特征点
orb_fearures(img1,keypoints1,descriptions1);
orb_fearures(img2,keypoints2,descriptions2);
//特征点匹配
vector<DMatch> matches;//定义存放匹配结果的变量
BFMatcher matcher(NORM_HAMMING);//定义特征点匹配的类,使用汉明距离
matcher.match(descriptions1,descriptions2,matches);//进行特征点匹配
ostringstream ss;
ss<<"matches="<<matches.size()<<endl;//匹配成功特征点数目
//通过汉明距离删选匹配结果
double min_dist=1000,max_dist=0;
for(int i=0;i<matches.size();i++){
double dist=matches[i].distance;
if(dist<min_dist) min_dist=dist;
if(dist>max_dist) max_dist=dist;
}
//输出所有匹配结果中最大韩明距离和最小汉明距离
ss<<"min_dist="<<min_dist<<endl;
ss<<"max_dist="<<max_dist<<endl;
//将汉明距离较大的匹配点对删除
vector<DMatch> good_matches;
for(int i=0;i<matches.size();i++){
if(matches[i].distance<=max(2*min_dist,20.0)){
good_matches.push_back(matches[i]);
}
}
ss<<"good_min="<<good_matches.size()<<endl;//剩余特征点数目
LOGD("%s",ss.str().c_str());
//用ransac算法筛选匹配结果
vector<DMatch> good_ransac;
ransac(good_matches,keypoints1,keypoints2,good_ransac);
//绘制匹配结果
Mat outimg2;
drawMatches(img1,keypoints1,img2,keypoints2,good_ransac,outimg2);
//显示结果
imwrite("/sdcard/DCIM/outimg2.png",outimg2);//ransac筛选
}
ransac筛选结果: