问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

OpenCV C++ SIFT 特征匹配

创作时间:
作者:
@小白创作中心

OpenCV C++ SIFT 特征匹配

引用
CSDN
1.
https://m.blog.csdn.net/m0_73782904/article/details/137087080

SIFT(尺度不变特征变换)是一种在计算机视觉领域中广泛应用的特征检测和描述算法。它能够检测图像中的局部特征,并对这些特征进行描述,使得在图像旋转、尺度变化、亮度变化等情况下仍能保持较好的检测效果。本文将通过一个具体的代码示例,详细介绍如何使用OpenCV库中的SIFT算法进行特征匹配。

代码实现

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

using namespace cv;
using namespace std;

int main() {
    int i;
    Mat img[2];
    img[0] = imread("E:/study/cv/计算机视觉/imgMain/lena.jpg");
    img[1] = imread("E:/study/cv/计算机视觉/imgMain/lena_copy.jpg");
    if (img[0].empty() || img[1].empty())
        return 0;
    Ptr<SiftFeatureDetector> sift = SiftFeatureDetector::create(100);
    std::vector<KeyPoint> keyPoints[2];
    Mat descriptors[2];
    for (i = 0; i < 2; i++) {
        // 计算特征点
        sift->detect(img[i], keyPoints[i]);
        // 计算特征描述符
        sift->compute(img[i], keyPoints[i], descriptors[i]);
        // 绘制KeyPoints
        drawKeypoints(img[i], keyPoints[i], img[i]);
    }
    // 特征匹配:Flann-based matcher 使用快速近似最近邻搜索算法寻找 当我们需要找到一个相对好的匹配但是不需要最佳匹配的时候往往使用FlannBasedMatcher
    cv::Ptr<cv::DescriptorMatcher> matcher = cv::DescriptorMatcher::create(cv::DescriptorMatcher::FLANNBASED);
    // KNN-NNDR匹配法
      // KNN:K最邻近。如果一个样本在特征空间中的K个最相似(即特征空间中最邻近)的样本中大多数属于某一个类别,则该样本叶属于这个类别
      // NNDR:最近邻距离比率。最近邻距离和次近邻距离的比值
    std::vector<std::vector<cv::DMatch>> knn_matches;
    const float ratio_thresh = 0.7f;
    std::vector<cv::DMatch> good_matches;
    matcher->knnMatch(descriptors[0], descriptors[0], knn_matches, 2);
    for (auto& knn_matche : knn_matches)
    {
        if (knn_matche[0].distance<ratio_thresh * knn_matche[1].distance)
            good_matches.push_back(knn_matche[0]);
    }
    // 最匹配图
    cv::Mat img_matches_knn;
    drawMatches(img[0], keyPoints[0], img[1], keyPoints[1], good_matches, img_matches_knn, cv::Scalar::all(-1),
        cv::Scalar::all(-1), std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
    cv::imshow("knn_matches", img_matches_knn);
    waitKey();  
}

关键步骤解释

  1. 创建SIFT特征检测器对象

    Ptr<SiftFeatureDetector> sift = SiftFeatureDetector::create(100);
    

    这里参数100表示预期检测到的特征点数目。

  2. 特征检测与描述符计算

    sift->detect(img[i], keyPoints[i]);
    sift->compute(img[i], keyPoints[i], descriptors[i]);
    

    detect函数用于检测特征点,compute函数用于计算特征描述符。

  3. 特征匹配

    cv::Ptr<cv::DescriptorMatcher> matcher = cv::DescriptorMatcher::create(cv::DescriptorMatcher::FLANNBASED);
    matcher->knnMatch(descriptors[0], descriptors[0], knn_matches, 2);
    

    使用FLANN(快速最近邻)匹配器进行特征点匹配,knnMatch函数返回每个特征点的两个最佳匹配。

  4. 筛选优秀匹配点对

    for (auto& knn_matche : knn_matches)
    {
        if (knn_matche[0].distance<ratio_thresh * knn_matche[1].distance)
            good_matches.push_back(knn_matche[0]);
    }
    

    通过比较最近邻距离和次近邻距离的比值来筛选出优秀的匹配点对。

  5. 绘制匹配结果

    drawMatches(img[0], keyPoints[0], img[1], keyPoints[1], good_matches, img_matches_knn);
    imshow("knn_matches", img_matches_knn);
    

    使用drawMatches函数绘制匹配结果,并显示在窗口中。

匹配结果展示

通过上述步骤,我们可以清晰地看到两张图像之间的特征匹配结果。SIFT算法的强大之处在于它能够在不同的光照条件、尺度和旋转角度下保持特征的稳定性,因此在图像拼接、目标识别、3D重建等领域都有广泛的应用。

本文通过一个简单的代码示例,展示了如何使用OpenCV实现SIFT特征匹配。希望读者能够通过这个示例,对SIFT算法有一个更直观的理解,并能够在实际项目中应用这一技术。

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号