OpenCV之图像特征提取与检测(九) SIFT特征检测

SIFT(Scale-Invariant Feature Transform  尺度不变性特征变换)特征检测关键特性:
    -建立尺度空间,寻找极值(最小最大值)-
    -关键点定位(寻找关键点准确位置与删除弱边缘)
    -关键点方向指定
        计算图像 x y 方向梯度获取像素位置的梯度,并以梯度计算直方图,最后统计出bins最高的梯度,这个梯度就是关键点的方向
    -关键点描述子

建立尺度空间,寻找极值  工作原理
    1. 构建图像高斯金字塔,求取DOG,发现最大与最小值在每一级
    2. 构建的高斯金字塔,每一层根据sigma的值不同,可以分为几个等级,最少有4 个。求出的DOG最少有3个

这里写图片描述
这里写图片描述

关键点定位
    我们在像素级别获得了极值点的位置,但是更准确的值应该在亚像素位置,如何得到 – 这个过程称为关键点(准确/精准)定位。
    删除弱边缘- 通过Hassian 矩阵特征值实现,小于阈值自动舍弃

这里写图片描述

关键点方向指定
    求得每一层对应图像的梯度,根据给定的窗口大小
    计算每个高斯权重, sigma=scalex1.5, 0~360之间建立36个直方图Bins
    找最高峰对应的Bin, 大于max*80% 的bins也都保留
    这样就实现了旋转不变性,提高了匹配时候的稳定性。
    大约有15%的关键点会有多个方向。

这里写图片描述

关键点描述子
    拟合多项式插值寻找最大Peak (得到的bins是一个角度范围,通过拟合,求出最大的角度)
    得到描述子 = 4x4x8=128

这里写图片描述

至此 SIFT算法 找到了 location 方向 keypoints周围的描述子,然后就可以去做匹配了
    SIFT算法比SURF更能抗干扰,也比SURF算法特征检测更精准,但是比SURF算法要慢

static Ptr<cv::xfeatures2d::SIFT> cv::xfeatures2d::SIFT::create( // SIFT特征检测
    int nfeatures = 0, // number of features 想求的特征的数量,越多计算量越大
    int nOctaveLayers = 3, // 高斯金字塔的层级数,最小3,小于3就没有SIFT的尺度不变性的特点了
    double contrastThreshold = 0.04, // 对比度,用于关键点定位
    double edgeThreshold = 10, // 边缘阈值
    double sigma = 1.6 // 高斯方差 σ
);

代码

    #include "../common/common.hpp"

    using namespace cv::xfeatures2d;

    static Mat src;
    static const char title[] = "SIFT KeyPoints";
    static int numFeatures = 400; // SIFT 要检测的特征的数量
    static int max_count = 800;

    static void sift_detect(int, void*);

    void main(int argc, char** argv)
    {
        src = imread(getCVImagesPath("images/test1_3.png"), IMREAD_GRAYSCALE);
        imshow("src2-11", src);

        namedWindow(title, CV_WINDOW_AUTOSIZE);
        createTrackbar("minHessian:", title, &numFeatures, max_count, sift_detect);
        sift_detect(0, 0);

        waitKey(0);
    }

    void sift_detect(int, void*)
    {
        if (numFeatures < 100) numFeatures = 100;
        Ptr<SIFT> detector = SIFT::create(numFeatures); // SIFT特征检测类
        vector<KeyPoint> keypoints; // 保存关键点
        detector->detect(src, keypoints, Mat()); // 检测
        cout << "keypoints.size=" << keypoints.size() << endl; // 最大只能寻找到 456 个关键点?

        Mat keypoint_img;
        drawKeypoints(src, keypoints, keypoint_img, Scalar::all(-1), DrawMatchesFlags::DEFAULT); // 绘制关键点
        imshow(title, keypoint_img); // SIFT检测出来的特征点比SURF的检测结果看起来更准确些
    }

效果图

这里写图片描述

猜你喜欢

转载自blog.csdn.net/huanghuangjin/article/details/81272014