好的博文:
《1》http://blog.csdn.net/abcjennifer/article/details/7639681 理论
《2》http://blog.csdn.net/abcjennifer/article/details/7365882 应用
《3》http://www.cnblogs.com/cql/archive/2013/05/23/3095749.html 理轮;
《4》http://blog.csdn.net/masibuaa/article/details/9207657 robhess代码解析
《5》http://blog.csdn.net/masibuaa/article/details/9191309 RobHess代码解析
《6》http://www.cnblogs.com/cql/archive/2013/05/23/3095749.html robhess 代码编译。
《7》http://blog.csdn.net/xiaowei_cqu/article/details/8067881 尺度理论
限于本人的编码水平和理论水平,看了看lowe的论文,只能了解大意,不能深入的理解,于是借助前面几篇中文的翻译和博主们对sift算法的理解来理解sift算法。
借助于4,5博文首先编译opensift,有了代码就啥都好办了,opencv虽然有sift实现但是封装的太好了,反而不容易理解。
按照6博文编译的过程中出现了unistd.h无法找到的错误,去掉后又出现getopt无定义等错误,可以先去掉出错的*.c文件,出错的主要是main函数的命令行解析函数,对理解代码没有什么太大的帮助和障碍,然后运行match.c文件中的main函数就可以了。在vs中的命令行中写入要进行sift运算的两个图片按下f5就可以了
初步运行达到博文6的效果。
首先介绍sift使用的基础算法
1.kd树实现最近邻搜索
(1)k近邻算法1.首先查找出与训练集T中找到与实例x最近邻的k个点,2.在这k个点所属的类别,根据多数表决原则,决定x所属的类别y。
(2)kd树。参看《统计学习方法》p41。1.开始构造根节点,选择x(1)坐标轴在训练集T中所有的实例的中点作为切分点,将所有的训练集T根据根节点所对应的超平面分为两个子区域。2 重复。对已经切分出来的子区域再根据坐标轴x(j)进行继续切分,知道切分的区域中只有一个实例,这个实例就是叶节点。3.切分到叶节点kd树构造完毕。
(3)kd树实现knn算法。1.构造kd树。2.由根节点开始递归的向下访问kd树,如果x的当前维小于切分点左移节点,反之右移,直到最后为叶节点。2.将找到的叶节点作为当前最近点。3.重复。a如果“当前最近点”比当前“计算的节点”更远,那么用“当前计算节点”替代“当前最近点”。b.计算父节点对应的超平面是否与最近节点所计算出的超球面相交或者相切,如果相交或者相切,递归想上搜索,否则结束。参考资料《统计学习方法》和http://xiaofeng1982.blog.163.com/blog/static/31572458201210214406792/ http://blog.csdn.net/v_july_v/article/details/8203674 资料中有个形象的gif下面转载过来:
2.sift算法过程总结
//将修正后的坐标赋值给特征点feat
//原图中特征点的x坐标,因为第octv组中的图的尺寸比原图小2^octv倍,所以坐标值要乘以2^octv
feat->img_pt.x = feat->x = ( c + xc ) * pow( 2.0, octv );
//原图中特征点的y坐标,因为第octv组中的图的尺寸比原图小2^octv倍,所以坐标值要乘以2^octv
feat->img_pt.y = feat->y = ( r + xr ) * pow( 2.0, octv );
(代码摘自opensif,注释来自:
http://blog.csdn.net/masibuaa/article/details/9207657);;;;;;;
#include "highgui.h"
#include "cv.h"
#include "vector"
#include "opencv\cxcore.hpp"
#include "iostream"
#include "opencv.hpp"
//#include "nonfree.hpp"
#include<opencv2/nonfree/features2d.hpp>
#include<opencv2/nonfree/nonfree.hpp>
//#include "showhelper.h"
using namespace cv;
using namespace std;
int main()//(int argc, _TCHAR* argv[])
{
//Load Image
Mat c_src1 = imread( "hello.jpg");
Mat c_src2 = imread("hello2.jpg");
Mat src1 = imread( "hello.jpg", CV_LOAD_IMAGE_GRAYSCALE);
Mat src2 = imread( "hello2.jpg", CV_LOAD_IMAGE_GRAYSCALE);
if( !src1.data || !src2.data )
{ std::cout<< " --(!) Error reading images " << std::endl; return -1; }
//sift feature detect
SiftFeatureDetector detector;
std::vector<KeyPoint> kp1, kp2;
detector.detect( src1, kp1 );
detector.detect( src2, kp2 );
SiftDescriptorExtractor extractor;
Mat des1,des2;//descriptor
extractor.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;
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();
cv::SIFT sift ;
//sift.
return 0;
}