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