OpenCV中特征匹配算法GMS(Grid-based Motion Statistics)原理介绍和使用代码示例
GMS(Grid-based Motion Statistics)算法,是由 Jiawang Bian 等人于 2017 年提出的一种快速、鲁棒的特征匹配过滤算法,全名为:
GMS: Grid-based Motion Statistics for Fast, Ultra-robust Feature Correspondence
该方法的目标是在传统特征匹配的结果上进行鲁棒过滤,显著提高内点比例(inlier ratio),避免使用 RANSAC 等代价高昂的方法。
一、论文背景与创新点
背景
- 在计算机视觉任务中(如 SfM、SLAM、图像拼接),特征匹配是关键步骤;
- 传统匹配器(如 ORB + BFMatcher)容易产生大量误匹配;
- 为了鲁棒性,通常使用 RANSAC 等几何模型估计器进行剔除,但计算代价较高。
创新点
二、算法整体框架
整个 GMS 过程可视为两阶段:
第一阶段:快速构建初始匹配点对(如 ORB + BFMatcher)
第二阶段:基于局部运动一致性的网格过滤策略进行匹配剔除
三、算法原理与步骤详解
1. 特征提取与初始匹配
- 任意特征点提取器(如 ORB、AKAZE、SIFT)
- 使用暴力匹配(BFMatcher)或 KD-Tree 得到初始
N
个匹配点对 ( p i , q i ) (p_i, q_i) (pi,qi)
该阶段不涉及 GMS,仅作为输入。
2. 构建图像网格(Grid)
-
将图像划分为 G × G G \\times G G×G 网格(例如 20×20)
-
对每个匹配点对,将其两个端点分别落入图像 1 和图像 2 的网格中:
- ( p i ∈ Grid k ) , ( q i ∈ Grid l ) (p_i \\in \\text{Grid}_{k}), (q_i \\in \\text{Grid}_{l}) (pi∈Gridk),(qi∈Gridl)
核心思想:如果匹配是正确的,那么在某一网格及其邻域中,源图像与目标图像网格间应该存在较多的一致映射。
3. 局部一致性统计(Motion Kernel)
对每个网格单元格 Grid k \\text{Grid}_k Gridk,统计其到目标图像所有匹配方向的投票数:
- 以网格 Grid k \\text{Grid}_k Gridk 的匹配点为中心;
- 将其对应目标图像网格的映射方向用作运动向量;
- 如果某方向得票最多且超过阈值(比如 >6),则认为该网格内的该方向为主运动。
GMS 就是利用这个局部“投票原则”来判断哪些匹配可信,哪些不是。
4. 多尺度与多旋转支持(增强 GMS)
由于真实场景中存在视角/尺度变化,GMS 原算法提供扩展:
多尺度 GMS(Scale-aware GMS)
- 使用金字塔图像分别构建匹配;
- 尝试多组网格尺寸(例如 G = 20, 40, 60…);
- 每层做一遍 GMS,合并最终内点。
多旋转 GMS(Rotation-aware GMS)
- 对目标图像旋转多个角度(通常是 8 个方向,如 0°, 45°, 90°…);
- 在每个旋转版本上执行一次 GMS;
- 得到最佳匹配组合。
这两项扩展显著增强了 GMS 的旋转 & 尺度不变性。
四、关键技术点总结
五、优点总结
六、不足与局限性
七、论文与资源链接
- 论文地址:https://arxiv.org/abs/1701.08396
- GitHub 示例(C++):https://github.com/JiawangBian/GMS-Feature-Matcher
- OpenCV 实现:位于
opencv_contrib/modules/xfeatures2d/src/matching.cpp
八、可选改进方向建议
九、 OpenCV中使用示例
在 OpenCV 中,GMS(Grid-based Motion Statistics)特征匹配功能位于 xfeatures2d
模块(contrib 扩展),提供了一个极简接口用于从粗匹配中快速剔除误匹配。
9.1、函数接口说明:cv::xfeatures2d::matchGMS
namespace cv {namespace xfeatures2d {/** * @brief Performs GMS (Grid-based Motion Statistics) feature matching filtering * * @param size1 size of the first image * @param size2 size of the second image * @param keypoints1 keypoints from image1 * @param keypoints2 keypoints from image2 * @param matches1to2 initial matches (e.g., from BFMatcher) * @param matchesGMS output: filtered matches after GMS * @param withRotation enable rotation-invariant GMS (default: false) * @param withScale enable scale-invariant GMS (default: false) * @param thresholdFactor threshold for motion consistency (default: 6.0) */void matchGMS( const Size& size1, const Size& size2, const std::vector<KeyPoint>& keypoints1, const std::vector<KeyPoint>& keypoints2, const std::vector<DMatch>& matches1to2, std::vector<DMatch>& matchesGMS, bool withRotation = false, bool withScale = false, double thresholdFactor = 6.0);}} // namespace cv::xfeatures2d
参数详解
size1
/ size2
cv::Size
keypoints1
/ keypoints2
std::vector
matches1to2
matchesGMS
withRotation
bool
withScale
bool
thresholdFactor
double
9.2、使用代码示例
以下代码展示如何用 ORB 提取特征,然后用 GMS 过滤匹配:
#include #include #include int main(){ cv::Mat img1 = cv::imread(\"img1.jpg\", cv::IMREAD_GRAYSCALE); cv::Mat img2 = cv::imread(\"img2.jpg\", cv::IMREAD_GRAYSCALE); if (img1.empty() || img2.empty()) { std::cerr << \"Image loading failed!\" << std::endl; return -1; } // 1. 特征提取 auto orb = cv::ORB::create(1000); std::vector<cv::KeyPoint> kp1, kp2; cv::Mat desc1, desc2; orb->detectAndCompute(img1, cv::noArray(), kp1, desc1); orb->detectAndCompute(img2, cv::noArray(), kp2, desc2); // 2. 初始匹配(暴力匹配器) std::vector<cv::DMatch> matches_all; cv::BFMatcher matcher(cv::NORM_HAMMING); matcher.match(desc1, desc2, matches_all); // 3. GMS 过滤 std::vector<cv::DMatch> matches_gms; bool withRotation = true; bool withScale = true; double threshold = 6.0; cv::xfeatures2d::matchGMS( img1.size(), img2.size(), kp1, kp2, matches_all, matches_gms, withRotation, withScale, threshold ); std::cout << \"Initial Matches: \" << matches_all.size() << std::endl; std::cout << \"GMS Matches: \" << matches_gms.size() << std::endl; // 4. 可视化 cv::Mat img_matches; cv::drawMatches(img1, kp1, img2, kp2, matches_gms, img_matches); cv::imshow(\"GMS Filtered Matches\", img_matches); cv::waitKey(0); return 0;}
9.3、匹配结果示意图
匹配点通常可视化如下:
cv::drawMatches(img1, kp1, img2, kp2, matches_gms, img_matches);cv::imshow(\"GMS Matches\", img_matches);
可视化会看到原始匹配很多错误点,而 GMS 匹配线更加集中与正确区域。
9.4、实际应用建议
北京人才网招聘求职