什么是特征描述子
图片具有特有特征
匹配
提取一份图像中的特征,去训练集图像库寻找,寻找贴合区域
函数api
void cv::drawMatches(
InputArray img1,
const std::vector< KeyPoint > &keypoints1,
InputArray img2,
const std::vector< KeyPoint > &keypoints2,
const std::vector< DMatch > &matches1to2,
InputOutputArray outImg,
const Scalar & matchColor = Scalar::all(-1),
const Scalar & singlePointColor = Scalar::all(-1),
const std::vector< char > &matchesMask = std::vector< char >(),
int flags = DrawMatchesFlags::DEFAULT
)
void cv::drawMatches(
InputArray img1,
const std::vector< KeyPoint > &keypoints1,
InputArray img2,
const std::vector< KeyPoint > &keypoints2,
const std::vector< std::vector< DMatch > > &matches1to2,
InputOutputArray outImg,
const Scalar & matchColor = Scalar::all(-1),
const Scalar & singlePointColor = Scalar::all(-1),
const std::vector< std::vector< char > > &matchesMask = std::vector< std::vector< char > >(),
int flags = DrawMatchesFlags::DEFAULT
)
参数介绍
两个函数的区别仅在于DMatch数据接收的数据类型不同
enum {
DEFAULT = 0, //创建输出图像矩阵,对每一个特征点都只绘制其中间部分。
DRAW_OVER_OUTIMG = 1, //不创建输出图像矩阵,而是在输出图像上绘制匹配对
NOT_DRAW_SINGLE_POINTS = 2, //单点特征点不被绘制
DRAW_RICH_KEYPOINTS = 4 //对每个特征点,绘制带大小和方向的关键点图像
}
循规蹈矩逐行逐列去匹配
例如下面的例子:使用SURF特征提取BF匹配方法进行匹配(暴力匹配)
#include
#include
#include
using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;
#define PIC_PATH "/work/opencv_pic/"
#define PIC_NAME "opencv.jpg"
#define PIC_PATH1 "/work/opencv_pic/"
#define PIC_NAME1 "opencvbkp.jpg"
int main(void)
{
Mat src,src1;
//获取完整的图片路径及名称
string pic = string(PIC_PATH1)+string(PIC_NAME1);
string pic1 = string(PIC_PATH)+string(PIC_NAME);
//打印图片路径
cout << "pic path is :"<<pic<<endl;
cout << "pic1 path is :"<<pic1<<endl;
//读取图片
src = imread(pic,IMREAD_GRAYSCALE);
src1 = imread(pic1,IMREAD_GRAYSCALE);
//判断图片是否存在
if(src.empty() || src1.empty())
{
cout<<"pic is not exist!!!!"<<endl;
return -1;
}
//显示图片
namedWindow("src pic",WINDOW_AUTOSIZE);
imshow("src pic",src);
namedWindow("src1 pic",WINDOW_AUTOSIZE);
imshow("src1 pic",src1);
int minHessian = 400;
vector<KeyPoint> keypoint1,keypoint2; //描述子
Mat descriptor1,descriptor2; //描述图像
Ptr<SURF> detector = SURF::create(minHessian); //创建SURF对象
//计算特征值
detector->detectAndCompute(src,Mat(),keypoint1,descriptor1);
detector->detectAndCompute(src1,Mat(),keypoint2,descriptor2);
BFMatcher matcher;
vector<DMatch> matches;
matcher.match(descriptor1,descriptor2,matches);
Mat matchimages;
drawMatches(src,keypoint1,src1,keypoint2,matches,matchimages);
imshow("matchImages",matchimages);
waitKey(0);
destroyAllWindows();
return 0;
}
最近邻搜索的问题在图像识别、数据压缩、模式识别和分类、机器学习、文档检索系统、统计和数据分析等方面是一个重大问题,在高维空间中解决这个问题似乎是一个非常难以执行的任务,没有算法明显优于标准的蛮力搜索,因此越来越多的人把兴趣点转向执行最近邻搜索的一类算法。
FLANN(Fast Library for Approximate Nearest Neighbors)时目前最完整的近似近邻开源库,不但实现了一系列查找算法还包含了一种自动选取最快算法的机制。
opencv中提供了函数FlannBasedMatcher()函数
#include
#include
#include
using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;
#define PIC_PATH "/work/opencv_pic/"
#define PIC_NAME "opencv.jpg"
#define PIC_PATH1 "/work/opencv_pic/"
#define PIC_NAME1 "opencvbkp.jpg"
int main(void)
{
Mat src,src1;
//获取完整的图片路径及名称
string pic = string(PIC_PATH1)+string(PIC_NAME1);
string pic1 = string(PIC_PATH)+string(PIC_NAME);
//打印图片路径
cout << "pic path is :"<<pic<<endl;
cout << "pic1 path is :"<<pic1<<endl;
//读取图片
src = imread(pic,IMREAD_GRAYSCALE);
src1 = imread(pic1,IMREAD_GRAYSCALE);
//判断图片是否存在
if(src.empty() || src1.empty())
{
cout<<"pic is not exist!!!!"<<endl;
return -1;
}
//显示图片
namedWindow("src pic",WINDOW_AUTOSIZE);
imshow("src pic",src);
namedWindow("src1 pic",WINDOW_AUTOSIZE);
imshow("src1 pic",src1);
int minHessian = 400;
vector<KeyPoint> keypoint1,keypoint2; //描述子
Mat descriptor1,descriptor2; //描述图像
Ptr<SURF> detector = SURF::create(minHessian); //创建SURF对象
//计算特征值
detector->detectAndCompute(src,Mat(),keypoint1,descriptor1);
detector->detectAndCompute(src1,Mat(),keypoint2,descriptor2);
//BFMatcher matcher;
FlannBasedMatcher matcher; //Flann匹配器
vector<DMatch> matches; //匹配数据
matcher.match(descriptor1,descriptor2,matches); //描述匹配 将匹配结果存放至matches
//flann匹配基于距离匹配 进行最优距离查找
float maxdist = 3;
float mindist = 100;
//通过逐步收敛的办法查找到最大值最小值
for(int i=0;i<descriptor1.rows;i++)
{
float distance = matches[i].distance;
distance*=100;
cout<<"distance: "<<distance<<endl;
if(distance>maxdist)
maxdist = distance;
if(distance<mindist)
mindist = distance;
}
//将最大值 最小值打印出来
cout<<"maxdist: "<<maxdist<<endl;
cout<<"mindist: "<<mindist<<endl;
vector<DMatch> goodmatches; //定义最优的距离点集合
for(int i=0;i<descriptor1.rows;i++)
{
float distance = matches[i].distance;
if(distance*100<=2*mindist)
{
//将查找到的最小距离添加到goodmatches中
goodmatches.push_back(matches[i]);
}
}
Mat matchimages;
//绘制匹配点 点数大大减少
drawMatches(src,keypoint1,src1,keypoint2,goodmatches,matchimages);
imshow("matchImages",matchimages);
waitKey(0);
destroyAllWindows();
return 0;
}