SURF:speed up robust feature,翻译为快速鲁棒特征。首先就其中涉及到的特征点和描述符做一些简单的介绍:

  • 特征点和描述符  

  特征点分为两类:狭义特征点和广义特征点。狭义特征点的位置本身具有常规的属性意义,比如角点、交叉点等等。而广义特征点是基于区域定义的,它本身的位置不具备特征意义,只代表满足一定特征条件的特征区域的位置。广义特征点可以是某特征区域的任一相对位置。这种特征可以不是物理意义上的特征,只要满足一定的数学描述就可以,因而有时是抽象的。因此,从本质上说,广义特征点可以认为是一个抽象的特征区域,它的属性就是特征区域具备的属性;称其为点,是将其抽象为一个位置概念。

  特征点既是一个点的位置标识,同时也说明它的局部邻域具有一定的模式特征。事实上,特征点是一个具有一定特征的局部区域的位置标识,称其为点,是将其抽象为一个位置概念,以便于确定两幅图像中同一个位置点的对应关系而进行图像匹配。所以在特征匹配过程中是以该特征点为中心,将邻域的局部特征进行匹配。也就是说在进行特征匹配时首先要为这些特征点(狭义和广义)建立特征描述,这种特征描述通常称之为描述符

  一个好的特征点需要有一个好的描述方法将其表现出来,它涉及到的是图像匹配的一个准确性。因此在基于特征点的图像拼接和图像配准技术中,特征点和描述符同样重要。

更多内容可参考:http://blog.sina.com.cn/s/blog_4b146a9c0100rb18.html

  • OpenCv中SURF的demo
 #include <stdio.h>
#include <iostream>
#include "opencv2/core/core.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp" using namespace cv; void readme(); /** @function main */
int main( int argc, char** argv )
{
if( argc != )
{ readme(); return -; } Mat img_object = imread( argv[], CV_LOAD_IMAGE_GRAYSCALE );
Mat img_scene = imread( argv[], CV_LOAD_IMAGE_GRAYSCALE ); if( !img_object.data || !img_scene.data )
{ std::cout<< " --(!) Error reading images " << std::endl; return -; } //-- Step 1: Detect the keypoints using SURF Detector
int minHessian = ; SurfFeatureDetector detector( minHessian ); std::vector<KeyPoint> keypoints_object, keypoints_scene; detector.detect( img_object, keypoints_object );
detector.detect( img_scene, keypoints_scene ); //-- Step 2: Calculate descriptors (feature vectors)
SurfDescriptorExtractor extractor; Mat descriptors_object, descriptors_scene; extractor.compute( img_object, keypoints_object, descriptors_object );
extractor.compute( img_scene, keypoints_scene, descriptors_scene ); //-- Step 3: Matching descriptor vectors using FLANN matcher
FlannBasedMatcher matcher;
std::vector< DMatch > matches;
matcher.match( descriptors_object, descriptors_scene, matches ); double max_dist = ; double min_dist = ; //-- Quick calculation of max and min distances between keypoints
for( int i = ; i < descriptors_object.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 ); //-- Draw only "good" matches (i.e. whose distance is less than 3*min_dist )
std::vector< DMatch > good_matches; for( int i = ; i < descriptors_object.rows; i++ )
{ if( matches[i].distance < *min_dist )
{ good_matches.push_back( matches[i]); }
} Mat img_matches;
drawMatches( img_object, keypoints_object, img_scene, keypoints_scene,
good_matches, img_matches, Scalar::all(-), Scalar::all(-),
vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS ); //-- Localize the object
std::vector<Point2f> obj;
std::vector<Point2f> scene; for( int i = ; i < good_matches.size(); i++ )
{
//-- Get the keypoints from the good matches
obj.push_back( keypoints_object[ good_matches[i].queryIdx ].pt );
scene.push_back( keypoints_scene[ good_matches[i].trainIdx ].pt );
} Mat H = findHomography( obj, scene, CV_RANSAC ); //-- Get the corners from the image_1 ( the object to be "detected" )
std::vector<Point2f> obj_corners();
obj_corners[] = cvPoint(,); obj_corners[] = cvPoint( img_object.cols, );
obj_corners[] = cvPoint( img_object.cols, img_object.rows ); obj_corners[] = cvPoint( , img_object.rows );
std::vector<Point2f> scene_corners(); perspectiveTransform( obj_corners, scene_corners, H); //-- Draw lines between the corners (the mapped object in the scene - image_2 )
line( img_matches, scene_corners[] + Point2f( img_object.cols, ), scene_corners[] + Point2f( img_object.cols, ), Scalar(, , ), );
line( img_matches, scene_corners[] + Point2f( img_object.cols, ), scene_corners[] + Point2f( img_object.cols, ), Scalar( , , ), );
line( img_matches, scene_corners[] + Point2f( img_object.cols, ), scene_corners[] + Point2f( img_object.cols, ), Scalar( , , ), );
line( img_matches, scene_corners[] + Point2f( img_object.cols, ), scene_corners[] + Point2f( img_object.cols, ), Scalar( , , ), ); //-- Show detected matches
imshow( "Good Matches & Object detection", img_matches ); waitKey();
return ;
} /** @function readme */
void readme()
{ std::cout << " Usage: ./SURF_descriptor <img1> <img2>" << std::endl; }

有了对特征点和描述符的简单认识后,对上述代码就能有更好的理解了。

代码来源:http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/features2d/feature_homography/feature_homography.html#feature-homography

  • SURF算法的具体实现过程

整理了网上的一些资料:

  1. surf算法原理,有一些简单介绍(1)

  http://blog.csdn.net/andkobe/article/details/5778739

2.  surf算法原理,有一些简单介绍(2)

  http://wuzizhang.blog.163.com/blog/static/78001208201138102648854/

3 . 特征点检测学习_2(surf算法)

http://www.cnblogs.com/tornadomeet/archive/2012/08/17/2644903.html

  • 其他
 // DMatch function
DMatch(int queryIdx, int trainIdx, float distance)

其中 queryIdx 和 trainIdx 对应的特征点索引由match 函数决定,例如:

 // 按如下顺序使用
match(descriptor_for_keypoints1, descriptor_for_keypoints2, matches)

则queryIdx 和 trainIdx分别对应keypoints1和keypoints2。

2013-11-05

OpenCV中的SURF算法介绍的更多相关文章

  1. OpenCV学习(22) opencv中使用kmeans算法

    kmeans算法的原理参考:http://www.cnblogs.com/mikewolf2002/p/3368118.html 下面学习一下opencv中kmeans函数的使用.      首先我们 ...

  2. OpenCV学习(35) OpenCV中的PCA算法

    PCA算法的基本原理可以参考:http://www.cnblogs.com/mikewolf2002/p/3429711.html     对一副宽p.高q的二维灰度图,要完整表示该图像,需要m = ...

  3. Opencv中使用Surf特征实现图像配准及对透视变换矩阵H的平移修正

    图像配准需要将一张测试图片按照第二张基准图片的尺寸.角度等形态信息进行透视(仿射)变换匹配,本例通过Surf特征的定位和匹配实现图像配准. 配准流程: 1. 提取两幅图像的Surf特征 2. 对Sur ...

  4. openCV中直方图均衡化算法的理解

    直方图均衡化就是调整灰度直方图的分布,即将原图中的灰度值映射为一个新的值.映射的结果直观表现是灰度图的分布变得均匀,从0到255都有分布,不像原图那样集中.图像上的表现就是对比度变大,亮的更亮,暗的更 ...

  5. Opencv中K均值算法(K-Means)及其在图像分割中的应用

    K均值(K-Means)算法是一种无监督的聚类学习算法,他尝试找到样本数据的自然类别,分类是K由用户自己定义,K均值在不需要任何其他先验知识的情况下,依据算法的迭代规则,把样本划分为K类.K均值是最常 ...

  6. OpenCV中Delaunay三角网算法例子

    #include <opencv2/opencv.hpp> #include <vector> using namespace cv; using namespace std; ...

  7. c++opencv中线条细化算法

    要达到的效果就是将线条尽量细化成单像素,按照论文上的Hilditch算法试了一下,发现效果不好,于是自己尝试着写了一下细化的算法,基本原理就是从上下左右四个方向向内收缩. 1.先是根据图片中的原则确定 ...

  8. 图像处理之 opencv 学习---opencv 中的常用算法

    http://blog.csdn.net/lindazhou2005/article/details/1534234 文中有提到鲁棒性 http://blog.csdn.net/chary8088/a ...

  9. 在OpenCV for Android 2.4.5中使用SURF(nonfree module)

    http://blog.csdn.net/ruifdu/article/details/9120559 在OpenCV4Android中没有nonfree module,因此也就没有了SURF和SIF ...

随机推荐

  1. 启用多处理器编译--加快VS2013编译

    依次打开项目“属性“==>”配置属性“==>”C/C++(或其它语言)“==>”常规“,最后一项,多处理器编译选择是. 官方解释如下: /MP 选项在命令行上以减少总时间编译源文件. ...

  2. CMD一键获取cpu信息

    windows + R 输入cmd打开CMD 输入wmic cpu get Name 获取cpu名称-即物理cpu数 cpu get NumberOfCores获取cpu核心数 cpu get Num ...

  3. 【ztree系列——图标的修改】Bootstrap风格的ztree

    前段时间项目中需要用树形结构,在选取的时候参考了很多插件,经过很多尝试,最后又回归到了ztree上.以前用的界面框架是EasyUI,但是它的树结构在实现起来有点复杂,并且功能不是特别完善.dtree在 ...

  4. Linux源码编译安装MySQL5.7

    目录[-] 一.环境准备: 二.升级系统: 三.做一些准备工作(以下Linux命令均在su到root用户操作): 四.开始编译安装mysql-5.7.9: 一.环境准备: 我尝试过以下环境都是能成功的 ...

  5. hive操作记录

    hive是依赖于hdfs和yarn的一个数据仓库 数据库和数据仓库的区别: 数据库在存储数据的同时,允许实时的增删改查等操作 数据仓库在存储数据的同时还执行着计算和分析数据的工作,但是并不能实时的进行 ...

  6. [Javascript] Deep merge in Javascript with Ramda.js mergeDeepWith

    Javascript's Object.assign is shadow merge, loadsh's _.merge is deep merge, but has probem for array ...

  7. MPTCP 源码分析(七) 拥塞控制

    简述      MPTCP的拥塞控制对TCP的拥塞控制的线性增加阶段进行了修改,而慢启动,快速重传. 快速恢复都没有改变.每条子路径拥有自己的cwnd,MPTCP的拥塞算法主要关心cwnd的改变.   ...

  8. QQ和微信凶猛成长的背后:腾讯网络基础架构的这些年

    本文来自腾讯资深架构师杨志华的分享. 1.前言 也许没有多少人记得2004年发生的事情.但对于老腾讯来说,14年前的那个日子,2004年6月16日永远难以忘怀.这一天,QQ诞生5年后的腾讯在香港联交所 ...

  9. 使用Python实现生产者消费者问题

    之前用C++写过一篇生产者消费者的实现. 生产者和消费者主要是处理互斥和同步的问题: 队列作为缓冲区,需要互斥操作 队列中没有产品,消费者需要等待,直到生产者放入产品并通知它.队列慢的情况类似. 这里 ...

  10. ural 1057 Amount of degrees 【数位dp】

    题意:求(x--y)区间转化为 c 进制 1 的个数为 k 的数的出现次数. 分析:发现其满足区间减法,所以能够求直接求0---x 的转化为 c 进制中 1 的个数为k的数的出现次数. 首先用一个数组 ...