步骤:先用SURF描述子检测关键点,再利用FLANN匹配对关键点进行筛选匹配,最后利用透视变换将匹配后的对象画出来。
#include<opencv2\opencv.hpp>
#include<opencv2\xfeatures2d.hpp>
using namespace cv;
using namespace xfeatures2d;
using namespace std;
int main(int arc, char** argv)
{
Mat src1 = imread("1.png",IMREAD_GRAYSCALE);
Mat src2 = imread("2.png", IMREAD_GRAYSCALE);
namedWindow("input1", CV_WINDOW_AUTOSIZE);
imshow("input1", src1);
imshow("input2", src2);
//surf features extraction
int minHessian = 400;
Ptr<SURF>surf = SURF::create(minHessian);
vector<KeyPoint>keypoints1, keypoints2;
Mat descriptors1, descriptors2;
surf->detectAndCompute(src1, Mat(), keypoints1, descriptors1);
surf->detectAndCompute(src2, Mat(), keypoints2, descriptors2);
//match
FlannBasedMatcher matcher;
vector<DMatch>matches;
matcher.match(descriptors1, descriptors2, matches);
//looking for some good match
double minDist = 1000;
double maxDist = 0;
for (int i = 0; i < descriptors1.rows; i++)
{
double dist = matches[i].distance;
if (dist > maxDist)
{
maxDist = dist;
}
if (dist < minDist)
{
minDist = dist;
}
}
printf("max distance:%lf\n", maxDist);
printf("min distance:%lf\n", minDist);
vector<DMatch>goodMatchers;
for (int i = 0; i < descriptors1.rows; i++)
{
double dist = matches[i].distance;
if (dist < max(3*minDist,0.02))
{
goodMatchers.push_back(matches[i]);
}
}
//draw matches_img
Mat matches_img;
drawMatches(src1, keypoints1, src2, keypoints2, goodMatchers, matches_img, Scalar::all(-1), Scalar::all(-1),vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
vector<Point2f>srcGoodPoints;
vector<Point2f>dstGoodPoints;
for (int j = 0; j < goodMatchers.size(); j++)
{
srcGoodPoints.push_back(keypoints1[goodMatchers[j].queryIdx].pt);
dstGoodPoints.push_back(keypoints2[goodMatchers[j].trainIdx].pt);
}
Mat H = findHomography(srcGoodPoints, dstGoodPoints, RANSAC);//寻找透视矩阵
//detect object
vector<Point2f>src_corners(4);
vector<Point2f>dst_corners(4);
src_corners[0] = Point(0, 0);
src_corners[1] = Point(src1.cols, 0);
src_corners[2] = Point(src1.cols, src1.rows);
src_corners[3] = Point(0,src1.rows);
perspectiveTransform(src_corners, dst_corners, H);//点的透视变换
//在匹配图上画出目标,因为匹配图的画布是两幅图合在一起的,所以需要加上第一幅图的宽度
line(matches_img, dst_corners[0] + Point2f(src1.cols,0), dst_corners[1] + Point2f(src1.cols,0),Scalar(0,0,255), 2);
line(matches_img, dst_corners[1] + Point2f(src1.cols,0), dst_corners[2] + Point2f(src1.cols,0), Scalar(0, 0, 255), 2);
line(matches_img, dst_corners[2] + Point2f(src1.cols,0), dst_corners[3] + Point2f(src1.cols,0), Scalar(0, 0, 255), 2);
line(matches_img, dst_corners[3] + Point2f(src1.cols,0), dst_corners[0] + Point2f(src1.cols,0), Scalar(0, 0, 255), 2);
imshow("output1", matches_img);
//在原图上画出目标
cvtColor(src2, src2, CV_GRAY2BGR);
line(src2, dst_corners[0] , dst_corners[1], Scalar(0, 0, 255), 2);
line(src2, dst_corners[1] , dst_corners[2], Scalar(0, 0, 255), 2);
line(src2, dst_corners[2] , dst_corners[3], Scalar(0, 0, 255), 2);
line(src2, dst_corners[3] , dst_corners[0], Scalar(0, 0, 255), 2);
imshow("output2", src2);
waitKey(0);
return 0;
}