|
有时候即使使用了描述子距离作为约束优化匹配的特征点,也会有部分误匹配。即使提高阈值约束条件能去除误匹配点,但同时正确的匹配点的特征也会随之减少。在实际情况中,我们也不可能反复调整阈值以获得更好的匹配结果。
为了更好的提高特征点匹配精度,我们可以采用RANSAC算法。RANSAC算法是随机抽样一致算法(RANdom SAmple Consensus)的缩写,该算法假设所有数据符合一定的规律,通过随机抽样的方式获取这个规律,并且通过重复获取规律寻找使得较多数据符合规的规律。RANSAC算法之所以能应用在特征点匹配中,是因为两种图像的变换为单应矩阵所对应的变换规律。但应矩阵可以由4个对应点得到单应矩阵,而图像中所有对应点都符合这个单应矩阵所对应的变换规律,因此可以使用RANSAC算法进行特征点匹配的优化。利用RANSAC算法优化特征点匹配可以概括为以下3个步骤。
第一步:在匹配结果中随机选取4对特征点,计算单应矩阵。
第二步:将第一帧图像中的特征点根据单应矩阵求取在第二帧图像中的重投影坐标,比较重投影坐标与已匹配的特征点坐标之间的距离,如果小于一定的阈值,那么认为是正确匹配点对,否则被认为错误匹配,并记录正确点对的数量。
第三步:重复第一步和第二步,比较多次循环后的统计正确匹配点对的数量,将正确匹配的点对数量最多的情况视为最终结果,剔除错误匹配,输出正确匹配对,从而实现特征点匹配的筛选。
Mat cv::findHomography(InputArray srcPoints,//原始图像中特征点的坐标
InputArray dstPoints,//目标图像中的特征点的坐标
int method=0,//计算单应矩阵方法的标志,可以选择的方法在下表
double ransacReprojThreshold=3,//重投影的最大误差
OutputArray mask=noArray(),//掩码矩阵,使用RANSAC算法时表示满足单应矩阵的特征点
const int maxIters=2000,//RANSAC算法迭代的最大次数
const double confindence=0.995//置信区间,取值范围为0~1) 该函数主要用于计算两幅图像的单应矩阵,但是利用RANSAC算法计算单应矩阵的同时可以计算满足单应矩阵的特征点对,因此可以用来优化特征点匹配。该函数的前两个参数分别是两幅图像中特征点的坐标,坐标存放在CV_32FC2的矩阵或者vector<Point2f>向量中。该函数的第三个参数是计算单应矩阵的算法标志。该函数的第四个参数是重投影的最大误差,该函数只在第三个参数选择RANSAC和RHO时有用,参数默认值为3.该函数的第五个参数是掩码矩阵,在使用RANSAC算法时输出结果表示是否满足单应矩阵重投影误差的特征点,用非零元素表示满足重投影误差。该函数的第六个参数是RANSAC算法迭代的最大次数,参数默认值为3000.该函数的最后一个参数是算法置信区间,取值范围在0~1之间,默认是0.995.
findHomography()函数计算单应矩阵的方法标志
方法标志 | 含义 | 0 | 使用最小二乘方法计算单应矩阵 | RANSAC | 使用RANSAC方法计算单应矩阵 | LMEDS | 使用最小中值方法计算单应矩阵 | RHO | 使用PROSAC方法计算单应矩阵 | 通过该函数优化匹配的特征点,需要判断输出的掩码矩阵中每一个元素是否为0,如果不为0,那么表示该点是成功匹配的特征点,进而在vector<DMatch>里寻找与之匹配的特征点,将匹配结果放在新的存放DMatch类型的向量中。为了了解RANSAC算法优化特征点匹配的实现过程,以下代码给出了利用RANSAC算法优化ORB特征点匹配的示例程序。在该过程中,首先用最小汉明距离对所有特征点匹配结果进行初步筛选,之后将所有通过筛选的特征点对用findHomography()函数进行筛选,该函数的第三个参数需要选择RANSAC,然后将所有正确匹配结果保存起来,最后绘制优化后的特征点匹配结果。
#include<iostream>
#include<opencv2\opencv.hpp>
#include<vector>
using namespace std;
using namespace cv;
void match_min(vector<DMatch> matches, vector<DMatch>&good_matches) {
double min_dist = 10000, max_dist = 0;
for (int i = 0; i < matches.size(); i++) {
double dist = matches.distance;
if (dist < min_dist) min_dist = dist;
if (dist > max_dist) max_dist = dist;
}
cout << &#34;min_dist=&#34; << min_dist << endl;
cout << &#34;max_dist=&#34; << max_dist << endl;
for (int i = 0; i < matches.size(); i++) {
if (matches.distance <= max(2 * min_dist, 20.0))
good_matches.push_back(matches);
}
}
//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 = queryKeyPoint[matches.queryIdx].pt;
dstPoints = trainKeyPoint[matches.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)
matches_ransac.push_back(matches);
}
void orb_features(Mat &gray, vector<KeyPoint>&keypoints, Mat &descriptions) {
Ptr<ORB>orb = ORB::create(1000, 1.2f);
orb->detect(gray, keypoints);
orb->compute(gray, keypoints, descriptions);
}
int main() {
Mat img1 = imread(&#34;D:/样本/12.png&#34;);
Mat img2 = imread(&#34;D:/样本/14.png&#34;);
if (!(img1.data&& img2.data)) {
cout << &#34;读取图像错误,请确认图像文件是否正确&#34; << endl;
return -1;
}
//提取ORB特征点
vector <KeyPoint>Keypoints1, Keypoints2;
Mat descriptions1, descriptions2;
//基于区域分割的ORB特征点提取
orb_features(img1, Keypoints1, descriptions1);
orb_features(img2, Keypoints2, descriptions2);
//特征点匹配
vector<DMatch>matches, good_min, good_ransac;
BFMatcher matcher(NORM_HAMMING);
matcher.match(descriptions1, descriptions2, matches);
cout << &#34;matches=&#34; << matches.size() << endl;
//最小汉明距离
match_min(matches, good_min);
cout << &#34;good_min=&#34; << good_min.size() << endl;
//用RANSAC算法筛选匹配结果
ransac(good_min, Keypoints1, Keypoints2, good_ransac);
cout << &#34;good_matches.size=&#34; << good_ransac.size() << endl;
//绘制结果图
Mat outimg, outimg1, outimg2;
drawMatches(img1, Keypoints1, img2, Keypoints2, matches, outimg);
drawMatches(img1, Keypoints1, img2, Keypoints2, good_min, outimg1);
drawMatches(img1, Keypoints1, img2, Keypoints2, good_ransac, outimg2);
imshow(&#34;未筛选结果&#34;, outimg);
imshow(&#34;最小汉明距离筛选&#34;, outimg1);
imshow(&#34;RANSAC筛选&#34;, outimg2);
waitKey(0);
return 0;
} |
|