前面我们对sift算法的流程进行简要研究,那么在OpenCV中,sift是如何被调用的?又是如何被实现出来的了?
特别是到了3.0以后,OpenCV对特征点提取这个方面进行了系统重构,那么整个代码结构变成了什么模样?
在代码中
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071200833-744634460.png)
可以看出目前的结构是基于hess的算法进行的重构。那么首先需要解决的是整体的调用和实现结构问题,然后是hess算法的结构问题,再然后才是具体的算法。需要做的事情很多,
一起来研究。
一、OpenCV中sift调用接口和例子
首先是一定要编译使用contrib版本的OpenCV代码,同时最后设置的时候需要注意,
头文件和命名空间要选择正确。
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071201443-965289106.png)
在最新版本的OpenCV中,已经对特征提取这块的函数进行了统一接口:
Mat matSrc
=
imread(
"e:/template/lena.jpg"
);
Mat gray;
Mat draw;
cvtColor( matSrc, gray, CV_RGB2GRAY );
Mat descriptors;
std : :vector <KeyPoint > keypoints;
// 生产sift结构
Ptr <SiftFeatureDetector > siftFD = SiftFeatureDetector : :create();
siftFD - >detectAndCompute(gray,Mat(),keypoints,draw);
drawKeypoints(gray,keypoints,gray,Scalar( 0, 0, 255),DrawMatchesFlags : :DEFAULT);
Mat draw;
cvtColor( matSrc, gray, CV_RGB2GRAY );
Mat descriptors;
std : :vector <KeyPoint > keypoints;
// 生产sift结构
Ptr <SiftFeatureDetector > siftFD = SiftFeatureDetector : :create();
siftFD - >detectAndCompute(gray,Mat(),keypoints,draw);
drawKeypoints(gray,keypoints,gray,Scalar( 0, 0, 255),DrawMatchesFlags : :DEFAULT);
结果:
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071201771-277696542.jpg)
这里也只是简单地把特征点给画了出来,并没有将方向等信息进行表示。下面我们具体看一看sift在OpenCV中是如何实现的。
OpenCV是开发源代码的,所以这里的代码都是可以自己看到的。那么联调的方式为
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071202068-770136789.png)
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071202193-1718657751.png)
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071203068-2070278268.png)
二、sift的代码结构解析
注意,sift的原始地址在
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071203865-247321557.png)
它的类结构为:
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071203974-996157668.png)
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071204052-1390750043.png)
它的构建函数为:
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071204146-1017332451.png)
直接返回的是本类的指针
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071204240-1614925081.png)
我们去看代码,基本了解结构以后,就直接从我们想要用的那个函数开始“顺藤摸瓜”。我们想要的是
detectAndCompute 函数。
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071205818-1568483363.png)
三、sift的代码具体实现
step0: createInitialImage 将图片转换成为合适的大小
Mat base = createInitialImage(image, firstOctave < 0, (float)sigma);
最为简单的一步,据说将输入的图片变化为规整的大小和格式:
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071206724-2108435637.png)
//step1: buildGaussianPyramid 构建高斯金字塔
buildGaussianPyramid(base, gpyr, nOctaves);
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071208021-849423805.png)
//step2: buildDoGPyramid 构建高斯差分金字塔
buildDoGPyramid(gpyr, dogpyr);
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071209052-1905587705.png)
//step3: findScaleSpaceExtrema removeDuplicated 寻找并筛选尺度空间特征值
findScaleSpaceExtrema(gpyr, dogpyr, keypoints);
注意这里将特征值的初略寻找和细化寻找放在了一起(一个循环)
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071211615-1203902553.png)
其中
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071214193-1897105861.png)
其中二
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071215615-220398764.png)
注意:
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071216224-2140423725.png)
//step4: calcDescriptors 计算特征值
calcDescriptors(gpyr, keypoints, descriptors, nOctaveLayers, firstOctave);
![](https://images2017.cnblogs.com/blog/508489/201710/508489-20171005071218380-1605065926.png)
三、简单小结
这里也只是将sift的代码挑了出来,简单进行了分析。应该说OpenCV的代码本身才是其最为精髓的地方,无论是代码背后的理论,还是代码实现的技术,以及各种提升速度的方法,都对于我们写出出色的图像处理算法和运用很有帮助。
而学习的最好方法就是去实现创造。OpenCV本身就是开源的项目,基于现有的这么多的资源,在图像处理广阔的领域去进行创新,不断巩固提升自己的能力。与大家共勉!