Анализ ключевых точек с помощью C++ и OpenCV
У меня есть вопрос по поводу следующего кода:
#include "iostream"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <opencv2/nonfree/features2d.hpp>
#include <opencv2/flann/flann.hpp>
#include "opencv2/flann/miniflann.hpp"
#include <opencv2/legacy/legacy.hpp>
#include "opencv2/contrib/contrib.hpp"
#include "opencv2/objdetect/objdetect.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/imgproc/types_c.h"
#include "opencv2/highgui/highgui_c.h"
#include "opencv2/core/version.hpp"
#include "opencv2/core/operations.hpp"
#include "opencv2/core/mat.hpp"
#include "opencv2/core/types_c.h"
#include <limits>
#include <vector>
#include <iostream>
#include <fstream>
using namespace cv;
using namespace std;
static void readTrainFilenames( const string& filename, string& dirName, vector<string>& trainFilenames )
{
trainFilenames.clear();
ifstream file( filename.c_str() );
if ( !file.is_open() )
return;
size_t pos = filename.rfind('\\');
char dlmtr = '\\';
if (pos == String::npos)
{
pos = filename.rfind('/');
dlmtr = '/';
}
dirName = pos == string::npos ? "" : filename.substr(0, pos) + dlmtr;
while( !file.eof() )
{
string str; getline( file, str );
if( str.empty() ) break;
trainFilenames.push_back(str);
}
file.close();
}
static bool createDetectorDescriptorMatcher( const string& detectorType, const string& descriptorType, const string& matcherType,
Ptr<FeatureDetector>& featureDetector,
Ptr<DescriptorExtractor>& descriptorExtractor,
Ptr<DescriptorMatcher>& descriptorMatcher )
{
cout << "< Creating feature detector, descriptor extractor and descriptor matcher ..." << endl;
featureDetector = FeatureDetector::create( detectorType );
descriptorExtractor = DescriptorExtractor::create( descriptorType );
descriptorMatcher = DescriptorMatcher::create( matcherType );
cout << ">" << endl;
bool isCreated = !( featureDetector.empty() || descriptorExtractor.empty() || descriptorMatcher.empty() );
if( !isCreated )
cout << "Can not create feature detector or descriptor extractor or descriptor matcher of given types." << endl << ">" << endl;
return isCreated;
}
static bool readImages( const string& queryImageName, const string& trainFilename,
Mat& queryImage, vector <Mat>& trainImages, vector<string>& trainImageNames )
{
cout << "< Reading the images..." << endl;
queryImage = imread( queryImageName);
if( queryImage.empty() )
{
cout << "Query image can not be read." << endl << ">" << endl;
return false;
}
string trainDirName;
readTrainFilenames( trainFilename, trainDirName, trainImageNames );
if( trainImageNames.empty() )
{
cout << "Train image filenames can not be read." << endl << ">" << endl;
return false;
}
int readImageCount = 0;
for( size_t i = 0; i < trainImageNames.size(); i++ )
{
string filename = trainDirName + trainImageNames[i];
Mat img = imread( filename );
if( img.empty() )
cout << "Train image " << filename << " can not be read." << endl;
else {
readImageCount++;
double min, max;
minMaxLoc(img, &min, &max);
if (min!=max) {
trainImages.push_back( img );
}
}
}
if( !readImageCount )
{
cout << "All train images can not be read." << endl << ">" << endl;
return false;
}
else
cout << readImageCount << " train images were read." << endl;
cout << ">" << endl;
return true;
}
static void detectKeypoints( const Mat& queryImage, vector<KeyPoint>& queryKeypoints,
const vector<Mat>& trainImages, vector<vector<KeyPoint> >& trainKeypoints,
Ptr<FeatureDetector>& featureDetector )
{
TickMeter tm;
tm.start();
cout << endl << "< Extracting keypoints from images..." << endl;
featureDetector->detect( queryImage, queryKeypoints );
featureDetector->detect( trainImages, trainKeypoints );
cout << ">" << endl;
tm.stop();
double exttime = tm.getTimeMilli();
cout << "Extraction time: " << exttime << endl;
}
static void computeDescriptors( const Mat& queryImage, vector<KeyPoint>& queryKeypoints, Mat& queryDescriptors,
const vector<Mat>& trainImages, vector<vector<KeyPoint> >& trainKeypoints, vector<Mat>& trainDescriptors,
Ptr<DescriptorExtractor>& descriptorExtractor )
{
TickMeter tm;
tm.start();
cout << "< Computing descriptors for keypoints..." << endl;
descriptorExtractor->compute( queryImage, queryKeypoints, queryDescriptors );
descriptorExtractor->compute( trainImages, trainKeypoints, trainDescriptors );
int totalTrainDesc = 0;
for( vector<Mat>::const_iterator tdIter = trainDescriptors.begin(); tdIter != trainDescriptors.end(); tdIter++ )
totalTrainDesc += tdIter->rows;
cout << "Query descriptors count: " << queryDescriptors.rows << "; Total train descriptors count: " << totalTrainDesc << endl;
cout << ">" << endl;
tm.stop();
double exttime = tm.getTimeMilli();
cout << "Description time: " << exttime << endl;
}
static void matchDescriptors( const Mat& queryDescriptors, const vector<Mat>& trainDescriptors,
vector<DMatch>& matches, Ptr<DescriptorMatcher>& descriptorMatcher )
{
cout << "< Set train descriptors collection in the matcher and match query descriptors to them..." << endl;
TickMeter tm;
tm.start();
descriptorMatcher->add( trainDescriptors );
descriptorMatcher->train();
tm.stop();
double buildTime = tm.getTimeMilli();
tm.start();
descriptorMatcher->match( queryDescriptors, matches );
tm.stop();
double matchTime = tm.getTimeMilli();
CV_Assert( queryDescriptors.rows == (int)matches.size() || matches.empty() );
cout << "Number of matches: " << matches.size() << endl;
cout << "Build time: " << buildTime << " ms; Match time: " << matchTime << " ms" << endl;
cout << ">" << endl;
}
int main(int argc, char** argv)
{
string detectorType = "SURF";
string descriptorType = "SURF";
string matcherType = "FlannBased";
string fileWithTrainImages = "/home/juan/workspace/keypoint/Debug/matching_to_many_images/train/keyframes.txt";
string dirToSaveResImages = "/home/juan/workspace/keypoint/Debug/matching_to_many_images/results";
string queryImageName = "/home/juan/workspace/keypoint/Debug/keyframe0.jpg";
Ptr<FeatureDetector> featureDetector;
Ptr<DescriptorExtractor> descriptorExtractor;
Ptr<DescriptorMatcher> descriptorMatcher;
createDetectorDescriptorMatcher( detectorType, descriptorType, matcherType, featureDetector, descriptorExtractor, descriptorMatcher );
Mat queryImage;
vector<Mat> trainImages;
vector<string> trainImagesNames;
if( !readImages( queryImageName, fileWithTrainImages, queryImage, trainImages, trainImagesNames ) )
{
cout << "Error!!" << endl;
return -1;
}
vector<KeyPoint> queryKeypoints;
vector<vector<KeyPoint> > trainKeypoints;
detectKeypoints( queryImage, queryKeypoints, trainImages, trainKeypoints, featureDetector );
Mat queryDescriptors;
vector<Mat> trainDescriptors;
computeDescriptors( queryImage, queryKeypoints, queryDescriptors,
trainImages, trainKeypoints, trainDescriptors,
descriptorExtractor );
vector<DMatch> matches;
matchDescriptors( queryDescriptors, trainDescriptors, matches, descriptorMatcher );
return 0;
}
Основная функциональность программы: читает изображение запроса и набор изображений поезда. Затем он обнаруживает ключевые точки с использованием установленного детектора типа (SURF, SIFT, FAST...). После этого он извлекает дескрипторы этих ключевых точек, используя установленный тип дескриптора (FREAK, SIFT...). Наконец, приведены соответствия между изображением запроса и всем набором изображений поездов на основе соответствия, установленного переменной matcherType (BruteForce, FlannBased...). Моя проблема в том, что я пытался использовать все типы детекторов, дескрипторов и сопоставителей (переменные DetectorType, DescriptorType, MatcherType), которые OpenCV предоставляет в своих методах. Тем не менее, я получил результаты только с несколькими из них. Например, комбинация Detector-Descriptor-Matcher "SURF-SURF-FlannBased" не работает для меня и выдает мне следующую ошибку:
juan @ juan-HP-G62-NoteBook-PC: ~ / рабочая область /keypoint/Debug$ ./keypoint<Создание детектора признаков, экстрактора дескриптора и средства сопоставления дескрипторов...
Невозможно создать детектор признаков или экстрактор дескрипторов или сопоставитель дескрипторов заданных типов. <Чтение изображений... Было прочитано 77 изображений поездов.
<Извлечение ключевых точек из изображений... Violación de segmento (`core 'generado)
Тем не менее, сочетание FAST-FREAK-BruteForce прекрасно работает для меня:
<Создание детектора признаков, экстрактора дескриптора и сопоставителя дескриптора...
<Чтение изображений... Было прочитано 77 изображений поездов.
<Извлечение ключевых точек из изображений...
Время извлечения: 374.277<Вычислительные дескрипторы для ключевых точек... Количество дескрипторов запросов: 786; Общее количество дескрипторов поездов: 154417 Время описания: 1489.24 <Установить коллекцию дескрипторов поездов в сопоставителе и сопоставить с ними дескрипторы запросов... Количество совпадений: 786 Время сборки: 0,024077 мс; Время матча: 14292,6 мс
Я использую OpenCV 2.4.9, с Eclipse как IDE и Linux как SO. Может кто-нибудь мне помочь? Я очень заинтересован в использовании сопоставителя FlannBased для работы с большой базой данных сравнений, поскольку сопоставитель BruteForce работает хорошо, но в этой ситуации он работает очень медленно. Спасибо!