计算机视觉
图像处理

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

#ifndef _FEATURE_H_ 
#define _FEATURE_H_

#include 
#include 
#include 

#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& keypoints);   // 检测特征点
	void extractDescriptors(const Mat& image, vector& keypoints, Mat& descriptor);   // 提取特征向量
	void bestMatch(const Mat& queryDescriptor, Mat& trainDescriptor, vector& matches);  // 最近邻匹配
	void knnMatch(const Mat& queryDescriptor, Mat& trainDescriptor, vector<vector>& matches, int k);   // K近邻匹配

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

private:
	Ptr m_detector;
	Ptr m_extractor;
	Ptr m_matcher;

	string m_detectType;
	string m_extractType;
	string m_matchType;

};


#endif

LocalFeature.cpp

#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& 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& 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& matches) 
{
	assert(!queryDescriptor.empty());
	assert(!trainDescriptor.empty());
	assert(!m_matchType.empty());

	matches.clear();

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

}


void Feature::knnMatch(const Mat& queryDescriptor, Mat& trainDescriptor, std::vector<std::vector>& 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(1, trainDescriptor));
	m_matcher->train();
	m_matcher->knnMatch(queryDescriptor, matches, k);

}



void Feature::saveKeypoints(const Mat& image, const vector& 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& queryKeypoints,
							const Mat& trainImage,
							const vector& trainKeypoints,
							const vector& 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(),  DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);

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

测试代码, main.cpp

#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 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

转载注明来源:CV视觉网 » OpenCV局部图像特征的提取与匹配

分享到:更多 ()
扫描二维码,给作者 打赏
pay_weixinpay_weixin

请选择你看完该文章的感受:

0不错 1超赞 0无聊 1扯淡 0不解 0路过

评论 20

评论前必须登录!