SIFT
Scale Invariant Feature Transform,尺度不变特征变换。SIFT特征对旋转、尺度缩放、亮度变化等保持不变性,是一种非常稳定的局部特征。
SIFT算法主要有以下几个步骤:
高斯差分金字塔的构建
使用组和层的结构构建了一个具有线性关系的金字塔(尺度空间),这样可以在连续的高斯核尺度上查找图像的特征点;另外,它使用一阶的高斯差分来近似高斯的拉普拉斯核,大大的减少了运算量。
尺度空间的极值检测及特征点的定位
搜索上一步建立的高斯尺度空间,通过高斯差分来识别潜在的对尺度和旋转不变的特征点。但是,在离散空间中,局部极值点可能并不是真正意义的极值点,真正的极值点有可能落在离散点的间隙中,SIFT通过尺度空间DoG函数进行曲线拟合寻找极值点。
特征方向赋值
基于图像局部的梯度方向,分配给每个关键点位置一个或多个方向,后续的所有操作都是对于关键点的方向、尺度和位置进行变换,从而提供这些特征的不变性。
特征描述子的生成
通过上面的步骤已经找到的SIFT特征点的位置、方向、尺度信息,最后使用一组向量来描述特征点及其周围邻域像素的信息。
SURF
Speeded Up Robust Features。加速版的SIFT。SURF的流程和SIFT比较类似,这些改进体现在以下几个方面:
特征点检测是基于Hessian矩阵,依据Hessian矩阵行列式的极值来定位特征点的位置。并且将Hession特征计算与高斯平滑结合在一起,两个操作通过近似处理得到一个核模板。
在构建尺度空间时,使用box filter与源图像卷积,而不是使用DoG算子。
SURF使用一阶Haar小波在x、y两个方向的响应作为构建特征向量的分布信息。
头文件:
#include
SIFT 和SURF属于xfeatures2d模块,在opencv的官网发布版中并没有,需要自编译 ,官网说明如下:
定义:
typedef SIFT cv::xfeatures2d::SiftDescriptorExtractor
typedef SIFT cv::xfeatures2d::SiftFeatureDetector
typedef SURF cv::xfeatures2d::SurfDescriptorExtractor
typedef SURF cv::xfeatures2d::SurfFeatureDetector
由以下类的继承图可看看出:
SurfFeatureDetector类和SurfDescriptorExtractor类,其实就是SURF类,他们三者等价;
同样地,SiftFeatureDetector类和SiftDescriptorExtractor类,其实就是SIFT类,他们三者等价;
测试示例:
#include
#include
#include
using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;
int main()
{
Mat left_image = imread("..\\image\\left.jpg", 0);
Mat right_image = imread("..\\image\\right.jpg", 0);
//创建检测器
//cv::Ptr detector = SiftFeatureDetector::create();//sift
cv::Ptr detector = SurfFeatureDetector::create(100);//surf
//提取特征点、计算描述子
vector key_points_1, key_points_2;
cv::Mat dstImage1, dstImage2;
detector->detectAndCompute(left_image, Mat(), key_points_1, dstImage1);
detector->detectAndCompute(right_image, Mat(), key_points_2, dstImage2);
//绘制特征点
Mat img_keypoints_1, img_keypoints_2;
drawKeypoints(left_image, key_points_1, img_keypoints_1, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
drawKeypoints(right_image, key_points_2, img_keypoints_2, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
//匹配
cv::Ptr matcher = cv::DescriptorMatcher::create("FlannBased");
vector mach;
matcher->match(dstImage1, dstImage2, mach);
//计算匹配距离筛选阈值
double Max_dist = 0;
double Min_dist = 100;
for (int i = 0; i Max_dist)Max_dist = dist;
}
std::cout << "最短距离" << Min_dist << std::endl;
std::cout << "最长距离" << Max_dist << std::endl;
//筛选匹配点
vectorgoodmaches;
for (int i = 0; i < dstImage1.rows; i++)
{
if (mach[i].distance < 2.0 * Min_dist)
{
goodmaches.push_back(mach[i]);
}
}
// 画出匹配图
Mat imageMatches;
drawMatches(left_image, key_points_1, right_image, key_points_2, goodmaches,
imageMatches, Scalar(0, 0, 255));
return 0;
}