目录

一、SIFT特征是什么?

二、SIFT特征是怎么计算的?

1. DoG尺度空间的极值检测

1.1 尺度空间

1.2 高斯尺度空间

1.3 高斯差分尺度空间(Difference of Gaussina, DOG尺度空间)

1.4 高斯差分金字塔

1.5 DoG尺度空间极值检测

2. 特征点定位

3. 特征方向赋值

4. 特征点描述

5. 特征匹配

三、代码示例

1. python版

2. C++版

参考


一、SIFT特征是什么?

SIFT的全称是Scale Invariant Feature Transform,尺度不变特征变换。具有旋转不变性、尺度不变性、亮度变化保持不变性,是一种非常稳定的局部特征

此方法由David Lowe1999年发表于ICCV(International Conference on Computer Vision),并经过5年的整理和完善,在2004年发表于IJCV(International journal of computer vision)。由于在此之前的目标检测算法对图片的大小、旋转非常敏感,而SIFT算法是一种基于局部兴趣点的算法,因此不仅对图片大小和旋转不敏感,而且对光照、噪声等影响的抗击能力也非常优秀,因此,该算法在性能和适用范围方面较于之前的算法有着质的改变。这使得该算法对比于之前的算法有着明显的优势,所以,一直以来它都在目标检测特征提取方向占据着重要的地位。

二、SIFT特征是怎么计算的?

主要有4个步骤:DOG(高斯差分)尺度空间的极值检测,特征点定位,特征方向赋值,特征点描述。

1. DoG尺度空间的极值检测

1.1 尺度空间

图像处理中的"尺度"可以理解为图像的模糊程度,类似眼睛近视的度数。(在图像尺寸一定的情况下)尺度(模糊程度)越大细节越少,SIFT特征希望提取所有尺度上的信息,也就是无论图像是否经过放大缩小都能够提取特征。

1.2 高斯尺度空间

我们还可以通过图像的模糊程度来模拟人在距离物体由远到近时物体在视网膜上成像过程,距离物体越近其尺度越大图像也越模糊,这就是高斯尺度空间(Gaussina),使用不同的参数,模糊图像(分辨率不变),是尺度空间的另一种表现形式。

我们知道图像和高斯函数进行卷积运算能够对图像进行模糊,使用不同的“高斯核”可得到不同模糊程度的图像。

在图像处理中对图像构建尺度空间的方法,是使用不同 σ 值的高斯核对图像进行卷积操作(注意,σ 就是“尺度”)。σ 表示为尺度空间因子,是高斯正态分布的标准差,σ 越小(尺度越小),反应的局部点越清晰。反之 σ 越大(尺度越大),图像越模糊,越不能反应出图像的细节。

高斯尺度空间 L(x,y,σ):

其中:G(x,y,σ)是高斯核函数;

1.3 高斯差分尺度空间(Difference of Gaussina, DOG尺度空间)

构建尺度空间的目的是为了检测出在不同的尺度下都存在的特征点,而检测特征点较好的算子是高斯拉普拉斯算子(Laplace of Gaussian, LoG, 一种二阶偏导微分算子),但其运算量过大,通常可使用 DoG来近似LoG。 LoG算子(高斯拉普拉斯算子)

高斯差分尺度空间 D(x,y,σ) (或者叫DoG尺度空间):

从上式可以知道,将相邻的两个高斯空间的图像相减就得到了DoG的响应图像。为了得到DoG图像,先要构建高斯尺度空间,而高斯的尺度空间可以在图像金字塔降采样的基础上加上高斯滤波得到,也就是对图像金字塔的每层图像使用不同的参数σ进行高斯模糊,使每层金字塔有多张高斯模糊过的图像。

1.4 高斯差分金字塔

图像金字塔

图像金字塔是同一图像在不同的分辨率下得到的一组结果,其生成过程一般包括两个步骤:

  1. 对原始图像进行平滑
  2. 对处理后的图像进行降采样(通常是水平、垂直方向的1/2)
    降采样后得到一系列不断尺寸缩小的图像。显然,一个传统的金字塔中,每一层的图像是其上一层图像长、高的各一半。多分辨率的图像金字塔虽然生成简单,但其本质是降采样,图像的局部特征则难以保持,也就是无法保持特征的尺度不变性。

高斯金字塔

在构建图像金字塔前,先对图像 I(x,y) 乘以一个高斯核函数 G(x,y,σ) 得到一个新的图像 (即高斯尺度空间 L(x,y,σ)),然后再对该新的图像,构建金字塔,即得到高斯金字塔。

易知,高斯金字塔有多组,每组又有多层。一组中的多个层之间的尺度是不一样的(也就是使用的高斯参数σ是不同的),相邻两层之间的尺度相差一个比例因子k。比如每组有S = 3层,则 。比如上面一图像的最底图像,是由下面一组中尺度为的图像,进行因子为2(长宽各减一半)的降采样得到的(高斯金字塔先从底层建立)。

高斯差分金字塔(DoG金字塔)

高斯金字塔构建完成后,将相邻的高斯金字塔相减就得到了DoG金字塔。

1.5 DoG尺度空间极值检测

为了寻找尺度空间的极值点,每个像素点要和其图像域(同一尺度空间)和尺度域(相邻的尺度空间)的所有相邻点进行比较(组内比较),当其大于(或者小于)所有相邻点时,改点就是极值点(候选关键点)。如图所示,中间的检测点要和其所在图像的3×3邻域8个像素点,以及其相邻的上下两层的3×3领域18个像素点,共26个像素点进行比较。

注意:每组图像的第一层和最后一层是无法进行比较取得极值的。为了满足尺度变换的连续性,在每一组图像的顶层继续使用高斯模糊生成3幅图像,高斯金字塔每组有S+3层图像,DoG金字塔的每组有S+2层图像。

2. 特征点定位

通过比较检测得到的DoG的局部极值点,是在离散的空间搜索得到的,由于离散空间是对连续空间采样得到的结果,因此在离散空间找到的极值点,不一定是真正意义上的极值点,因此要设法将不满足条件的点剔除掉。

这里可以通过对DoG尺度空间函数—D(x,y,σ) 进行曲线拟合(泰勒二次展开求极值)寻找极值点,这一步的本质是去掉DoG尺度空间中局部曲率非常不对称的点(参考:SIFT特征原理简析(HELU版))。
要剔除掉的不符合要求的点主要有两种:

  • 低对比度的特征点。
  • 不稳定的边缘响应点

3. 特征方向赋值

确定了每幅图中的特征点,为每个特征点计算一个方向,依照这个方向做进一步的计算。 利用关键点邻域像素的梯度方向分布特性,为每个关键点指定方向参数,使算子具备旋转不变性。

关键点的梯度值 m(x,y) 、梯度方向 θ(x,y) 计算 (L为高斯尺度空间函数L(x,y,σ)):

计算得到梯度方向后,就要使用直方图统计特征点邻域内像素对应的梯度方向和幅值。梯度方向的直方图的横轴是梯度方向的角度(梯度方向的范围是0到360度,直方图每36度一个柱共10个柱,或者没45度一个柱共8个柱),纵轴是梯度方向对应梯度幅值的累加。在直方图的峰值就是特征点的主方向

通过以上的图可以看出,梯度方向角为横轴刻度,取45度为一个单位,那么横轴就有8个刻度;纵轴是对应梯度的幅值累加值。

关键点主方向:极值点周围区域梯度直方图的主峰值也是特征点方向。

关键点辅方向:在梯度方向直方图中,当存在另一个相当于主峰值 80%能量的峰值时,则将这个方向认为是该关键点的辅方向。

图中所示的是180度方向为主方向,45度方向可以看做是辅方向。仅有15%的关键点被赋予多个方向,但可以明显的提高关键点匹配的稳定性 。

在Lowe的论文还提到了使用高斯函数对直方图进行平滑以增强特征点近的邻域点对关键点方向的作用,并减少突变的影响。为了得到更精确的方向,通常还可以对离散的梯度直方图进行插值拟合。具体而言,关键点的方向可以由和主峰值最近的三个柱值通过抛物线插值得到。在梯度直方图中,当存在一个相当于主峰值80%能量的柱值时,则可以将这个方向认为是该特征点辅助方向。所以,一个特征点可能检测到多个方向(也可以理解为,一个特征点可能产生多个坐标、尺度相同,但是方向不同的特征点)。Lowe在论文中指出

15%的关键点具有多方向,而且这些点对匹配的稳定性很关键。

得到特征点的主方向后,对于每个特征点可以得到三个信息(x,y,σ,θ),即位置、尺度方向。由此可以确定一个SIFT特征区域,一个SIFT特征区域由三个值表示,中心表示特征点位置,半径表示关键点的尺度,箭头表示主方向。具有多个方向的关键点可以被复制成多份,然后将方向值分别赋给复制后的特征点,一个特征点就产生了多个坐标、尺度相等,但是方向不同的特征点。

4. 特征点描述

这个描述符不只包含特征点,也含有特征点周围对其有贡献的像素点。描述子应具有较高的独立性,以保证匹配率

确定描述子计算区域和并校正主方向:

在计算描述子之前,我们需要先确定计算区域,Lowe实验结果表明:描述子采用4×4×8=128维向量表征,综合效果最优 (不变性与独特性)。为了保证特征矢量具有旋转不变性,需要以特征点为中心,将特征点附近邻域内图像梯度的位置和方向旋转一个方向角θ,即将原图像x轴转到与主方向相同的方向。

生成描述子:

下图所示,左图的中央为当前关键点的位置,每个小格代表为关键点邻域所在尺度空间的一个像素,求取每个像素的梯度幅值与梯度方向,箭头方向代表该像素的梯度方向,长度代表梯度幅值,然后利用高斯窗口对其进行加权运算。

最后在每个小块上(图像中每个正方形的区域,4像素x4像素)绘制8个方向的梯度直方图,计算每个梯度方向的累加值,即可形成一个种子点,如右图所示。每个特征点由4个种子点组成,每个种子点有8个方向的向量信息。这种邻域方向性信息联合增强了算法的抗噪声能力,同时对于含有定位误差的特征匹配也提供了比较理性的容错性。

在实际的计算过程中,为了增强匹配的稳健性,Lowe建议对每个关键点使用4×4(16像素x16像素)共16个种子点来描述,这样一个关键点就可以产生128维的SIFT特征向量。

5. 特征匹配

这个128维的SIFT特征向量就像是我们每个人的身份证一样,拥有绝对标识,几乎不可能重复,在这里可以对128维向量进行归一化处理,可以去除光照变化的影响。我们对模板图和目标图分别建立描述子集合。特征点的匹配是通过两点集合内关键点描述子的比对来完成,描述子的相似度量采用欧氏距离。假设如下:

取图像1中的某个关键点,并找出其与图像2中欧式距离最近的前两个关键点,在这两个关键点中,如果最近的距离除以次近的距离少于某个比例阈值下面的Threshold(也叫ratio),则接受这一对匹配点。

即最终留下来的配对的关键点描述子,需要满足条件:

作者建议ratio的取值原则如下:

ratio=0. 4 对于准确度要求高的匹配;
ratio=0. 6 对于匹配点数目要求比较多的匹配; 
ratio=0. 5 一般情况下。
也可按如下原则:当最近邻距离<200时,ratio=0. 6,反之ratio=0. 4。ratio的取值策略能排分错误匹配点。

  

三、代码示例-SIFT特征匹配

1 python版

import cv2
import numpy as np
#import pdb
#pdb.set_trace()#turn on the pdb prompt#read image
img = cv2.imread('D:\privacy\picture\little girl.jpg',cv2.IMREAD_COLOR)
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
cv2.imshow('origin',img);#SIFT
detector = cv2.SIFT()
keypoints = detector.detect(gray,None)
img = cv2.drawKeypoints(gray,keypoints)
#img = cv2.drawKeypoints(gray,keypoints,flags = cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow('test',img);
cv2.waitKey(0)
cv2.destroyAllWindows()

2 C++版

// FeatureDetector.cpp : Defines the entry point for the console application.
//
//  Created by Rachel on 14-1-12.
//  Copyright (c) 2013年 ZJU. All rights reserved.
//  #include "stdafx.h"
#include "highgui.h"
#include "cv.h"
#include "vector"
#include "opencv\cxcore.hpp"
#include "iostream"
#include "opencv.hpp"
#include "nonfree.hpp"
#include "showhelper.h"using namespace cv;
using namespace std;int _tmain(int argc, _TCHAR* argv[])
{//Load Image Mat c_src1 =  imread( "..\\Images\\3.jpg");Mat c_src2 = imread("..\\Images\\4.jpg");Mat src1 = imread( "..\\Images\\3.jpg", CV_LOAD_IMAGE_GRAYSCALE);Mat src2 = imread( "..\\Images\\4.jpg", CV_LOAD_IMAGE_GRAYSCALE);if( !src1.data || !src2.data ){ std::cout<< " --(!) Error reading images " << std::endl; return -1; }//sift feature detectSiftFeatureDetector detector;std::vector<KeyPoint> kp1, kp2;detector.detect( src1, kp1 );detector.detect( src2, kp2 );SiftDescriptorExtractor extractor;Mat des1,des2;//descriptorextractor.compute(src1,kp1,des1);extractor.compute(src2,kp2,des2);  Mat res1,res2; int drawmode = DrawMatchesFlags::DRAW_RICH_KEYPOINTS;drawKeypoints(c_src1,kp1,res1,Scalar::all(-1),drawmode);//在内存中画出特征点drawKeypoints(c_src2,kp2,res2,Scalar::all(-1),drawmode);cout<<"size of description of Img1: "<<kp1.size()<<endl;cout<<"size of description of Img2: "<<kp2.size()<<endl;//write the size of features on pictureCvFont font;    double hScale=1;   double vScale=1;    int lineWidth=2;// 相当于写字的线条    cvInitFont(&font,CV_FONT_HERSHEY_SIMPLEX|CV_FONT_ITALIC, hScale,vScale,0,lineWidth);//初始化字体,准备写到图片上的   // cvPoint 为起笔的x,y坐标   IplImage* transimg1 = cvCloneImage(&(IplImage) res1);IplImage* transimg2 = cvCloneImage(&(IplImage) res2);char str1[20],str2[20];sprintf(str1,"%d",kp1.size());sprintf(str2,"%d",kp2.size());const char* str = str1;cvPutText(transimg1,str1,cvPoint(280,230),&font,CV_RGB(255,0,0));//在图片中输出字符 str = str2;cvPutText(transimg2,str2,cvPoint(280,230),&font,CV_RGB(255,0,0));//在图片中输出字符 //imshow("Description 1",res1);cvShowImage("descriptor1",transimg1);cvShowImage("descriptor2",transimg2);BFMatcher matcher(NORM_L2);vector<DMatch> matches;matcher.match(des1,des2,matches);Mat img_match;drawMatches(src1,kp1,src2,kp2,matches,img_match);//,Scalar::all(-1),Scalar::all(-1),vector<char>(),drawmode);cout<<"number of matched points: "<<matches.size()<<endl;imshow("matches",img_match);cvWaitKey();cvDestroyAllWindows();return 0;
}

参考

  • SIFT特征详解
  • SIFT特征提取分析
  • SIFT特征原理简析(HELU版)

  • SIFT特征匹配详细原理

图像处理_描述下SIFT特征?(清晰易懂)相关推荐

  1. OpenCV与图像处理学习十四——SIFT特征(含代码)

    OpenCV与图像处理学习十四--SIFT特征(含代码) 一.SIFT算法 二.SIFT实现过程 三.代码实现 一.SIFT算法 SIFT, 即尺度不变特征变换算法(Scale-invariant f ...

  2. sift计算描述子代码详解_浅谈SIFT特征描述子

    SIFT是我接触最早的图像局部特征描述子之一,其实最初,始终觉得局部特征描述子是些非常玄虚的东西.对于SIFT,这种感觉更是尤为强烈,"尺度空间""拉普拉斯高斯算子(Lo ...

  3. python图像相似度识别_一个用SIFT特征比较图像相似度的python小程序

    1 问题描述 把一堆图片按照与给出的一张图片的相似度进行排序 2 程序 可以从图片中提取SIFT特征,对两幅图片的SIFT特征进行匹配并按照一定条件删选就能得到两幅图片的匹配点个数,匹配点个数越多,相 ...

  4. 图像特征检测描述(一):SIFT、SURF、ORB、HOG、LBP特征的原理概述及OpenCV代码实现

    图像处理开发需求.图像处理接私活挣零花钱,请加微信/QQ 2487872782 图像处理开发资料.图像处理技术交流请加QQ群,群号 271891601 什么叫特征检测?就是检测图像中目标的特征呗,所谓 ...

  5. 【图像处理】——特征匹配(SIFT特征检测器+FLANN特征匹配方法+KNN近邻最优匹配筛选)——cv.xfeatures2d.SIFT_create()sift.detectAndCompute

    转载请注明地址 目录 1.特征检测和特征匹配方法 (1)特征检测算法 (2)特征匹配算法 (3)各种特征检测算法的比较 2.特征匹配的基本步骤(附带主要的函数) (1)图像预处理--灰度化(模板--查 ...

  6. matlab人民币识别,Matlab图像处理学习笔记(六):基于sift特征点的人民币识别...

    本文记录如何利用sift特征点进行人民币的识别.本文给出的matlab源码识别了1元与100元人民币的面额,相同思路,可以对各种币值的人民币进行面额.正反面的识别.但由于本程序采用串行,模板数的增多会 ...

  7. Ubuntu16.04下基于opencv--实现图像SIFT特征与全景图片的生成

    Ubuntu16.04下基于opencv--实现图像SIFT特征与全景图片的生成 一. 理解和实践SIFT特征提取与匹配 二. 全景图片的生成 三.循环依次读取一个序列图片,进行匹配连线 一. 理解和 ...

  8. SIFT特征点提取及描述论文算法详解

    SIFT特征点提取及描述论文算法详解 1. 尺度空间极值检测(Scale-space extrema detection) 1.1 尺度空间和极值 1.2 DoG和LoG的关系 1.3 构建高斯尺度差 ...

  9. Python什么是闭包、闭包特征、定义闭包传入一个数求和并输出,定义一个装饰器:打印函数运行花费的时间,定义一个类:要求:包含一个对象属性,且用_(单下划线)命名的定义一个类方法(装饰器)

    1. 闭包.闭包特征及应用 1.1 什么是闭包? 闭包就是外部函数中定义一个内部函数,内部函数引用外部函数中的变量,外部函数的返回值是内部函数; 闭包是由函数及其相关的引用环境组合而成的实体(即:闭包 ...

  10. numpy 数组抽取_清晰易懂的Numpy入门教程

    原标题:清晰易懂的Numpy入门教程 翻译 | 石头 来源 | Machine Learning Plus Numpy是python语言中最基础和最强大的科学计算和数据处理的工具包,如数据分析工具pa ...

最新文章

  1. cdr怎样把一张图片随意变形_PS手记|移动工具的使用与画布的变形
  2. error C2873: “Matrix2r”: 符号不能用在 using 声明中
  3. python3官方最新下载-python3.7
  4. cgroup代码浅析(2)
  5. 我是如何提高工作和研究效率的?分享给大家几个神器
  6. LeetCode_每日一题今日份_343.整除拆分
  7. 电商网站模板_阿里云建站:模板建站与定制建站怎么选(小白参考)
  8. bloomfilter的java实现,BloomFilter(布隆过滤器)原理及实战详解
  9. 关于webstorm 配置 banbel
  10. 现有php环境下安装memcached并测试(centos6.4系统64位)
  11. soapui 免费版 实现 datasource+ dataLoop
  12. ES6入门:模板字符串
  13. c语言memcmp函数详解,C语言之memcmp()函数
  14. 如何用将top命令的结果写入txt?
  15. Linux系统查看FC HBA卡信息的方法
  16. DXO 做了哪些测试?
  17. yarn安装依赖速度太慢的解决办法
  18. 十二届蓝桥杯第四期模拟比赛
  19. 百度搜索资源平台链接提交通道
  20. python语句基础

热门文章

  1. java中使用switch case报错case expressions must be constant expres
  2. [洛谷P4183][USACO18JAN]Cow at Large P
  3. [2019杭电多校第四场][hdu6616]Divide the Stones
  4. JavaScript MD5加密实现
  5. 从TIN获取任意坐标点高程(原创)
  6. 为什么设置 height 100% 不起作用
  7. Windows10远程连接服务器时出现“这可能是由于CredSSP加密数据库修正”的错误提示的解决办法
  8. VS2015 设置结构成员对齐
  9. python自动发邮件mysql_python自动化六--操作mysql,redis,发送邮件,EXCEL,MD5加密
  10. android 6.0 ndk版本,[推荐]android-ndk6.0翻译(1)