OpenCV中特征匹配算法GMS(Grid-based Motion Statistics)原理介绍和使用代码示例

发布于:2025-07-22 ⋅ 阅读:(13) ⋅ 点赞:(0)

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 等几何模型估计器进行剔除,但计算代价较高

创新点

编号 创新内容
1 提出基于网格的一致性统计(GMS),利用特征分布的局部空间一致性代替代价昂贵的几何模型拟合
2 完全无需几何模型(如单应性、基础矩阵等),仅用点对分布统计即可剔除误匹配
3 支持尺度和旋转不变性扩展(Multi-scale + Multi-orientation)
4 可实时处理(30+ fps),适合嵌入式系统和大规模特征任务

二、算法整体框架

整个 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}) (piGridk),(qiGridl)

核心思想:如果匹配是正确的,那么在某一网格及其邻域中,源图像与目标图像网格间应该存在较多的一致映射。


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 的旋转 & 尺度不变性。


四、关键技术点总结

技术点 描述
网格划分策略 可调网格数(G=20~40),用于投票统计
运动核检测 判断局部运动方向是否一致,以此投票过滤匹配
匹配投票阈值 通常设为 6,表示区域内要有足够匹配一致性
支持邻域 默认 3x3 邻域一致性统计(更鲁棒)
Multi-scale + Multi-rotation 增强匹配在实际变换场景下的稳定性

五、优点总结

优点 说明
快速 无需几何模型拟合,纯粹使用空间投票
鲁棒 在重复纹理、仿射变换等下仍有效
无描述子依赖 可用于任意描述子的匹配结果过滤
易部署 可直接用于特征匹配前端、VIO、图像配准等系统
实时性 在 CPU 上可轻松 30~60 FPS 运行(上千点匹配)

六、不足与局限性

不足 说明
无全局几何检验 无法判断匹配是否符合某个几何模型(如单应、基础矩阵)
对遮挡/大量错配无显式建模 多目标运动场景下存在误判风险
网格尺度敏感 网格大小选择影响性能(需调参)
对特征分布密度敏感 稀疏特征场景下效果下降

七、论文与资源链接


八、可选改进方向建议

方向 描述
融合 GMS 与 F matrix 单应性验证 提升鲁棒性
用 CNN 替代手工网格统计 GMS with learned kernels
利用 GMS 初步过滤,再进行局部几何估计(如 E matrix) 应用于 VO/VIO

九、 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<cv::KeyPoint> 特征点列表
matches1to2 初始匹配点对 通常来自 ORB/SIFT + BFMatcher
matchesGMS 输出 GMS 过滤后的匹配结果
withRotation bool 是否启用旋转不变性
withScale bool 是否启用尺度不变性
thresholdFactor double 投票一致性阈值(建议为 6.0)

9.2、使用代码示例

以下代码展示如何用 ORB 提取特征,然后用 GMS 过滤匹配:

#include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <iostream>

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、实际应用建议

场景 是否推荐使用 GMS
图像拼接 强烈推荐
SLAM 前端 可大幅减少误匹配输入
目标跟踪 可提升匹配精度
小视差图像对齐 特别有效
多目标匹配 无法分辨多目标,建议配合几何验证(如单应矩阵)


网站公告

今日签到

点亮在社区的每一天
去签到