OpenCV中的SURF算法介绍
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; }
有了对特征点和描述符的简单认识后,对上述代码就能有更好的理解了。
- SURF算法的具体实现过程
整理了网上的一些资料:
- 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算法介绍的更多相关文章
- OpenCV学习(22) opencv中使用kmeans算法
kmeans算法的原理参考:http://www.cnblogs.com/mikewolf2002/p/3368118.html 下面学习一下opencv中kmeans函数的使用. 首先我们 ...
- OpenCV学习(35) OpenCV中的PCA算法
PCA算法的基本原理可以参考:http://www.cnblogs.com/mikewolf2002/p/3429711.html 对一副宽p.高q的二维灰度图,要完整表示该图像,需要m = ...
- Opencv中使用Surf特征实现图像配准及对透视变换矩阵H的平移修正
图像配准需要将一张测试图片按照第二张基准图片的尺寸.角度等形态信息进行透视(仿射)变换匹配,本例通过Surf特征的定位和匹配实现图像配准. 配准流程: 1. 提取两幅图像的Surf特征 2. 对Sur ...
- openCV中直方图均衡化算法的理解
直方图均衡化就是调整灰度直方图的分布,即将原图中的灰度值映射为一个新的值.映射的结果直观表现是灰度图的分布变得均匀,从0到255都有分布,不像原图那样集中.图像上的表现就是对比度变大,亮的更亮,暗的更 ...
- Opencv中K均值算法(K-Means)及其在图像分割中的应用
K均值(K-Means)算法是一种无监督的聚类学习算法,他尝试找到样本数据的自然类别,分类是K由用户自己定义,K均值在不需要任何其他先验知识的情况下,依据算法的迭代规则,把样本划分为K类.K均值是最常 ...
- OpenCV中Delaunay三角网算法例子
#include <opencv2/opencv.hpp> #include <vector> using namespace cv; using namespace std; ...
- c++opencv中线条细化算法
要达到的效果就是将线条尽量细化成单像素,按照论文上的Hilditch算法试了一下,发现效果不好,于是自己尝试着写了一下细化的算法,基本原理就是从上下左右四个方向向内收缩. 1.先是根据图片中的原则确定 ...
- 图像处理之 opencv 学习---opencv 中的常用算法
http://blog.csdn.net/lindazhou2005/article/details/1534234 文中有提到鲁棒性 http://blog.csdn.net/chary8088/a ...
- 在OpenCV for Android 2.4.5中使用SURF(nonfree module)
http://blog.csdn.net/ruifdu/article/details/9120559 在OpenCV4Android中没有nonfree module,因此也就没有了SURF和SIF ...
随机推荐
- redis秒杀系统数据同步(保证不多卖)
东西不多卖 秒杀系统需要保证东西不多卖,关键是在多个客户端对库存进行减操作时,必须加锁.Redis中的Watch刚好可以实现一点.首先我们需要获取当前库存,只有库存中的食物小于购物车的数目才能对库存进 ...
- java 的 CopyOnWriteArrayList类
初识CopyOnWriteArrayList 第一次见到CopyOnWriteArrayList,是在研究JDBC的时候,每一个数据库的Driver都是维护在一个CopyOnWriteArrayLis ...
- flask-compress的使用方法以及对应的http头Vary、Content-Encoding的意思
参考:https://github.com/shengulong/flask-compress 1.Content-Encoding是HTTP协议的响应报文头,一般形式如:Content-Encodi ...
- 【监控】使用 Grafana、collectd 和 InfluxDB 打造现代监控系统
参考资料:Grafana 是 Graphite 和 InfluxDB 仪表盘和图形编辑器:http://www.oschina.net/p/grafana 使用 Grafana.collectd 和 ...
- python对象序列化或持久化的方法
http://blog.csdn.net/chen_lovelotus/article/details/7233293 一.Python对象持久化方法 目前为止,据我所知,在python中对象持久化有 ...
- css水平竖直居中方式
CSS水平和垂直居中的几种实现方法: 1.单行垂直居中 文字在层中垂直居中vertical-align 属性是做不到的.我们这里有个比较巧妙的方法就是:设置height的高度与line-height的 ...
- Java Volatile keyword
Volatile修饰的成员变量在每次被线程訪问时,都强迫从主内存中重读该成员变量的值.并且,当成员变量发生变化时,强迫线程将变化值回写到主内存.这样在不论什么时刻,两个不同的线程总是看到某个成员变量的 ...
- ibatis--百度百科
iBATIS一词来源于“internet”和“abatis”的组合,是一个由Clinton Begin在2002年发起的开放源代码项目.于2010年6月16号被谷歌托管,改名为MyBatis.是一个基 ...
- 让C#可以像Javascript一样操作Json DynamicJson
http://blog.csdn.net/lisenyang/article/details/52535314
- jmeter 之 BSF,BeanShell(转载)
jmeter无法自行处理javascript,但是它可以用自带的BSF PreProcessor(BSF:面向java的脚本语言,支持javascript) (使用这个之前要把bsh-2.0b2.ja ...