Random sample consensus (RANSAC),即随机抽样一致性,其是一种用于估计模型参数的迭代方法,特别适用于处理包含离群点(outliers)的数据集
RANSAC 的主要思想是随机采样数据点,用这些采样点拟合一个模型,然后计算其他数据点到这个模型的拟合误差;根据误差和阈值,将数据点分为内点(inliers)和外点(outliers);重复这个过程多次,选择具有最多内点的模型作为最终的估计
大致步骤为:
随机采样
从数据集中随机选择一小部分数据点,通常是与所估计模型参数数量相等的数据点
模型拟合
使用这些随机采样的数据点拟合一个模型,例如直线
内点检测
计算所有数据点到模型的拟合误差,并将与模型拟合误差小于某个阈值的数据点标记为内点
判断是否满足条件
如果内点的数量达到了某个设定的阈值,且模型参数的估计是合理的(例如,模型的拟合误差小于一定阈值),则认为找到了一个满足条件的模型
重复迭代
重复上述过程多次(通常几百甚至上千次),并且记录具有最多内点的模型,以及该模型估计的内点
输出最佳模型
在所有迭代中,选择具有最多内点的模型作为最终的估计模型。这些内点被认为是满足模型的数据点
RANSAC 的一个优点是它能够对模型参数进行鲁棒估计,能够在存在大量噪声的情况下找到合适的模
RANSAC 的缺点是计算这些参数所需的时间没有上限,其需要进行大量的随机采样和模型拟合,因此对于大规模数据集来说,计算复杂度较高,可能需要较长的时间来运行
请见 3 实践操作 步骤二
基本矩阵(Fundamental Matrix)描述了两个摄像机之间的基本几何关系
在对极几何中,对于立体图像对中对应点的齐次图像坐标 p1
和 p2
, F*p1
描述了另一图像上的对应点 p2
必须位于其上的线(对极线)这意味着,对于所有对应点对都成立:
p
2
T
∗
F
∗
p
1
=
0
p_2^T * F * p_1 = 0
p2T∗F∗p1=0
在 OpenCV 中,提供了 findFundamentalMat
函数,用于估计两幅图像之间的F矩阵
以下是 findFundamentalMat
函数的基本用法:
Mat fundamental_matrix = findFundamentalMat(points1, points2, mask, method, ransacReprojThreshold, confidence);
其中各参数的含义如下:
points1
和 points2
:两幅图像中的匹配点坐标,通常是 vector
类型,表示两幅图像中匹配点的像素坐标mask
:是一个输出数组通常是 vector
类型,用于指示哪些匹配点被视为内点(inliers)和哪些被视为外点(outliers)method
:用于指定计算基本矩阵的方法,可以是以下几种选项之一:
cv::FM_RANSAC
:使用 RANSAC 算法进行估计,用于排除离群点cv::FM_LMEDS
:使用最小中值误差估计方法cv::FM_8POINT
:使用 8 点法估计基本矩阵ransacReprojThreshold
:RANSAC 算法中的重投影误差阈值,用于判断内点和外点,通常需要根据具体问题来选择适当的阈值,默认值为 3.0confidence
:置信度,通常为默认值 0.99之前通过SIFT
+Flann
+ratio=0.7
的图像匹配和初步筛选,得到了 good_matches
(vector
类型)
将 vector
类型的 good_matches
中的坐标信息提取出来存入 vector
类型的 matchedPoints1/2
;以便于后续的几何计算将匹配点对的坐标提取出来,以便于后续的几何计算
// 声明用于保存匹配点对的容器
vector<Point2f> matchedPoints1, matchedPoints2;
for (int i = 0; i < good_matches.size(); ++i)
{
matchedPoints1.push_back(keypoints1[good_matches[i].queryIdx].pt);
matchedPoints2.push_back(keypoints2[good_matches[i].trainIdx].pt);
}
直接使用 findFundamentalMat
函数
这个函数在内部已经包含了 RANSAC 筛选步骤;具体来说,findFundamentalMat
函数会计算基本矩阵 F,同时使用 RANSAC 迭代方法来排除离群点,确保得到的基本矩阵对于图像匹配是稳健的
// 使用RANSAC进行基本矩阵F的估计
Mat F;
vector<uchar> inliers;
F = findFundamentalMat(matchedPoints1, matchedPoints2, inliers, RANSAC);
为了查看 RANSAC 筛选的效果我们进行如下操作
inliers
是一个二进制向量,指示哪些匹配点对被视为内点(符合基本矩阵约束),哪些被视为外点;我们接下来使用内点来进一步筛选匹配,只保留通过 RANSAC 筛选的匹配对在ransac_filtered_matches
中,并打印出来
// 进一步筛选匹配
vector<DMatch> ransac_filtered_matches;
for (int i = 0; i < inliers.size(); ++i)
{
if (inliers[i])
{
ransac_filtered_matches.push_back(good_matches[i]);
}
}
// ransac_filtered_matches 包含了通过RANSAC筛选后的匹配对
Mat ransac_filtered_img_matches;
drawMatches(img1, keypoints1, img2, keypoints2, ransac_filtered_matches, ransac_filtered_img_matches);
imwrite(SAVE_PATH, ransac_filtered_img_matches);
匹配点数量 | 图像效果 | |
---|---|---|
RANSAC 筛选前 | 2949 | |
RANSAC 筛选后 | 2581 |
可以明显看出,在 RANSAC 筛选后,消除了 368
对离群匹配,达到了非常好的匹配效果