/* * Vocabulary.cpp * * Created on: 2014-05-09 * Author: mathieu */ #include "Vocabulary.h" #include "Settings.h" #include #include Vocabulary::Vocabulary() { } Vocabulary::~Vocabulary() { } void Vocabulary::clear() { descriptors_ = cv::Mat(); wordToObjects_.clear(); } QMultiMap Vocabulary::addWords(const cv::Mat & descriptors, int objectIndex, bool incremental) { QMultiMap words; if (descriptors.empty()) { return words; } if(incremental) { int k = 2; cv::Mat results(descriptors.rows, k, CV_32SC1); // results index cv::Mat dists(descriptors.rows, k, CV_32FC1); // Distance results are CV_32FC1 bool globalSearch = false; if(!descriptors_.empty() && descriptors_.rows >= (int)k) { flannIndex_.knnSearch(descriptors, results, dists, k, Settings::getFlannSearchParams() ); globalSearch = true; } QVector newWordsId; // index global cv::Mat newWords; int matches = 0; for(int i = 0; i < descriptors.rows; ++i) { QMap fullResults; // nearest descriptors sorted by distance if(newWords.rows) { // Check if this descriptor matches with a word not already added to the vocabulary cv::flann::Index tmpIndex; cv::flann::IndexParams * params; if(descriptors.type()==CV_8U) { params = Settings::createFlannIndexParams(); // should be LSH } else { params = new cv::flann::LinearIndexParams(); // faster } tmpIndex.build(newWords, *params, Settings::getFlannDistanceType()); delete params; cv::Mat tmpResults(1, newWords.rows>1?k:1, CV_32SC1); // results index cv::Mat tmpDists(1, newWords.rows>1?k:1, CV_32FC1); // Distance results are CV_32FC1 tmpIndex.knnSearch(descriptors.row(i), tmpResults, tmpDists, newWords.rows>1?k:1, Settings::getFlannSearchParams()); for(int j = 0; j < (newWords.rows>1?k:1); ++j) { fullResults.insert(tmpDists.at(0,j), newWordsId.at(tmpResults.at(0,j))); } } if(globalSearch) { for(int j=0; j(i,j), results.at(i,j)); } } bool match = false; // Apply NNDR if(fullResults.size() >= 2 && fullResults.begin().key() <= Settings::getNearestNeighbor_4nndrRatio() * (++fullResults.begin()).key()) { match = true; } if(match) { words.insert(fullResults.begin().value(), i); wordToObjects_.insert(fullResults.begin().value(), objectIndex); ++matches; } else { cv::Mat tmp(newWords.rows+1, descriptors.cols, descriptors.type()); if(newWords.rows) { cv::Mat dest(tmp, cv::Range(0, newWords.rows)); newWords.copyTo(dest); } cv::Mat dest(tmp, cv::Range(newWords.rows, newWords.rows+1)); descriptors.row(i).copyTo(dest); newWordsId.push_back(descriptors_.rows + newWords.rows); newWords = tmp; words.insert(newWordsId.back(), i); wordToObjects_.insert(newWordsId.back(), objectIndex); } } //printf("matches = %d\n", matches); //concatenate new words if(newWords.rows) { cv::Mat tmp(descriptors_.rows+newWords.rows, descriptors.cols, descriptors.type()); if(descriptors_.rows) { cv::Mat dest(tmp, cv::Range(0, descriptors_.rows)); descriptors_.copyTo(dest); } cv::Mat dest(tmp, cv::Range(descriptors_.rows, descriptors_.rows+newWords.rows)); newWords.copyTo(dest); descriptors_ = tmp; } //update this->update(); } else { for(int i = 0; i < descriptors.rows; ++i) { wordToObjects_.insert(descriptors_.rows+i, objectIndex); words.insert(descriptors_.rows+i, i); } //just concatenate descriptors cv::Mat tmp(descriptors_.rows+descriptors.rows, descriptors.cols, descriptors.type()); if(descriptors_.rows) { cv::Mat dest(tmp, cv::Range(0, descriptors_.rows)); descriptors_.copyTo(dest); } cv::Mat dest(tmp, cv::Range(descriptors_.rows, descriptors_.rows+descriptors.rows)); descriptors.copyTo(dest); descriptors_ = tmp; } return words; } void Vocabulary::update() { if(!descriptors_.empty()) { cv::flann::IndexParams * params = Settings::createFlannIndexParams(); flannIndex_.build(descriptors_, *params, Settings::getFlannDistanceType()); delete params; } } void Vocabulary::search(const cv::Mat & descriptors, cv::Mat & results, cv::Mat & dists, int k) { if(!descriptors_.empty()) { flannIndex_.knnSearch(descriptors, results, dists, k, Settings::getFlannSearchParams()); } }