opencv中SIFT匹配对于误匹配点RANSAC算法接口的使用
小白一名,在测试opencv自带的SIFT特征点检测的过程中,发现在不设定create的SIFT探测器的参数或者设定的模糊系数较大的时候(未规定指定生成数目),一般会生成巨多的特征点,即使是有另一张图像进行匹配操作,最后得到的匹配对依旧是数量不少(大概对于一张几十k的图,可以生成上百甚至数百个特征点对),更加让人郁闷的是,最后生成的特征点对还不是十分的准确,甚至在一张图像特有的区域,明明另一张图像没有显示出来,却被在显示区域找了一个特征点就这么连接了起来。最后的匹配结果可想而知,看下面这张匹配的杂乱无章的图:
虽然对于一些关键特征点匹配的还是蛮准确,不过有的匹配就略显莫名其妙的。
看来,如果不对这些特征点好好甄别一下,对于匹配操作优化一下,这些匹配信息根本不好用啊。看了一下opencv官网,找到了一个函数findHomography(),opencv是通过调用这个函数来实现RANSAC算法功能的,而RANSAC算法在我的理解就是从找到的匹配点中,随机找四个不共线点的样本,生成一个函数模型,然后将所有其他点带入,根据阈值判断,满足条件则判为内点,以此形式迭代k次,获取到k次迭代生成的内点值最多的情况,并以此得到的模型来模拟变换矩阵。
具体的如何将RANSAC算法整合入opencv并提供findHomography()接口,是一个繁杂的过程,感兴趣的同学可以看一下这篇博文,其对于每一个涉及的类和成员函数,讲解的十分明白:OpenCV中的RANSAC详解
这里附带下我写的改进处理代码:
//使用RANSAC算法筛选匹配点,滤掉错误匹配点
vector<Point2f>pic1KeyToP2f;
vector<Point2f>pic2KeyToP2f;
for (int i = 0; i < matches.size(); i++)
{
//DMatch主要用来储存匹配信息的结构体,query是要匹配的描述子,train是被匹配的描述子,在Opencv中进行匹配时
//queryIdx为query描述子的索引,match函数中前面的那个描述子
//trainIdx为train描述子的索引,match函数中后面的那个描述子
//KeyPoint参数pt代表关键点坐标
pic1KeyToP2f.push_back(keypointsa1[matches[i].queryIdx].pt);
pic2KeyToP2f.push_back(keypointsa2[matches[i].trainIdx].pt);
}
vector<unsigned char>tempmat(pic1KeyToP2f.size());//标记
//CV_Error(Error::StsBadArg, "The input arrays should be 2D or 3D point sets")
//findHomography()对应的一二参数不可以为Mat类型,否则会报错
//则需要进行类型转换将keyPoint类型的坐标位置传给Point2f类型
Mat transM = findHomography(pic1KeyToP2f, pic2KeyToP2f, CV_FM_RANSAC, 3,tempmat, 100);
cout << "变换矩阵为:" << endl;
cout << transM<<endl;//输出变换矩阵
vector<DMatch>optimizeM;
for (int j = 0; j<tempmat.size(); j++)
{
if (tempmat[j])
optimizeM.push_back(matches[j]);
}
cout << "处理前匹配对数:" << matches.size() << endl;//输出处理前和处理后的匹配对数
matches.swap(optimizeM);
cout << "处理后匹配对数:" << matches.size() << endl;
Mat optimizeP;
drawMatches(src1, keypointsa1, src2, keypointsa2, matches, optimizeP);
imshow("output4", optimizeP);
这里是经过处理之后的效果图:
生成的变换矩阵,处理前匹配点数,处理后匹配点数如下:
发现经过处理之后的匹配结果,虽然依旧会有一点点微小的出入,但是匹配的精度却极大地提高了,这也为以后的图像拼接程序,打下了良好的基础。