FLANN (Fast Approximate Nearest Neighbor Search Library), 快速最近邻逼近搜索函数库。即实现快速高效匹配。
特征匹配记录下目标图像与待匹配图像的特征点(KeyPoint),并根据特征点集合构造特征量(descriptor),对这个特征量进行比较、筛选,最终得到一个匹配点的映射集合。我们也可以根据这个集合的大小来衡量两幅图片的匹配程度。
特征匹配与模板匹配不同,由于是计算特征点集合的相关度,转置操作对匹配影响不大,但它容易受到失真、缩放的影响。
代码示例:
#include
#include
#include
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;
int main(int argc, char** argv)
{
Mat img1 = imread("D:/cv400/data/box.png", IMREAD_GRAYSCALE);
Mat img2 = imread("D:/cv400/data/box_in_scene.png", IMREAD_GRAYSCALE);
if (img1.empty() || img2.empty())
{
cout << "Load image error..." << endl;
return -1;
}
imshow("object image", img1);
imshow("object in scene", img2);
// surf featurs extraction
double t1 = (double)getTickCount();
int minHessian = 400;
Ptr detector = SURF::create(minHessian);
vector keypoints_obj;
vector keypoints_scene;
Mat descriptor_obj, descriptor_scene;
detector->detectAndCompute(img1, Mat(), keypoints_obj, descriptor_obj);
detector->detectAndCompute(img2, Mat(), keypoints_scene, descriptor_scene);
// matching
FlannBasedMatcher matcher;
vector matches;
matcher.match(descriptor_obj, descriptor_scene, matches);
double t2 = (double)getTickCount();
double t = (t2 - t1) / getTickFrequency();
cout << "spend time : " << t << "s" << endl;
//求匹配点最近距离
double minDist = 1000;
for (int i = 0; i < descriptor_obj.rows; i++)
{
double dist = matches[i].distance;
if (dist < minDist)
minDist = dist;
}
cout<<"min distance : "<< minDist< goodMatches;
for (int i = 0; i < descriptor_obj.rows; i++)
{
double dist = matches[i].distance;
if (dist < max(3 * minDist, 0.02))
goodMatches.push_back(matches[i]);
}
Mat matchesImg;
drawMatches(img1, keypoints_obj, img2, keypoints_scene, goodMatches, matchesImg, Scalar::all(-1),
Scalar::all(-1), vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
imshow("Flann Matching Result", matchesImg);
waitKey(0);
return 0;
}
运行截图:
耗时 175 ms
接下来,在前面程序的基础上,将场景中的目标图像定位出来(画出来),要用到两个函数:
#include
#include
#include
#include
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;
int main(int argc, char** argv)
{
Mat img1 = imread("D:/cv400/data/box.png", IMREAD_GRAYSCALE);
Mat img2 = imread("D:/cv400/data/box_in_scene.png", IMREAD_GRAYSCALE);
if (img1.empty() || img2.empty())
{
cout << "Load image error..." << endl;
return -1;
}
imshow("object image", img1);
imshow("object in scene", img2);
// surf featurs extraction
double t1 = (double)getTickCount();
int minHessian = 400;
Ptr detector = SURF::create(minHessian);
vector keypoints_obj;
vector keypoints_scene;
Mat descriptor_obj, descriptor_scene;
detector->detectAndCompute(img1, Mat(), keypoints_obj, descriptor_obj);
detector->detectAndCompute(img2, Mat(), keypoints_scene, descriptor_scene);
// matching
FlannBasedMatcher matcher;
vector matches;
matcher.match(descriptor_obj, descriptor_scene, matches);
double t2 = (double)getTickCount();
double t = (t2 - t1) / getTickFrequency();
cout << "spend time : " << t << "s" << endl;
//求匹配点最近距离
double minDist = 1000;
for (int i = 0; i < descriptor_obj.rows; i++)
{
double dist = matches[i].distance;
if (dist < minDist)
minDist = dist;
}
cout<<"min distance : "<< minDist< goodMatches;
for (int i = 0; i < descriptor_obj.rows; i++)
{
double dist = matches[i].distance;
if (dist < max(3 * minDist, 0.02))
goodMatches.push_back(matches[i]);
}
//寻找匹配上的关键点的变换
vector obj; //目标特征点
vector objInScene; //场景中目标特征点
for (size_t t = 0; t < goodMatches.size(); t++)
{
obj.push_back(keypoints_obj[goodMatches[t].queryIdx].pt);
objInScene.push_back(keypoints_scene[goodMatches[t].trainIdx].pt);
}
Mat imgBH = findHomography(obj, objInScene, RANSAC);
//映射点
vector obj_corners(4);
vector scene_corners(4);
obj_corners[0] = Point(0, 0);
obj_corners[1] = Point(img1.cols, 0);
obj_corners[2] = Point(img1.cols, img1.rows);
obj_corners[3] = Point(0, img1.rows);
perspectiveTransform(obj_corners, scene_corners, imgBH);
//四个点之间画线
Mat dst;
cvtColor(img2, dst, COLOR_GRAY2BGR);
line(dst, scene_corners[0], scene_corners[1], Scalar(0, 0, 255), 2, 8, 0);
line(dst, scene_corners[1], scene_corners[2], Scalar(0, 0, 255), 2, 8, 0);
line(dst, scene_corners[2], scene_corners[3], Scalar(0, 0, 255), 2, 8, 0);
line(dst, scene_corners[3], scene_corners[0], Scalar(0, 0, 255), 2, 8, 0);
imshow("find object in sence", dst);
waitKey(0);
return 0;
}
运行截图: