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
相關內容:www.icvpr.com
------------------------------------------
< 轉載請註明:http://blog.csdn.net/icvpr >