38 #include <opencv2/opencv_modules.hpp> 40 #if CV_MAJOR_VERSION < 3 41 #ifdef HAVE_OPENCV_GPU 42 #include <opencv2/gpu/gpu.hpp> 45 #include <opencv2/core/cuda.hpp> 46 #ifdef HAVE_OPENCV_CUDAFEATURES2D 47 #include <opencv2/cudafeatures2d.hpp> 64 _totalActiveReferences(0),
65 _incrementalDictionary(
Parameters::defaultKpIncrementalDictionary()),
66 _incrementalFlann(
Parameters::defaultKpIncrementalFlann()),
67 _rebalancingFactor(
Parameters::defaultKpFlannRebalancingFactor()),
69 _dictionaryPath(
Parameters::defaultKpDictionaryPath()),
70 _newWordsComparedTogether(
Parameters::defaultKpNewWordsComparedTogether()),
72 useDistanceL1_(
false),
74 _strategy(kNNBruteForce)
88 ParametersMap::const_iterator iter;
98 if((iter=parameters.find(Parameters::kKpDictionaryPath())) != parameters.end())
100 dictionaryPath = (*iter).second.c_str();
102 if((iter=parameters.find(Parameters::kKpIncrementalDictionary())) != parameters.end())
104 incrementalDictionary =
uStr2Bool((*iter).second.c_str());
108 if((iter=parameters.find(Parameters::kKpNNStrategy())) != parameters.end())
114 if(incrementalDictionary)
132 UWARN(
"Incremental dictionary set: already loaded visual words (%d) from the fixed dictionary will be included in the incremental one.",
_visualWords.size());
140 if(!dictionaryPath.empty())
145 UDEBUG(
"incremental=%d, oldPath=%s newPath=%s, visual words=%d",
150 UDEBUG(
"Loading fixed vocabulary \"%s\", this may take a while...", dictionaryPath.c_str());
152 if(driver->openConnection(dictionaryPath,
false))
154 driver->load(
this,
false);
157 iter->second->setSaved(
true);
160 driver->closeConnection(
false);
164 UERROR(
"Could not load dictionary from database %s", dictionaryPath.c_str());
170 UWARN(
"Loading fixed vocabulary \"%s\", this may take a while...", dictionaryPath.c_str());
172 file.open(dictionaryPath.c_str(), std::ifstream::in);
175 UDEBUG(
"Deleting old dictionary and loading the new one from \"%s\"", dictionaryPath.c_str());
180 std::list<std::string> strList;
181 std::getline(file, str);
184 for(std::list<std::string>::iterator iter = strList.begin(); iter != strList.end(); ++iter)
188 dimension = std::atoi(iter->c_str());
192 UDEBUG(
"descriptor dimension = %d", dimension);
194 if(dimension <= 0 || dimension > 1000)
196 UERROR(
"Invalid dictionary file, visual word dimension (%d) is not valid, \"%s\"", dimension, dictionaryPath.c_str());
203 std::getline(file, str);
205 if((
int)strList.size() == dimension+1)
208 std::list<std::string>::iterator iter = strList.begin();
209 int id = std::atoi(iter->c_str());
210 cv::Mat descriptor(1, dimension, CV_32F);
215 for(;i<dimension && iter != strList.end(); ++i, ++iter)
221 UERROR(
"Loaded word has not the same size (%d) than descriptor size previously detected (%d).", i, dimension);
230 else if(!str.empty())
232 UWARN(
"Cannot parse line \"%s\"", str.c_str());
243 UERROR(
"Cannot open dictionary file \"%s\"", dictionaryPath.c_str());
251 UWARN(
"No words loaded, cannot set a fixed dictionary.", (
int)
_visualWords.size());
262 UDEBUG(
"Dictionary \"%s\" already loaded...", dictionaryPath.c_str());
266 UERROR(
"Cannot change to a fixed dictionary if there are already words (%d) in the incremental one.",
_visualWords.size());
271 UWARN(
"Cannot change to fixed dictionary, %d words already loaded as incremental", (
int)
_visualWords.size());
284 #if CV_MAJOR_VERSION < 3 285 #ifdef HAVE_OPENCV_GPU 288 UERROR(
"Nearest neighobr strategy \"kNNBruteForceGPU\" chosen but no CUDA devices found! Doing \"kNNBruteForce\" instead.");
294 UERROR(
"Nearest neighobr strategy \"kNNBruteForceGPU\" chosen but OpenCV is not built with GPU/cuda module! Doing \"kNNBruteForce\" instead.");
299 #ifdef HAVE_OPENCV_CUDAFEATURES2D 302 UERROR(
"Nearest neighobr strategy \"kNNBruteForceGPU\" chosen but no CUDA devices found! Doing \"kNNBruteForce\" instead.");
308 UERROR(
"Nearest neighobr strategy \"kNNBruteForceGPU\" chosen but OpenCV cudafeatures2d module is not found! Doing \"kNNBruteForce\" instead.");
405 UDEBUG(
"Building FLANN index...");
412 UASSERT_MSG(descriptor.type() == CV_32F,
"To use KdTree dictionary, float descriptors are required!");
416 UASSERT_MSG(descriptor.type() == CV_8U,
"To use LSH dictionary, binary descriptors are required!");
420 UFATAL(
"Not supposed to be here!");
423 UDEBUG(
"Building FLANN index... done!");
431 std::pair<std::map<int, int>::iterator,
bool> inserted;
432 inserted =
_mapIndexId.insert(std::pair<int, int>(index, w->
id()));
434 inserted =
_mapIdIndex.insert(std::pair<int, int>(w->
id(), index));
457 std::pair<std::map<int, int>::iterator,
bool> inserted =
_mapIdIndex.insert(std::pair<int, int>(w->
id(), i));
475 if(
_visualWords.begin()->second->getDescriptor().type() == CV_8U)
484 type =
_visualWords.begin()->second->getDescriptor().type();
489 type =
_visualWords.begin()->second->getDescriptor().type();
491 int dim =
_visualWords.begin()->second->getDescriptor().cols;
493 UASSERT(type == CV_32F || type == CV_8U);
498 std::map<int, VisualWord*>::const_iterator iter =
_visualWords.begin();
499 for(
unsigned int i=0; i <
_visualWords.size(); ++i, ++iter)
502 if(iter->second->getDescriptor().type() == CV_8U)
506 iter->second->getDescriptor().convertTo(descriptor, CV_32F);
510 descriptor = iter->second->getDescriptor();
515 descriptor = iter->second->getDescriptor();
518 UASSERT(descriptor.cols == dim);
519 UASSERT(descriptor.type() == type);
535 UASSERT_MSG(type == CV_32F,
"To use KdTree dictionary, float descriptors are required!");
539 UASSERT_MSG(type == CV_8U,
"To use LSH dictionary, binary descriptors are required!");
549 UDEBUG(
"Dictionary updated! (size=%d added=%d removed=%d)",
554 UDEBUG(
"Dictionary has not changed, so no need to update it! (size=%d)",
_dataTree.rows);
564 if(printWarningsIfNotEmpty)
568 UWARN(
"Visual dictionary would be already empty here (%d words still in dictionary).", (
int)
_visualWords.size());
572 UWARN(
"Not indexed words should be empty here (%d words still not indexed)", (
int)
_notIndexedWords.size());
637 UDEBUG(
"id=%d descriptors=%d", signatureId, descriptorsIn.rows);
639 std::list<int> wordIds;
640 if(descriptorsIn.rows == 0 || descriptorsIn.cols == 0)
642 UERROR(
"Descriptors size is null!");
648 UERROR(
"Dictionary mode is set to fixed but no words are in it!");
657 dim =
_visualWords.begin()->second->getDescriptor().cols;
658 type =
_visualWords.begin()->second->getDescriptor().type();
659 UASSERT(type == CV_32F || type == CV_8U);
661 if(dim && dim != descriptorsIn.cols)
663 UERROR(
"Descriptors (size=%d) are not the same size as already added words in dictionary(size=%d)", descriptorsIn.cols, dim);
666 if(type>=0 && type != descriptorsIn.type())
668 UERROR(
"Descriptors (type=%d) are not the same type as already added words in dictionary(type=%d)", descriptorsIn.type(), type);
674 if(descriptorsIn.type() == CV_8U)
679 descriptorsIn.convertTo(descriptors, CV_32F);
683 descriptors = descriptorsIn;
688 descriptors = descriptorsIn;
696 UASSERT(type == CV_32F || type == CV_8U);
699 if(dim && dim != descriptors.cols)
701 UERROR(
"Descriptors (size=%d) are not the same size as already added words in dictionary(size=%d)", descriptors.cols, dim);
705 if(type>=0 && type != descriptors.type())
707 UERROR(
"Descriptors (type=%d) are not the same type as already added words in dictionary(type=%d)", descriptors.type(), type);
711 int dupWordsCountFromDict= 0;
712 int dupWordsCountFromLast= 0;
717 std::vector<int> newWordsId;
721 std::vector<std::vector<cv::DMatch> > matches;
722 bool bruteForce =
false;
730 UDEBUG(
"newPts.total()=%d ", descriptors.rows);
739 cv::BFMatcher matcher(descriptors.type()==CV_8U?cv::NORM_HAMMING:cv::NORM_L2SQR);
740 matcher.knnMatch(descriptors,
_dataTree, matches, k);
745 #if CV_MAJOR_VERSION < 3 746 #ifdef HAVE_OPENCV_GPU 747 cv::gpu::GpuMat newDescriptorsGpu(descriptors);
748 cv::gpu::GpuMat lastDescriptorsGpu(
_dataTree);
749 if(descriptors.type()==CV_8U)
751 cv::gpu::BruteForceMatcher_GPU<cv::Hamming> gpuMatcher;
752 gpuMatcher.knnMatch(newDescriptorsGpu, lastDescriptorsGpu, matches, k);
756 cv::gpu::BruteForceMatcher_GPU<cv::L2<float> > gpuMatcher;
757 gpuMatcher.knnMatch(newDescriptorsGpu, lastDescriptorsGpu, matches, k);
760 UERROR(
"Cannot use brute Force GPU because OpenCV is not built with gpu module.");
763 #ifdef HAVE_OPENCV_CUDAFEATURES2D 764 cv::cuda::GpuMat newDescriptorsGpu(descriptors);
765 cv::cuda::GpuMat lastDescriptorsGpu(
_dataTree);
766 cv::Ptr<cv::cuda::DescriptorMatcher> gpuMatcher;
767 if(descriptors.type()==CV_8U)
769 gpuMatcher = cv::cuda::DescriptorMatcher::createBFMatcher(cv::NORM_HAMMING);
770 gpuMatcher->knnMatch(newDescriptorsGpu, lastDescriptorsGpu, matches, k);
774 gpuMatcher = cv::cuda::DescriptorMatcher::createBFMatcher(cv::NORM_L2);
775 gpuMatcher->knnMatch(newDescriptorsGpu, lastDescriptorsGpu, matches, k);
778 UERROR(
"Cannot use brute Force GPU because OpenCV is not built with cuda module.");
788 if(dists.type() == CV_32S)
791 dists.convertTo(temp, CV_32F);
795 UDEBUG(
"Time to find nn = %f s", timerLocal.
ticks());
799 for(
int i = 0; i < descriptors.rows; ++i)
801 std::multimap<float, int> fullResults;
802 if(!bruteForce && dists.cols)
804 for(
int j=0; j<dists.cols; ++j)
806 float d = dists.at<
float>(i,j);
808 if (
sizeof(
size_t) == 8)
810 index = *((
size_t*)&results.at<
double>(i, j));
814 index = *((
size_t*)&results.at<
int>(i, j));
817 if(d >= 0.0
f &&
id != 0)
819 fullResults.insert(std::pair<float, int>(d,
id));
827 else if(bruteForce && matches.size())
829 for(
unsigned int j=0; j<matches.at(i).size(); ++j)
831 float d = matches.at(i).at(j).distance;
833 if(d >= 0.0
f &&
id != 0)
835 fullResults.insert(std::pair<float, int>(d,
id));
847 std::vector<std::vector<cv::DMatch> > matchesNewWords;
848 cv::BFMatcher matcher(descriptors.type()==CV_8U?cv::NORM_HAMMING:
useDistanceL1_?cv::NORM_L1:cv::NORM_L2SQR);
849 UASSERT(descriptors.cols == newWords.cols && descriptors.type() == newWords.type());
850 matcher.knnMatch(descriptors.row(i), newWords, matchesNewWords, newWords.rows>1?2:1);
851 UASSERT(matchesNewWords.size() == 1);
852 for(
unsigned int j=0; j<matchesNewWords.at(0).size(); ++j)
854 float d = matchesNewWords.at(0).at(j).distance;
855 int id = newWordsId[matchesNewWords.at(0).at(j).trainIdx];
856 if(d >= 0.0
f &&
id != 0)
858 fullResults.insert(std::pair<float, int>(d,
id));
869 bool badDist =
false;
870 if(fullResults.size() == 0)
876 if(fullResults.size() >= 2)
879 if(fullResults.begin()->first >
_nndrRatio * (++fullResults.begin())->first)
896 newWords.push_back(descriptors.row(i));
897 newWordsId.push_back(vw->
id());
898 wordIds.push_back(vw->
id());
905 ++dupWordsCountFromLast;
909 ++dupWordsCountFromDict;
912 this->
addWordRef(fullResults.begin()->second, signatureId);
913 wordIds.push_back(fullResults.begin()->second);
916 else if(fullResults.size())
919 ++dupWordsCountFromDict;
920 this->
addWordRef(fullResults.begin()->second, signatureId);
921 wordIds.push_back(fullResults.begin()->second);
922 UASSERT(fullResults.begin()->second>0);
928 ULOGGER_DEBUG(
"%d duplicated words added (from current image = %d)...",
929 dupWordsCountFromDict+dupWordsCountFromLast, dupWordsCountFromLast);
943 int type = (*vws.begin())->getDescriptor().type();
944 int dim = (*vws.begin())->getDescriptor().cols;
946 if(dim !=
_visualWords.begin()->second->getDescriptor().cols)
948 UERROR(
"Descriptors (size=%d) are not the same size as already added words in dictionary(size=%d)", (*vws.begin())->getDescriptor().cols, dim);
949 return std::vector<int>(vws.size(), 0);
952 if(type !=
_visualWords.begin()->second->getDescriptor().type())
954 UERROR(
"Descriptors (type=%d) are not the same type as already added words in dictionary(type=%d)", (*vws.begin())->getDescriptor().type(), type);
955 return std::vector<int>(vws.size(), 0);
961 cv::Mat query(vws.size(), dim, type);
962 for(std::list<VisualWord *>::const_iterator iter=vws.begin(); iter!=vws.end(); ++iter, ++index)
976 return std::vector<int>(vws.size(), 0);
982 std::vector<int> resultIds(queryIn.rows, 0);
988 int dim =
_visualWords.begin()->second->getDescriptor().cols;
989 int type =
_visualWords.begin()->second->getDescriptor().type();
990 UASSERT(type == CV_32F || type == CV_8U);
992 if(dim != queryIn.cols)
994 UERROR(
"Descriptors (size=%d) are not the same size as already added words in dictionary(size=%d)", queryIn.cols, dim);
997 if(type != queryIn.type())
999 UERROR(
"Descriptors (type=%d) are not the same type as already added words in dictionary(type=%d)", queryIn.type(), type);
1005 if(queryIn.type() == CV_8U)
1009 queryIn.convertTo(query, CV_32F);
1026 UASSERT(type == CV_32F || type == CV_8U);
1029 if(dim && dim != query.cols)
1031 UERROR(
"Descriptors (size=%d) are not the same size as already added words in dictionary(size=%d)", query.cols, dim);
1035 if(type>=0 && type != query.type())
1037 UERROR(
"Descriptors (type=%d) are not the same type as already added words in dictionary(type=%d)", query.type(), type);
1041 std::vector<std::vector<cv::DMatch> > matches;
1042 bool bruteForce =
false;
1049 UDEBUG(
"query.rows=%d ", query.rows);
1058 cv::BFMatcher matcher(query.type()==CV_8U?cv::NORM_HAMMING:cv::NORM_L2SQR);
1059 matcher.knnMatch(query,
_dataTree, matches, k);
1064 #if CV_MAJOR_VERSION < 3 1065 #ifdef HAVE_OPENCV_GPU 1066 cv::gpu::GpuMat newDescriptorsGpu(query);
1067 cv::gpu::GpuMat lastDescriptorsGpu(
_dataTree);
1068 if(query.type()==CV_8U)
1070 cv::gpu::BruteForceMatcher_GPU<cv::Hamming> gpuMatcher;
1071 gpuMatcher.knnMatch(newDescriptorsGpu, lastDescriptorsGpu, matches, k);
1075 cv::gpu::BruteForceMatcher_GPU<cv::L2<float> > gpuMatcher;
1076 gpuMatcher.knnMatch(newDescriptorsGpu, lastDescriptorsGpu, matches, k);
1079 UERROR(
"Cannot use brute Force GPU because OpenCV is not built with gpu module.");
1082 #ifdef HAVE_OPENCV_CUDAFEATURES2D 1083 cv::cuda::GpuMat newDescriptorsGpu(query);
1084 cv::cuda::GpuMat lastDescriptorsGpu(
_dataTree);
1085 cv::Ptr<cv::cuda::DescriptorMatcher> gpuMatcher;
1086 if(query.type()==CV_8U)
1088 gpuMatcher = cv::cuda::DescriptorMatcher::createBFMatcher(cv::NORM_HAMMING);
1089 gpuMatcher->knnMatchAsync(newDescriptorsGpu, lastDescriptorsGpu, matches, k);
1093 gpuMatcher = cv::cuda::DescriptorMatcher::createBFMatcher(cv::NORM_L2);
1094 gpuMatcher->knnMatchAsync(newDescriptorsGpu, lastDescriptorsGpu, matches, k);
1097 UERROR(
"Cannot use brute Force GPU because OpenCV is not built with cuda module.");
1107 if(dists.type() == CV_32S)
1110 dists.convertTo(temp, CV_32F);
1116 std::map<int, int> mapIndexIdNotIndexed;
1117 std::vector<std::vector<cv::DMatch> > matchesNotIndexed;
1120 cv::Mat dataNotIndexed = cv::Mat::zeros(
_notIndexedWords.size(), query.cols, query.type());
1121 unsigned int index = 0;
1144 UASSERT(vw != 0 && descriptor.cols == query.cols && descriptor.type() == query.type());
1146 mapIndexIdNotIndexed.insert(mapIndexIdNotIndexed.end(), std::pair<int,int>(index, vw->
id()));
1151 cv::BFMatcher matcher(query.type()==CV_8U?cv::NORM_HAMMING:
useDistanceL1_?cv::NORM_L1:cv::NORM_L2SQR);
1152 matcher.knnMatch(query, dataNotIndexed, matchesNotIndexed, dataNotIndexed.rows>1?2:1);
1156 for(
int i=0; i<query.rows; ++i)
1158 std::multimap<float, int> fullResults;
1159 if(!bruteForce && dists.cols)
1161 for(
int j=0; j<dists.cols; ++j)
1163 float d = dists.at<
float>(i,j);
1166 if (
sizeof(
size_t) == 8)
1168 index = *((
size_t*)&results.at<
double>(i, j));
1172 index = *((
size_t*)&results.at<
int>(i, j));
1175 if(d >= 0.0
f &&
id != 0)
1177 fullResults.insert(std::pair<float, int>(d,
id));
1181 else if(bruteForce && matches.size())
1183 for(
unsigned int j=0; j<matches.at(i).size(); ++j)
1185 float d = matches.at(i).at(j).distance;
1187 if(d >= 0.0
f &&
id != 0)
1189 fullResults.insert(std::pair<float, int>(d,
id));
1195 if(matchesNotIndexed.size())
1197 for(
unsigned int j=0; j<matchesNotIndexed.at(i).size(); ++j)
1199 float d = matchesNotIndexed.at(i).at(j).distance;
1200 int id =
uValue(mapIndexIdNotIndexed, matchesNotIndexed.at(i).at(j).trainIdx);
1201 if(d >= 0.0
f &&
id != 0)
1203 fullResults.insert(std::pair<float, int>(d,
id));
1214 bool badDist =
false;
1215 if(fullResults.size() == 0)
1221 if(fullResults.size() >= 2)
1224 if(fullResults.begin()->first >
_nndrRatio * (++fullResults.begin())->first)
1237 resultIds[i] = fullResults.begin()->second;
1240 else if(fullResults.size())
1243 resultIds[i] = fullResults.begin()->second;
1265 if(_lastWordId < vw->
id())
1294 UDEBUG(
"Removing %d words from dictionary (current size=%d)", (
int)words.size(), (int)
_visualWords.size());
1295 for(
unsigned int i=0; i<words.size(); ++i)
1310 for(
unsigned int i=0; i<unusedWords.size(); ++i)
1312 delete unusedWords[i];
1321 UWARN(
"Dictionary is empty, cannot export it!");
1324 if(
_visualWords.begin()->second->getDescriptor().type() != CV_32FC1)
1326 UERROR(
"Exporting binary descriptors is not implemented!");
1332 fopen_s(&foutRef, fileNameReferences,
"w");
1333 fopen_s(&foutDesc, fileNameDescriptors,
"w");
1335 foutRef = fopen(fileNameReferences,
"w");
1336 foutDesc = fopen(fileNameDescriptors,
"w");
1341 fprintf(foutRef,
"WordID SignaturesID...\n");
1347 fprintf(foutDesc,
"WordID Descriptors...\n");
1352 fprintf(foutDesc,
"WordID Descriptors...%d\n", (*
_visualWords.begin()).second->getDescriptor().cols);
1362 fprintf(foutRef,
"%d ", (*iter).first);
1363 const std::map<int, int> ref = (*iter).second->getReferences();
1364 for(std::map<int, int>::const_iterator jter=ref.begin(); jter!=ref.end(); ++jter)
1366 for(
int i=0; i<(*jter).second; ++i)
1368 fprintf(foutRef,
"%d ", (*jter).first);
1371 fprintf(foutRef,
"\n");
1377 fprintf(foutDesc,
"%d ", (*iter).first);
1378 const float * desc = (
const float *)(*iter).second->getDescriptor().data;
1379 int dim = (*iter).second->getDescriptor().cols;
1381 for(
int i=0; i<dim; i++)
1383 fprintf(foutDesc,
"%f ", desc[i]);
1385 fprintf(foutDesc,
"\n");
static bool parse(const ParametersMap ¶meters, const std::string &key, bool &value)
void removePoint(unsigned int index)
std::vector< int > getUnusedWordIds() const
std::vector< K > uKeys(const std::multimap< K, V > &mm)
unsigned int getIndexMemoryUsed() const
bool uIsDigit(const char c)
int removeAllRef(int signatureId)
void buildLSHIndex(const cv::Mat &features, unsigned int table_number=12, unsigned int key_size=20, unsigned int multi_probe_level=2, float rebalancingFactor=2.0f)
bool UTILITE_EXP uStr2Bool(const char *str)
std::set< K > uKeysSet(const std::map< K, V > &m)
float UTILITE_EXP uStr2Float(const std::string &str)
void knnSearch(const cv::Mat &query, cv::Mat &indices, cv::Mat &dists, int knn, int checks=32, float eps=0.0, bool sorted=true) const
virtual std::list< int > addNewWords(const cv::Mat &descriptors, int signatureId)
std::map< std::string, std::string > ParametersMap
const std::map< int, int > & getReferences() const
void addWordRef(int wordId, int signatureId)
const VisualWord * getWord(int id) const
void exportDictionary(const char *fileNameReferences, const char *fileNameDescriptors) const
std::string getExtension()
std::map< int,int > _mapIdIndex
unsigned int addPoints(const cv::Mat &features)
unsigned int getIndexedWordsCount() const
void setFixedDictionary(const std::string &dictionaryPath)
std::list< std::string > uSplit(const std::string &str, char separator= ' ')
std::vector< VisualWord * > getUnusedWords() const
#define UASSERT(condition)
int _totalActiveReferences
void setIncrementalDictionary()
virtual void parseParameters(const ParametersMap ¶meters)
void buildLinearIndex(const cv::Mat &features, bool useDistanceL1=false, float rebalancingFactor=2.0f)
#define ULOGGER_DEBUG(...)
bool _newWordsComparedTogether
#define UASSERT_MSG(condition, msg_str)
bool _incrementalDictionary
unsigned int indexedFeatures() const
std::map< int,int > _mapIndexId
const cv::Mat & getDescriptor() const
std::vector< int > findNN(const std::list< VisualWord * > &vws) const
VWDictionary(const ParametersMap ¶meters=ParametersMap())
unsigned int memoryUsed() const
void clear(bool printWarningsIfNotEmpty=true)
std::list< std::string > uSplitNumChar(const std::string &str)
bool uContains(const std::list< V > &list, const V &value)
static DBDriver * create(const ParametersMap ¶meters=ParametersMap())
std::vector< V > uValues(const std::multimap< K, V > &mm)
void removeWords(const std::vector< VisualWord * > &words)
std::set< int > _notIndexedWords
std::map< int, VisualWord * > _unusedWords
int getLastIndexedWordId() const
void addRef(int signatureId)
std::set< int > _removedIndexedWords
static const int ID_START
void removeAllWordRef(int wordId, int signatureId)
void setSaved(bool saved)
T uSum(const std::list< T > &list)
void buildKDTreeIndex(const cv::Mat &features, int trees=4, bool useDistanceL1=false, float rebalancingFactor=2.0f)
static const int ID_INVALID
virtual void addWord(VisualWord *vw)
void setNNStrategy(NNStrategy strategy)
VisualWord * getUnusedWord(int id) const
std::string UTILITE_EXP uFormat(const char *fmt,...)
std::string _dictionaryPath
V uValue(const std::map< K, V > &m, const K &key, const V &defaultValue=V())
std::map< int, VisualWord * > _visualWords