OpenCV_局部图像特征的提取与匹配_源代码

OpenCV的feature2d module中提供了从局部图像特征(Local image feature)的检测、特征向量(feature vector)的提取,到特征匹配的实现。其中的局部图像特征包括了常用的几种局部图像特征检测与描述算子,如FAST、SURF、SIFT、以及ORB。对于高维特征向量之间的匹配,OpenCV主要有两种方式:1)BruteForce穷举法;2)FLANN近似K近邻算法(包含了多种高维特征向量匹配的算法,例如随机森林等)。


feature2d module: http://docs.opencv.org/modules/features2d/doc/features2d.html

OpenCV FLANN: http://docs.opencv.org/modules/flann/doc/flann.html

FLANN: http://www.cs.ubc.ca/~mariusm/index.php/FLANN/FLANN



下面的这段代码实现了基于OpenCV的局部图像特征检测、特征向量提取、以及高维特征向量的匹配功能。


版本:OpenCV2.4.2 


// LocalFeature.h

// 局部图像特征提取与匹配
// Author:  www.icvpr.com
// Blog  :  http://blog.csdn.net/icvpr
	
#ifndef _FEATURE_H_ 
#define _FEATURE_H_

#include <iostream>
#include <vector>
#include <string>

#include <opencv2/opencv.hpp>

using namespace cv;
using namespace std;

class Feature
{
public:
	Feature();
	~Feature();

	Feature(const string& detectType, const string& extractType, const string& matchType);

public:
	
	void detectKeypoints(const Mat& image, vector<KeyPoint>& keypoints);   // 检测特征点
	void extractDescriptors(const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptor);   // 提取特征向量
	void bestMatch(const Mat& queryDescriptor, Mat& trainDescriptor, vector<DMatch>& matches);  // 最近邻匹配
	void knnMatch(const Mat& queryDescriptor, Mat& trainDescriptor, vector<vector<DMatch>>& matches, int k);   // K近邻匹配

	void saveKeypoints(const Mat& image, const vector<KeyPoint>& keypoints, const string& saveFileName = "");  // 保存特征点
	void saveMatches(const Mat& queryImage,
			 const vector<KeyPoint>& queryKeypoints,
			 const Mat& trainImage,
			 const vector<KeyPoint>& trainKeypoints,
			 const vector<DMatch>& matches,
			 const string& saveFileName = "");   // 保存匹配结果到图片中

private:
	Ptr<FeatureDetector> m_detector;
	Ptr<DescriptorExtractor> m_extractor;
	Ptr<DescriptorMatcher> m_matcher;

	string m_detectType;
	string m_extractType;
	string m_matchType;

};

#endif

// LocalFeature.cpp

//  局部图像特征提取与匹配  
//  Author:  www.icvpr.com
//  Blog  :  http://blog.csdn.net/icvpr

#include "LocalFeature.h"

Feature::Feature()
{
	m_detectType = "SIFT";
	m_extractType = "SIFT";
	m_matchType = "FruteForce";
	initModule_nonfree(); 
}

Feature::~Feature()
{

}


Feature::Feature(const string& detectType, const string& extractType, const string& matchType)
{
	assert(!detectType.empty());
	assert(!extractType.empty());
	assert(!matchType.empty());

	m_detectType = detectType;
	m_extractType = extractType;
	m_matchType = matchType;
	initModule_nonfree(); 
}


void Feature::detectKeypoints(const Mat& image, std::vector<KeyPoint>& keypoints) 
{
	assert(image.type() == CV_8UC1);
	assert(!m_detectType.empty());

	keypoints.clear();
	m_detector = FeatureDetector::create(m_detectType);
	m_detector->detect(image, keypoints);

}



void Feature::extractDescriptors(const Mat& image, std::vector<KeyPoint>& keypoints, Mat& descriptor)
{
	assert(image.type() == CV_8UC1);
	assert(!m_extractType.empty());

	m_extractor = DescriptorExtractor::create(m_extractType);
	m_extractor->compute(image, keypoints, descriptor);

}


void Feature::bestMatch(const Mat& queryDescriptor, Mat& trainDescriptor, std::vector<DMatch>& matches) 
{
	assert(!queryDescriptor.empty());
	assert(!trainDescriptor.empty());
	assert(!m_matchType.empty());

	matches.clear();

	m_matcher = DescriptorMatcher::create(m_matchType);
	m_matcher->add(std::vector<Mat>(1, trainDescriptor));
	m_matcher->train();
	m_matcher->match(queryDescriptor, matches);

}


void Feature::knnMatch(const Mat& queryDescriptor, Mat& trainDescriptor, std::vector<std::vector<DMatch>>& matches, int k)
{
	assert(k > 0);
	assert(!queryDescriptor.empty());
	assert(!trainDescriptor.empty());
	assert(!m_matchType.empty());

	matches.clear();

	m_matcher = DescriptorMatcher::create(m_matchType);
	m_matcher->add(std::vector<Mat>(1, trainDescriptor));
	m_matcher->train();
	m_matcher->knnMatch(queryDescriptor, matches, k);

}



void Feature::saveKeypoints(const Mat& image, const vector<KeyPoint>& keypoints, const string& saveFileName)
{
	assert(!saveFileName.empty());

	Mat outImage;
	cv::drawKeypoints(image, keypoints, outImage, Scalar(255,255,0), DrawMatchesFlags::DRAW_RICH_KEYPOINTS );

	//
	string saveKeypointsImgName = saveFileName + "_" + m_detectType + ".jpg";
	imwrite(saveKeypointsImgName, outImage);

}



void Feature::saveMatches(const Mat& queryImage,
							const vector<KeyPoint>& queryKeypoints,
							const Mat& trainImage,
							const vector<KeyPoint>& trainKeypoints,
							const vector<DMatch>& matches,
							const string& saveFileName)
{
	assert(!saveFileName.empty());

	Mat outImage;
	cv::drawMatches(queryImage, queryKeypoints, trainImage, trainKeypoints, matches, outImage, 
				Scalar(255, 0, 0), Scalar(0, 255, 255), vector<char>(),  DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

	//
	string saveMatchImgName = saveFileName + "_" + m_detectType + "_" + m_extractType + "_" + m_matchType + ".jpg";
	imwrite(saveMatchImgName, outImage);
}

// 测试代码  main.cpp

//  局部图像特征提取与匹配  
//  Author:  www.icvpr.com  
//  Blog  : http://blog.csdn.net/icvpr    
  
#include   
#include   
#include <opencv2/opencv.hpp>  
  
using namespace cv;  
using namespace std;  
  
#include "LocalFeature.h"  
  
int main(int argc, char** argv)  
{  
	if (argc != 6)  
	{  
		cout << "wrong usage!" << endl;  
		cout << "usage: .exe FAST SIFT BruteForce queryImage trainImage" << endl;  
		return -1;  
	}  
  
	string detectorType = argv[1];  
	string extractorType = argv[2];  
	string matchType = argv[3];  
	string queryImagePath = argv[4];  
	string trainImagePath = argv[5];  
	  
	Mat queryImage = imread(queryImagePath, CV_LOAD_IMAGE_GRAYSCALE);  
	if (queryImage.empty())  
	{  
		cout<<"read failed"<< endl;  
		return -1;  
	}  
	  
	Mat trainImage = imread(trainImagePath, CV_LOAD_IMAGE_GRAYSCALE);  
	if (trainImage.empty())  
	{  
		cout<<"read failed"<< endl;  
		return -1;  
	}  
	  
	Feature feature(detectorType, extractorType, matchType);  
	  
	vector queryKeypoints, trainKeypoints;  
	feature.detectKeypoints(queryImage, queryKeypoints);  
	feature.detectKeypoints(trainImage, trainKeypoints);  
	  
	Mat queryDescriptor, trainDescriptor;  
	  
	feature.extractDescriptors(queryImage, queryKeypoints, queryDescriptor);  
	feature.extractDescriptors(trainImage, trainKeypoints, trainDescriptor);  
	  
	vector matches;  
	feature.bestMatch(queryDescriptor, trainDescriptor, matches);  
	  
	vector<vector> knnmatches;  
	feature.knnMatch(queryDescriptor, trainDescriptor, knnmatches, 2);  
	  
	Mat outImage;  
	feature.saveMatches(queryImage, queryKeypoints, trainImage, trainKeypoints, matches, "../");  
	  
	return 0;  
}  

下面是对不同的局部图像特征检测算子的实验对比结果:

(说明:这里只是简单地对各个局部图像特征检测算子进行了对比,实际应用中需要考虑不同检测算子的特点,以及所应用的场景来选择。)


1. FAST+SIFT+FLANN (即局部图像特征检测算子+特征向量描述算子+高维特征向量匹配方法)



2. HARRIS+SIFT+FLANN


3. SURF+SIFT+FLANN


4. MSER+SIFT+FLANN


5. STAR+SIFT+FLANN


6.SIFT+SIFT+FLANN


7. ORB+ORB+FLANN


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值