zoukankan      html  css  js  c++  java
  • OpenCV成长之路(9):特征点检测与图像匹配

    特征点又称兴趣点、关键点,它是在图像中突出且具有代表意义的一些点,通过这些点我们可以用来识别图像、进行图像配准、进行3D重建等。本文主要介绍OpenCV中几种定位与表示关键点的函数。

    一、Harris角点

    角点是图像中最基本的一种关键点,它是由图像中一些几何结构的关节点构成,很多都是线条之间产生的交点。Harris角点是一类比较经典的角点类型,它的基本原理是计算图像中每点与周围点变化率的平均值。

    image   (1)

    	exttt{dst} (x,y) =  mathrm{det} M^{(x,y)} - k  cdot left ( mathrm{tr} M^{(x,y)} 
ight )^2  (2)

    其中I(x+u,y+u)代表了点(x,y)邻域点的灰度值。通过变换可以将上式变化为一个协方差矩阵求特征值的问题(2),具体数学原理本文不过多描述。

    OpenCV的Hairrs角点检测的函数为cornerHairrs(),但是它的输出是一幅浮点值图像,浮点值越高,表明越可能是特征角点,我们需要对图像进行阈值化。我们使用一张建筑图像来显示:

    int main()
    {
        Mat image=imread("../buliding.png");
        Mat gray;
        cvtColor(image,gray,CV_BGR2GRAY);
    
        Mat cornerStrength;
        cornerHarris(gray,cornerStrength,3,3,0.01);
        threshold(cornerStrength,cornerStrength,0.001,255,THRESH_BINARY);
        return 0;
    }

    imageimage

    首先我们来说明一下cornerHairrs()这个函数参数的意思:

    前2参数是输入与输出,输入是一个灰度图像,输出是一个浮点图像,第三个参数指定角点分析的邻域,第4个参数实际上在角点求取过程中计算梯度图像的核窗口大小,第5个参数是它原理公式(2)中的一个系数。

    从上面的例子的结果我们可以看到,有很多角点都是粘连在一起的,我们下面通过加入非极大值抑制来进一步去除一些粘在一起的角点。

    非极大值抑制原理是,在一个窗口内,如果有多个角点则用值最大的那个角点,其他的角点都删除,窗口大小这里我们用3*3,程序中通过图像的膨胀运算来达到检测极大值的目的,因为默认参数的膨胀运算就是用窗口内的最大值替代当前的灰度值。程序的最后使用了一个画角点的函数将角点显示在图像中,这个函数与本系列第5篇中画角点的函数是一致的。

    int main()
    {
        Mat image=imread("../buliding.png");
        Mat gray;
        cvtColor(image,gray,CV_BGR2GRAY);
    
        Mat cornerStrength;
        cornerHarris(gray,cornerStrength,3,3,0.01);
    
        double maxStrength;
        double minStrength;
        // 找到图像中的最大、最小值
        minMaxLoc(cornerStrength,&minStrength,&maxStrength);
    
        Mat dilated;
        Mat locaMax;
        // 膨胀图像,最找出图像中全部的局部最大值点
        dilate(cornerStrength,dilated,Mat());
        // compare是一个逻辑比较函数,返回两幅图像中对应点相同的二值图像
        compare(cornerStrength,dilated,locaMax,CMP_EQ);
    
        Mat cornerMap;
        double qualityLevel=0.01;
        double th=qualityLevel*maxStrength; // 阈值计算
        threshold(cornerStrength,cornerMap,th,255,THRESH_BINARY);
        cornerMap.convertTo(cornerMap,CV_8U);
        // 逐点的位运算
        bitwise_and(cornerMap,locaMax,cornerMap);
    
        drawCornerOnImage(image,cornerMap);
        namedWindow("result");
        imshow("result",image);
        waitKey();
        
        return 0;
    }
    void drawCornerOnImage(Mat& image,const Mat&binary)
    {
        Mat_<uchar>::const_iterator it=binary.begin<uchar>();
        Mat_<uchar>::const_iterator itd=binary.end<uchar>();
        for(int i=0;it!=itd;it++,i++)
        {
            if(*it)
                circle(image,Point(i%image.cols,i/image.cols),3,Scalar(0,255,0),1);    
        }
    }

    现在我们得到的效果就比默认的函数得到的结果有相当的改善。

    image

    由于cornerHarris的一些缺点,OpenCV提供了另一个相似的函数GoodFeaturesToTrack()它用角点间的距离限制来防止角点粘连在一起。

    goodFeaturesToTrack(image,corner,
                      500,    // 最多检测到的角点数
                         0.01,    // 阈值系数
                         10);    // 角点间的最小距离

    它可以得到与上面基本一致的结果。

    二、FAST特征点

    harris特征在算法复杂性上比较高,在大的复杂的目标识别或匹配应用上效率不能满足要求,OpenCV提供了一个快速检测角点的类FastFeatureDetector,而实际上FAST并不是快的意思,而是Features from Accelerated Segment Test,但这个算法效率确实比较高,下面我们来看看这个类的用法。

    OpenCV里为角点检测提供了统一的接口,通过类下面的detect方法来检测对应的角点,而输出格式都是vector<KeyPoint>。

    vector<KeyPoint> keypoints; 
    FastFeatureDetector fast( // 定义检测类
        40); //40是检测的阈值
    fast.detect(image,keypoints);
    
    drawKeypoints(image,keypoints,image,Scalar(255,0,0),
        DrawMatchesFlags::DRAW_OVER_OUTIMG);

    其中drawKeypoints是OpenCV提供的在图像上画角点的函数。它的参数可以让我们选择用不同的方式标记出特征点。

    三、尺度不变的SURF特征

    surf特征是类似于SIFT特征的一种尺度不变的特征点,它的优点在于比SIFT效率要高,在实际运算中可以达到实时性的要求,关于SURF的原理这里就不过多的介绍,网络上这类的文章很多。

    类似于FAST特征点的求法,SURF也可以使用通用接口求得,而SURF特征的类为SurfFeatureDetector,类似的SIFT特征点的检测类为SiftFeatureDetector。

    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/nonfree/features2d.hpp>
    
    using namespace cv;
    
    int main()
    {
        Mat image=imread("../buliding.png");
    
        vector<KeyPoint> keypoints; 
        
        SurfFeatureDetector surf(2500.);
        surf.detect(image,keypoints);
    
        drawKeypoints(image,keypoints,image,Scalar(255,0,0),
            DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
        namedWindow("result");
        imshow("result",image);
        waitKey();
        
        return 0;
    }

    这里有一个值得说明的问题是:OpenCV2.4版本后好像把SurfFeatureDetector这个类的定义移到了头文件nonfree/features2d.hpp

    中,所以头文件中要加入该文件,并且要把opencv_nonfree24xd.lib加入属性表的链接器熟悉的输入中,其中x换成你当前opencv的版本号。

    最终的显示效果如下:

    image

    四、SURF特征的描述

    在图像配准中,特征点的描述往往不是位置这么简单,而是使用了一个N维向量来描述一个特征点,这些描述子之间可以通过定义距离公式来比较相近程度。

    SurfDescriptorExtractor 是一个提取SURF特征点以及其描述的类。

    下面是一个宽景图像的拼接配准的例子:

    image  image

    #include <opencv2/core/core.hpp>
    #include <opencv2/highgui/highgui.hpp>
    #include <opencv2/nonfree/features2d.hpp>
    #include <opencv2/legacy/legacy.hpp>
    
    using namespace cv;
    int main()
    {
        Mat image1=imread("../b1.png");
        Mat image2=imread("../b2.png");
        // 检测surf特征点
        vector<KeyPoint> keypoints1,keypoints2;     
        SurfFeatureDetector detector(400);
        detector.detect(image1, keypoints1);
        detector.detect(image2, keypoints2);
        // 描述surf特征点
        SurfDescriptorExtractor surfDesc;
        Mat descriptros1,descriptros2;
        surfDesc.compute(image1,keypoints1,descriptros1);
        surfDesc.compute(image2,keypoints2,descriptros2);
    
        // 计算匹配点数
        BruteForceMatcher<L2<float>>matcher;
        vector<DMatch> matches;
        matcher.match(descriptros1,descriptros2,matches);
        std::nth_element(matches.begin(),matches.begin()+24,matches.end());
        matches.erase(matches.begin()+25,matches.end());
        // 画出匹配图
        Mat imageMatches;
        drawMatches(image1,keypoints1,image2,keypoints2,matches,
            imageMatches,Scalar(255,0,0));
    
        namedWindow("image2");
        imshow("image2",image2);
        waitKey();
        
        return 0;
    }

    程序中我们选择了25个配准点,得到最后的匹配如下:

    image

  • 相关阅读:
    mysql 远程登陆不上
    hdu 5339 Untitled【搜索】
    SqlServer 书目
    passwordauthentication yes
    oracle 11g RAC ocfs2
    Oracle 11g RAC database on ASM, ACFS or OCFS2
    CentOS ips bonding
    Oracle 11g RAC features
    openStack 王者归来之 trivial matters
    openstack windows 2008 img
  • 原文地址:https://www.cnblogs.com/ronny/p/opencv_road_9.html
Copyright © 2011-2022 走看看