版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_26671711/article/details/62891143
// FeatureDetector.cpp : Defines the entry point for the console application.
#include<opencv2/nonfree/features2d.hpp> //使用SiftFeatureDetector需要加上此头文件
#include<opencv2\opencv.hpp>
#include<iostream>
#include<fstream>
using namespace cv;
using namespace std;
int main(int argc, char* argv[])
{
//ofstream fileo("data.txt");
//Load Image
Mat c_src1 = imread("E:\\P\\case2\\CV_RoiImage.bmp");
Mat c_src2 = imread("E:\\P\\case2\\cv_temp.bmp");
Mat src1 = imread("E:\\P\\case2\\cv_temp.bmp", CV_LOAD_IMAGE_GRAYSCALE);
Mat src2 = imread("E:\\P\\case2\\CV_RoiImage.bmp", CV_LOAD_IMAGE_GRAYSCALE);
if (!src1.data || !src2.data)
{
std::cout << " --(!) Error reading images " << std::endl; return -1;
}
//sift feature detect
SiftFeatureDetector detector;
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 << kp1.at(matches.at(1).queryIdx).angle << endl;
//cout<<kp2.at(matches.at(1).trainIdx).angle << endl;
//投票表决,获得近似的角度
int angle_count[361] = {0};
int count = 0;
for (int i = 0; i < matches.size(); i++)
{
int index = kp2.at(matches.at(i).trainIdx).angle - kp1.at(matches.at(i).queryIdx).angle+0.5;
//fileo << kp2.at(matches.at(i).trainIdx).angle - kp1.at(matches.at(i).queryIdx).angle << endl;
index=index > 0 ? index : index + 360;
//cout << index << endl;
angle_count[index]++;
}
int maxindex = 0;
for (int i = 0; i < 361; i++)
{
//cout << i << " " << angle_count[i]<<endl;
if (angle_count[i] >= angle_count[maxindex])
{
maxindex = i;
}
}
maxindex = (maxindex - 360) < 0 ? maxindex : (maxindex - 360);
cout << "旋转角度:" << maxindex << endl;
//对临界值的处理,存在一些问题
int down, up;
down = maxindex - 1 < 0 ? maxindex : maxindex - 1;
up = maxindex + 1 > 360 ? maxindex : maxindex + 1;
double angle = 0;
count = 0;
for (int i = 0; i < matches.size(); i++)
{
double temp = kp2.at(matches.at(i).trainIdx).angle - kp1.at(matches.at(i).queryIdx).angle;
if (temp >= down&&temp <= up)
{
count++;
angle += temp;
}
}
angle /= count;
cout << "精确角度:" << angle << endl;
cout << "number of matched points: " << matches.size() << endl;
imshow("matches", img_match);
cvWaitKey();
cvDestroyAllWindows();
return 0;
}
SIFT描述子具有旋转不变性,在这个方法中,给出了使用SIFT描述子进行匹配并进行投票计算旋转角度的方法。
(目标区域)
模板,没有找到很好的例子,就直接拍了键盘,模板是原图顺时针旋转30°得到的。
结果如下:
可以看到,角度还是算的蛮准的,缺点就是速度比较慢。不过,目前使用的是投票然后求平均值,平均值在很多时候并不能有效,可以换用中位数。