OpenCV学习之旅9——特征检测与匹配(2)

本文介绍如何使用SURF算法提取图像特征,并利用OpenCV中的drawMatches函数和BruteForceMatcher类进行特征点匹配。此外,还展示了如何通过FLANN进行更高效的特征匹配。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. SURF特征提取

在OpenCV中,使用SURF进行特征点描述主要是使用drawMatches 方法和BruteForceMatcher类。

1.1 drawMatches()函数

drawMatches用于绘制出相匹配的两个图像的关键点,该函数有两个函数原型。

void drawMatches( const Mat& img1, const vector<KeyPoint>& keypoints1,
                  const Mat& img2, 
                  const vector<KeyPoint>& keypoints2,
                  const vector<DMatch>& matches1to2, 
                  Mat& outImg,
                  const Scalar& singlePointColor=Scalar::all(-1),
                  int flags=DrawMatchesFlags::DEFAULT );

 void drawMatches( const Mat& img1, const vector<KeyPoint>& keypoints1,
                   const Mat& img2, const vector<KeyPoint>& keypoints2,
                   Mat& outImg,
                   const Scalar& matchColor=Scalar::all(-1), 
                   const Scalar& singlePointColor=Scalar::all(-1),
                   const vector<vector<char> >& matchesMask=vector<vector<char> >(), 
                   int flags=DrawMatchesFlags::DEFAULT );

第一个参数:第一幅源图像;
第二个参数:第一幅图像的特征点,为输出参数;
第三个参数:第二幅源图像;
第四个参数:第二幅图像的特征点,为输出参数;
第五个参数:matches1to2,第一幅图像到第二幅图像的匹配点;
第六个参数:输出图像;
第七个参数:线和关键点的颜色,默认Scalar::all(-1)表随机颜色;
第八个参数:单一特征点的颜色,默认值表随机颜色;
第九个参数:确定哪些匹配是要绘制出来的掩码,默认值表所有的都要绘制;
第十个参数:特征绘制的标识符。

1.2 BruteForceMatches类

template<class Distance>
class CV_EXPORTS BruteForceMatcher : public BFMatcher
{
public:
    BruteForceMatcher( Distance d = Distance() ) : BFMatcher(Distance::normType, false) {(void)d;}
    virtual ~BruteForceMatcher() {}
};

1.3 程序实例

#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <opencv2/nonfree/nonfree.hpp>
#include<opencv2/legacy/legacy.hpp>
#include <iostream>
using namespace cv;
using namespace std;

//-----------------------------------【main( )函数】--------------------------------------------
//      描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main(  )
{
    //【0】改变console字体颜色
    system("color 1F"); 

    //【1】载入素材图
    Mat srcImage1 = imread("1.jpg",1);
    Mat srcImage2 = imread("2.jpg",1);
    if( !srcImage1.data || !srcImage2.data )
    { printf("读取图片错误,请确定目录下是否有imread函数指定的图片存在~! \n"); return false; }  

    //【2】使用SURF算子检测关键点
    int minHessian = 700;//SURF算法中的hessian阈值
    SurfFeatureDetector detector( minHessian );//定义一个SurfFeatureDetector(SURF) 特征检测类对象  
    std::vector<KeyPoint> keyPoint1, keyPoints2;//vector模板类,存放任意类型的动态数组

    //【3】调用detect函数检测出SURF特征关键点,保存在vector容器中
    detector.detect( srcImage1, keyPoint1 );
    detector.detect( srcImage2, keyPoints2 );

    //【4】计算描述符(特征向量)
    SurfDescriptorExtractor extractor;
    Mat descriptors1, descriptors2;
    extractor.compute( srcImage1, keyPoint1, descriptors1 );
    extractor.compute( srcImage2, keyPoints2, descriptors2 );

    //【5】使用BruteForce进行匹配
    // 实例化一个匹配器
    BruteForceMatcher< L2<float> > matcher;
    std::vector< DMatch > matches;
    //匹配两幅图中的描述子(descriptors)
    matcher.match( descriptors1, descriptors2, matches );

    //【6】绘制从两个图像中匹配出的关键点
    Mat imgMatches;
    drawMatches( srcImage1, keyPoint1, srcImage2, keyPoints2, matches, imgMatches );//进行绘制

    //【7】显示效果图
    imshow("匹配图", imgMatches );

    waitKey(0);
    return 0;
}

2.使用FLANN进行特征点匹配

FLANN——快速最近邻逼近搜索函数库,Fast Libray for Approximate Nearest Neighbors。

2.1 FlannBasedMatcher类

class CV_EXPORTS_W FlannBasedMatcher : public DescriptorMatcher
{
//
}

2.2 找到最佳匹配:DescriptorMatcher::match方法

2.3 程序实例

#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include <opencv2/nonfree/nonfree.hpp>
#include<opencv2/legacy/legacy.hpp>
#include <iostream>
using namespace cv;
using namespace std;

//-----------------------------------【main( )函数】--------------------------------------------
//   描述:控制台应用程序的入口函数,我们的程序从这里开始执行
//-----------------------------------------------------------------------------------------------
int main( int argc, char** argv )
{
    //【0】改变console字体颜色    
    system("color 4F");    

    //【1】载入源图片
    Mat img_1 = imread("1.jpg", 1 );
    Mat img_2 = imread( "2.jpg", 1 );
    if( !img_1.data || !img_2.data ) { printf("读取图片image0错误~! \n"); return false; }  

    //【2】利用SURF检测器检测的关键点
    int minHessian = 300;
    SURF detector( minHessian );
    std::vector<KeyPoint> keypoints_1, keypoints_2;
    detector.detect( img_1, keypoints_1 );
    detector.detect( img_2, keypoints_2 );

    //【3】计算描述符(特征向量)
    SURF extractor;
    Mat descriptors_1, descriptors_2;
    extractor.compute( img_1, keypoints_1, descriptors_1 );
    extractor.compute( img_2, keypoints_2, descriptors_2 );

    //【4】采用FLANN算法匹配描述符向量
    FlannBasedMatcher matcher;
    std::vector< DMatch > matches;
    matcher.match( descriptors_1, descriptors_2, matches );
    double max_dist = 0; double min_dist = 100;

    //【5】快速计算关键点之间的最大和最小距离
    for( int i = 0; i < descriptors_1.rows; i++ )
    {
        double dist = matches[i].distance;
        if( dist < min_dist ) min_dist = dist;
        if( dist > max_dist ) max_dist = dist;
    }
    //输出距离信息
    printf("> 最大距离(Max dist) : %f \n", max_dist );
    printf("> 最小距离(Min dist) : %f \n", min_dist );

    //【6】存下符合条件的匹配结果(即其距离小于2* min_dist的),使用radiusMatch同样可行
    std::vector< DMatch > good_matches;
    for( int i = 0; i < descriptors_1.rows; i++ )
    { 
        if( matches[i].distance < 2*min_dist )
        { good_matches.push_back( matches[i]); }
    }

    //【7】绘制出符合条件的匹配点
    Mat img_matches;
    drawMatches( img_1, keypoints_1, img_2, keypoints_2,
        good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
        vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );

    //【8】输出相关匹配点信息
    for( int i = 0; i < good_matches.size(); i++ )
    { printf( ">符合条件的匹配点 [%d] 特征点1: %d  -- 特征点2: %d  \n", i, good_matches[i].queryIdx, good_matches[i].trainIdx ); }

    //【9】显示效果图
    imshow( "匹配效果图", img_matches );

    //按任意键退出程序
    waitKey(0);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值