获取特征点后,SIFT用方向梯度直方图描述每个特征点的特征。
首先计算每个特征点的梯度幅度和方向:
然后计算特征点周围16x16范围的每个点的梯度方向,对其中上下左右每4x4的区域,统计区域内各点的方向梯度直方图。
直方图把360度角划分为36个bin,计算前先用高斯平滑削弱边缘的影响。16x16点的梯度方向在进行直方图统计前先按特征点的“主方向”旋转,以获取旋转不变性特征。
以下是OpenCV中SIFT的简单应用:
#include <opencv2\opencv.hpp>
#include <opencv2\nonfree\nonfree.hpp>
using namespace std;
using namespace cv;
int main() {
Mat img = imread("d:/dataset/book.jpg");
Mat gray;
cvtColor(img, gray, CV_RGB2GRAY);
Mat rotImg;
Mat affine = getRotationMatrix2D(Point2f((float)img.cols / 2, (float)img.rows / 2), 45, 0.5);
warpAffine(img, rotImg, affine, Size(img.cols, img.rows));
Mat rotGray;
cvtColor(rotImg, rotGray, CV_RGB2GRAY);
initModule_nonfree();
Ptr<FeatureDetector> detector = FeatureDetector::create("SIFT");
Ptr<DescriptorExtractor> extractor = DescriptorExtractor::create("SIFT");
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce");
if (detector.empty() || extractor.empty() ) {
cout << "create detector error" << endl;
exit(-1);
}
vector<KeyPoint> pts1, pts2;
Mat feats1, feats2;
vector<DMatch> matches, goodMatches;
detector->detect(gray, pts1);
extractor->compute(gray, pts1, feats1);
detector->detect(rotGray, pts2);
extractor->compute(rotGray, pts2, feats2);
matcher->match(feats1, feats2, matches);
double maxDist = 0, minDist = 1000;
for (int i = 0; i < matches.size(); i++) {
if (minDist > matches[i].distance)
minDist = matches[i].distance;
if (maxDist < matches[i].distance)
maxDist = matches[i].distance;
}
cout << minDist << " " << maxDist << endl;
double thres = minDist + 0.1 * (maxDist - minDist);
for (int i = 0; i < matches.size(); i++) {
if (matches[i].distance <= thres)
goodMatches.push_back(matches[i]);
}
Mat disp;
drawMatches(img, pts1, rotImg, pts2, goodMatches, disp);
namedWindow("disp");
imshow("disp", disp);
waitKey();
}