您的位置:首页 > 编程语言

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

2015-08-12 08:27 661 查看
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.6

#pragma once

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

#include <opencv2/opencv.hpp>
#include <opencv2/nonfree/nonfree.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;
};
Feature.cpp:

#include "Feature.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);
//	imshow(saveMatchImgName, outImage);
//	waitKey(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



< 转载请注明:http://blog.csdn.net/icvpr >
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: