tools/VocabularyComparison/main.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the name of the Universite de Sherbrooke nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
28 #include <opencv2/core/core.hpp>
29 #include <opencv2/core/types_c.h>
30 #include <opencv2/highgui/highgui_c.h>
31 #include <opencv2/imgproc/imgproc_c.h>
32 #include <opencv2/flann/miniflann.hpp>
33 #include <opencv2/features2d/features2d.hpp>
34 #include <opencv2/nonfree/features2d.hpp>
36 #include <rtabmap/utilite/UTimer.h>
38 #include <rtabmap/utilite/UStl.h>
39 #include <rtabmap/utilite/UMath.h>
40 #include <fstream>
41 #include <vector>
42 #include <list>
43 #include <string>
44 #include <iostream>
45 
46 void showUsage()
47 {
48  printf("Usage:\n"
49  "vocabularyComparison.exe \"dictionary/path\"\n"
50  " Dictionary path example: \"data/Dictionary49k.txt\""
51  " Note that 400 first descriptors in the file are used as queries.\n");
52  exit(1);
53 }
54 
55 int main(int argc, char * argv[])
56 {
57  if(argc < 2)
58  {
59  showUsage();
60  }
63 
64  std::string dictionaryPath = argv[argc-1];
65  std::list<std::vector<float> > objectDescriptors;
66  //std::list<std::vector<float> > descriptors;
67  std::map<int, std::vector<float> > descriptors;
68  int dimension = 0;
69  UTimer timer;
70  int objectDescriptorsSize= 400;
71 
72  std::ifstream file;
73  if(!dictionaryPath.empty())
74  {
75  file.open(dictionaryPath.c_str(), std::ifstream::in);
76  }
77  if(file.good())
78  {
79  UDEBUG("Loading the dictionary from \"%s\"", dictionaryPath.c_str());
80 
81  // first line is the header
82  std::string str;
83  std::list<std::string> strList;
84  std::getline(file, str);
85  strList = uSplitNumChar(str);
86  for(std::list<std::string>::iterator iter = strList.begin(); iter != strList.end(); ++iter)
87  {
88  if(uIsDigit(iter->at(0)))
89  {
90  dimension = std::atoi(iter->c_str());
91  break;
92  }
93  }
94 
95  if(dimension == 0 || dimension > 1000)
96  {
97  UERROR("Invalid dictionary file, visual word dimension (%d) is not valid, \"%s\"", dimension, dictionaryPath.c_str());
98  }
99  else
100  {
101  int descriptorsLoaded = 0;
102  // Process all words
103  while(file.good())
104  {
105  std::getline(file, str);
106  strList = uSplit(str);
107  if((int)strList.size() == dimension+1)
108  {
109  //first one is the visual word id
110  std::list<std::string>::iterator iter = strList.begin();
111  int id = atoi(iter->c_str());
112  ++iter;
113 
114  std::vector<float> descriptor(dimension);
115  int i=0;
116 
117  //get descriptor
118  for(;i<dimension && iter != strList.end(); ++i, ++iter)
119  {
120  descriptor[i] = uStr2Float(*iter);
121  }
122  if(i != dimension)
123  {
124  UERROR("");
125  }
126 
127  if(++descriptorsLoaded<=objectDescriptorsSize)
128  {
129  objectDescriptors.push_back(descriptor);
130  }
131  else
132  {
133  //descriptors.push_back(descriptor);
134  descriptors.insert(std::make_pair(id, descriptor));
135  }
136  }
137  else if(str.size())
138  {
139  UWARN("Cannot parse line \"%s\"", str.c_str());
140  }
141  }
142  }
143 
144  UDEBUG("Time loading dictionary = %fs, dimension=%d", timer.ticks(), dimension);
145  }
146  else
147  {
148  UERROR("Cannot open dictionary file \"%s\"", dictionaryPath.c_str());
149  }
150  file.close();
151 
152  if(descriptors.size() && objectDescriptors.size() && dimension)
153  {
154  cv::Mat dataTree;
155  cv::Mat queries;
156 
157  UDEBUG("Creating data structures...");
158  // Create the data structure
159  dataTree = cv::Mat((int)descriptors.size(), dimension, CV_32F); // SURF descriptors are CV_32F
160  {//scope
161  //std::list<std::vector<float> >::const_iterator iter = descriptors.begin();
162  std::map<int, std::vector<float> >::const_iterator iter = descriptors.begin();
163  for(unsigned int i=0; i < descriptors.size(); ++i, ++iter)
164  {
165  UTimer tim;
166  //memcpy(dataTree.ptr<float>(i), iter->data(), dimension*sizeof(float));
167  memcpy(dataTree.ptr<float>(i), iter->second.data(), dimension*sizeof(float));
168  //if(i%100==0)
169  // UDEBUG("i=%d/%d tim=%fs", i, descriptors.size(), tim.ticks());
170  }
171  }
172 
173  queries = cv::Mat((int)objectDescriptors.size(), dimension, CV_32F); // SURF descriptors are CV_32F
174  {//scope
175  std::list<std::vector<float> >::const_iterator iter = objectDescriptors.begin();
176  for(unsigned int i=0; i < objectDescriptors.size(); ++i, ++iter)
177  {
178  UTimer tim;
179  memcpy(queries.ptr<float>(i), iter->data(), dimension*sizeof(float));
180  //if(i%100==0)
181  // UDEBUG("i=%d/%d tim=%fs", i, objectDescriptors.size(), tim.ticks());
182  }
183  }
184 
185  UDEBUG("descriptors.size()=%d, objectDescriptorsSize=%d, copying data = %f s",descriptors.size(), objectDescriptors.size(), timer.ticks());
186 
187  UDEBUG("Creating indexes...");
188  cv::flann::Index * linearIndex = new cv::flann::Index(dataTree, cv::flann::LinearIndexParams());
189  UDEBUG("Time to create linearIndex = %f s", timer.ticks());
190 
191  cv::flann::Index * kdTreeIndex1 = new cv::flann::Index(dataTree, cv::flann::KDTreeIndexParams(1));
192  UDEBUG("Time to create kdTreeIndex1 = %f s", timer.ticks());
193 
194  cv::flann::Index * kdTreeIndex4 = new cv::flann::Index(dataTree, cv::flann::KDTreeIndexParams(4));
195  UDEBUG("Time to create kdTreeIndex4 = %f s", timer.ticks());
196 
197  cv::flann::Index * kMeansIndex = new cv::flann::Index(dataTree, cv::flann::KMeansIndexParams());
198  UDEBUG("Time to create kMeansIndex = %f s", timer.ticks());
199 
200  cv::flann::Index * compositeIndex = new cv::flann::Index(dataTree, cv::flann::CompositeIndexParams());
201  UDEBUG("Time to create compositeIndex = %f s", timer.ticks());
202 
203  //cv::flann::Index * autoTunedIndex = new cv::flann::Index(dataTree, cv::flann::AutotunedIndexParams());
204  //UDEBUG("Time to create autoTunedIndex = %f s", timer.ticks());
205 
206 
207  UDEBUG("Search indexes...");
208  int k=2; // 2 nearest neighbors
209  cv::Mat results(queries.rows, k, CV_32SC1); // results index
210  cv::Mat dists(queries.rows, k, CV_32FC1); // Distance results are CV_32FC1
211 
212  linearIndex->knnSearch(queries, results, dists, k);
213  //std::cout << results.t() << std::endl;
214  cv::Mat transposedLinear = dists.t();
215  UDEBUG("Time to search linearIndex = %f s", timer.ticks());
216 
217  kdTreeIndex1->knnSearch(queries, results, dists, k);
218  //std::cout << results.t() << std::endl;
219  cv::Mat transposed = dists.t();
220  UDEBUG("Time to search kdTreeIndex1 = %f s (size=%d, dist error(k1,k2)=(%f,%f))",
221  timer.ticks(),
222  transposed.cols,
223  uMeanSquaredError( (float*)transposed.data,
224  transposed.cols,
225  (float*)transposedLinear.data,
226  transposedLinear.cols),
227  uMeanSquaredError( &transposed.at<float>(1,0),
228  transposed.cols,
229  &transposedLinear.at<float>(1,0),
230  transposedLinear.cols));
231 
232  kdTreeIndex4->knnSearch(queries, results, dists, k);
233  //std::cout << results.t() << std::endl;
234  transposed = dists.t();
235  UDEBUG("Time to search kdTreeIndex4 = %f s (size=%d, dist error(k1,k2)=(%f,%f))",
236  timer.ticks(),
237  transposed.cols,
238  uMeanSquaredError( (float*)transposed.data,
239  transposed.cols,
240  (float*)transposedLinear.data,
241  transposedLinear.cols),
242  uMeanSquaredError( &transposed.at<float>(1,0),
243  transposed.cols,
244  &transposedLinear.at<float>(1,0),
245  transposedLinear.cols));
246 
247  kMeansIndex->knnSearch(queries, results, dists, k);
248  //std::cout << results.t() << std::endl;
249  transposed = dists.t();
250  UDEBUG("Time to search kMeansIndex = %f s (size=%d, dist error(k1,k2)=(%f,%f))",
251  timer.ticks(),
252  transposed.cols,
253  uMeanSquaredError( (float*)transposed.data,
254  transposed.cols,
255  (float*)transposedLinear.data,
256  transposedLinear.cols),
257  uMeanSquaredError( &transposed.at<float>(1,0),
258  transposed.cols,
259  &transposedLinear.at<float>(1,0),
260  transposedLinear.cols));
261 
262  compositeIndex->knnSearch(queries, results, dists, k);
263  //std::cout << results.t() << std::endl;
264  transposed = dists.t();
265  UDEBUG("Time to search compositeIndex = %f s (size=%d, dist error(k1,k2)=(%f,%f))",
266  timer.ticks(),
267  transposed.cols,
268  uMeanSquaredError( (float*)transposed.data,
269  transposed.cols,
270  (float*)transposedLinear.data,
271  transposedLinear.cols),
272  uMeanSquaredError( &transposed.at<float>(1,0),
273  transposed.cols,
274  &transposedLinear.at<float>(1,0),
275  transposedLinear.cols));
276 
277  //autoTunedIndex->knnSearch(queries, results, dists, k);
278  //UDEBUG("Time to search autoTunedIndex = %f s", timer.ticks());
279 
280  delete linearIndex;
281  delete kdTreeIndex1;
282  delete kdTreeIndex4;
283  delete kMeansIndex;
284  delete compositeIndex;
285  //delete autoTunedIndex;
286  }
287 
288  return 0;
289 }
Definition: UTimer.h:46
bool uIsDigit(const char c)
Definition: UStl.h:622
float UTILITE_EXP uStr2Float(const std::string &str)
Basic mathematics functions.
Some conversion functions.
static void setLevel(ULogger::Level level)
Definition: ULogger.h:339
std::list< std::string > uSplit(const std::string &str, char separator= ' ')
Definition: UStl.h:566
Wrappers of STL for convenient functions.
int main(int argc, char *argv[])
static void setType(Type type, const std::string &fileName=kDefaultLogFileName, bool append=true)
Definition: ULogger.cpp:176
T uMeanSquaredError(const T *x, unsigned int sizeX, const T *y, unsigned int sizeY)
Definition: UMath.h:455
std::list< std::string > uSplitNumChar(const std::string &str)
Definition: UStl.h:672
struct Index Index
Definition: sqlite3.c:8577
#define UDEBUG(...)
#define UERROR(...)
ULogger class and convenient macros.
#define UWARN(...)
double ticks()
Definition: UTimer.cpp:110


rtabmap
Author(s): Mathieu Labbe
autogenerated on Wed Jun 5 2019 22:41:31