欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SIFT特征提取及其opencv实现

程序员文章站 2022-05-17 20:32:36
...

SIFT特征提取及其opencv实现

SIFT特征提取算法的实质是寻找图像中对位置、尺度、旋转等保持不变的关键点,其步骤主要有如下四步:

  1. 尺度空间极值检测:搜索所有尺度上的图像位置。通过高斯微分函数来识别潜在的对于尺度和旋转不变的兴趣点。
  2. 关键点定位:在每个候选的位置上,通过一个拟合精细的模型来确定位置和尺度。关键点的选择依据于它们的稳定程度。
  3. 方向确定:基于图像局部的梯度方向,分配给每个关键点位置一个或多个方向。所有后面的对图像数据的操作都相对于关键点的方向、尺度和位置进行变换,从而提供对于这些变换的不变性。
  4. 关键点描述:在每个关键点周围的邻域内,在选定的尺度上测量图像局部的梯度。这些梯度被变换成一种表示,这种表示允许比较大的局部形状的变形和光照变化。

关于SIFT特征提取的资料很多,这里只说明几个地方。首先对于尺度的变换,Lindeberg等人已证明高斯卷积核是实现尺度变换的唯一变换核,并且是唯一的线性核。在SIFT算法中,用DOG算子来获得不同尺度下的图像特征,之所以用DOG(高斯差分算子)来进行这种处理,是因为,2002年Mikolajczyk在详细的实验比较中发现尺度归一化的高斯拉普拉斯函数的极大值和极小值同其它的特征提取函数,例如:梯度,Hessian或Harris角特征比较,能够产生最稳定的图像特征。而Lindeberg早在1994年就发现高斯差分函数 与尺度归一化的高斯拉普拉斯函数非常近似。这个在参考的博客中有详细的介绍和推导。为了获得旋转不变性,我们需要利用直方图统计各个方向关键点的个数来作为处理,选择峰值的80%作为辅助方向。在寻找极值点的过程中,会用每个像素点和其领域的8个点以及上下两层的9x2=18个点作比较,也就是和26个点作比较,获得极值点。


对于opencv实现SIFT特征提取,这里简单介绍一个数据结构KeyPoint,关于其中的源码分析请看链接。KeyPoint类是一个为特征点检测而生的数据结构,用于表示特征点。

class KeyPoint
{
Point2f pt; //坐标
    float size; //特征点领域直径
    float angle;//特征点的方向,值为[0,360],负值表示不使用
    float response;
    int octave; //特征点所在的图像金字塔的组
    int class_id;//用于聚类的id
}

下面是利用C++和opencv实现的SIFT特征提取。

#include <opencv2/opencv.hpp>
#include <opencv2/features2d/features2d.hpp>
#include<opencv2/nonfree/nonfree.hpp>
#include<opencv2/legacy/legacy.hpp>
#include<vector>
#include <fstream>
#include<iostream>

using namespace std;
using namespace cv;

int  main(  )
{
    //从文件中读入图像
    Mat img = imread("/home/fc/1.png",1);

    //如果读入图像失败
    if (img.empty()){
        fprintf(stderr, "Can not load image \n");
        return -1;
    }
    //显示图像
    imshow("image before", img);

    //sift特征检测
    SiftFeatureDetector siftdtc;
    vector<KeyPoint>kp;
    siftdtc.detect(img, kp);//到这里其实只是提取到了特征点的具体位置和角度,其保存在kp中
    Mat outimg;
    drawKeypoints(img, kp, outimg);
    imshow("image keypoints", outimg);
    imwrite("fc.jpg",outimg);


    SiftDescriptorExtractor extractor;//特征提取器
    Mat descriptor; //这个描述符才是做实验要用的特征
    extractor.compute(img, kp, descriptor);
    ofstream file("./img.feature");//提取到的特征保存在这个文件中,128维,整数做实验以后再归一化一下
    file << endl << descriptor << endl;

    //此函数等待按键,按键盘任意键就返回
    waitKey();
    return 0;
}

我是在QT下编程,所以需要配置一下.pro中的lib,具体如下:

TEMPLATE = app
CONFIG += console c++11
CONFIG -= app_bundle
CONFIG -= qt
INCLUDEPATH += /usr/local/include \
                /usr/local/include/opencv \
                /usr/local/include/opencv2

LIBS += /usr/local/lib/libopencv_highgui.so \
        /usr/local/lib/libopencv_core.so    \
        /usr/local/lib/libopencv_imgproc.so\
        /usr/local/lib/libopencv_legacy.so\
        /usr/local/lib/libopencv_nonfree.so\
         /usr/local/lib/libopencv_features2d.so
SOURCES += main.cpp

相关链接:
SIFT特征检测参数
尺度不变特征变换
SIFT算法详解

相关标签: CV