eval_solution.cpp
Go to the documentation of this file.
1 // kate: replace-tabs off; indent-width 4; indent-mode normal
2 // vim: ts=4:sw=4:noexpandtab
3 /*
4 
5 Copyright (c) 2010--2012,
6 François Pomerleau and Stephane Magnenat, ASL, ETHZ, Switzerland
7 You can contact the authors at <f dot pomerleau at gmail dot com> and
8 <stephane at magnenat dot net>
9 
10 All rights reserved.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, are permitted provided that the following conditions are met:
14  * Redistributions of source code must retain the above copyright
15  notice, this list of conditions and the following disclaimer.
16  * Redistributions in binary form must reproduce the above copyright
17  notice, this list of conditions and the following disclaimer in the
18  documentation and/or other materials provided with the distribution.
19  * Neither the name of the <organization> nor the
20  names of its contributors may be used to endorse or promote products
21  derived from this software without specific prior written permission.
22 
23 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
24 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
25 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
26 DISCLAIMED. IN NO EVENT SHALL ETH-ASL BE LIABLE FOR ANY
27 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
28 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
30 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 
34 */
35 
37 #include "pointmatcher/IO.h"
38 #include "pointmatcher/Timer.h"
39 #include <cassert>
40 #include <iostream>
41 #include <fstream>
42 #include <map>
43 #include <time.h>
44 
45 #include <ncurses.h>
46 
47 #include <boost/program_options.hpp>
48 #include <boost/filesystem.hpp>
49 #include <boost/date_time/posix_time/posix_time.hpp>
50 #include <boost/date_time/posix_time/posix_time_io.hpp>
51 #include <boost/thread/thread.hpp>
52 #include <boost/thread/mutex.hpp>
53 
54 
55 using namespace std;
56 using namespace PointMatcherSupport;
57 namespace po = boost::program_options;
58 namespace fs = boost::filesystem;
59 namespace pt = boost::posix_time;
60 
64 
66 {
67  string name;
68  bool downloaded;
69  string path;
71  DataSetInfo(string name, bool downloaded):
72  name(name),
73  downloaded(downloaded)
74  {}
75 };
76 
77 struct Config
78 {
79  // Default values
80  string path_config;
81  string path_download;
82  string path_result;
85  map<string, DataSetInfo> dataSetStatus;
86 
88  {
89  path_config = string(getenv("HOME")) + "/.lpm/eval_solution.conf";
90  path_download = string(getenv("HOME")) + "/.lpm/download/";
91  path_result = "./";
92  path_server_validation = "robotics.ethz.ch/~asl-datasets/evaluations/validation";
93  path_server_protocols = "robotics.ethz.ch/~asl-datasets/evaluations/protocols";
94  DataSetInfo info;
95  info = DataSetInfo("apartment", false);
96  info.path = "robotics.ethz.ch/~asl-datasets/apartment_03-Dec-2011-18_13_33/csv_local/local_frame.zip";
97  dataSetStatus[info.name] = info;
98  info = DataSetInfo("eth", false);
99  info.path = "http://robotics.ethz.ch/~asl-datasets/ETH_hauptgebaude_23-Aug-2011-18_43_49/csv_local/local_frame.zip";
100  dataSetStatus[info.name] = info;
101  info = DataSetInfo("plain", false);
102  info.path = "http://robotics.ethz.ch/~asl-datasets/plain_01-Sep-2011-16_39_18/csv_local/local_frame.zip";
103  dataSetStatus[info.name] = info;
104  info = DataSetInfo("stairs", false);
105  info.path = "http://robotics.ethz.ch/~asl-datasets/stairs_26-Aug-2011-14_26_14/csv_local/local_frame.zip";
106  dataSetStatus[info.name] = info;
107  info = DataSetInfo("gazebo", false);
108  info.path = "http://robotics.ethz.ch/~asl-datasets/gazebo_winter_18-Jan-2012-16_10_04/csv_local/local_frame.zip";
109  dataSetStatus[info.name] = info;
110  info = DataSetInfo("wood", false);
111  info.path = "http://robotics.ethz.ch/~asl-datasets/wood_summer_25-Aug-2011-13_00_30/csv_local/local_frame.zip";
112  dataSetStatus[info.name] = info;
113  }
114 
115 };
116 
118 {
119 public:
121  int coreId;
123  double result_time;
124  void evaluateSolution(const string &tmp_file_name, const string &yaml_config, const int &coreId, PMIO::FileInfoVector::const_iterator it_eval, PMIO::FileInfoVector::const_iterator it_end);
125 
126 };
127 
128 po::options_description setupOptions(const string & name);
129 string outputStatus(map<string, DataSetInfo> dataSetStatus);
130 string enterValidPath(string message);
131 void setConfig(Config& config);
132 void saveConfig(Config& config);
133 void loadConfig(Config& config);
134 void downloadDataSets(Config& config, po::variables_map &vm);
135 void validateFileInfo(const PMIO::FileInfo &fileInfo);
136 void displayLoadingBar(const int &coreId, const int &i, const int &total, const int &nbFailures, const double sec, const double total_time);
137 
138 int main(int argc, char *argv[])
139 {
140  srand ( time(NULL) );
141 
142  // Option parsing
143  po::options_description desc = setupOptions(argv[0]);
144  po::positional_options_description p;
145  p.add("icp-config", -1);
146 
147  po::variables_map vm;
148  po::store(po::command_line_parser(argc, argv).
149  options(desc).positional(p).run(), vm);
150  po::notify(vm);
151 
152  // Evaluation configuration
153  Config config;
154 
155  if (vm.count("help")) {
156  cout << desc << endl;
157  return 1;
158  }
159 
160  // Check for config
161  fs::path c_path(config.path_config);
162  if(fs::exists(c_path) == false)
163  {
164  fs::create_directories(c_path.parent_path());
165  cout << ">> no configuration found. Using default values." << endl;
166 
167  }
168  else
169  {
170  loadConfig(config);
171  }
172 
173  if (vm.count("config"))
174  {
175  setConfig(config);
176  saveConfig(config);
177  return 0;
178  }
179 
180  if (vm.count("download"))
181  {
182  downloadDataSets(config, vm);
183  saveConfig(config);
184  return 0;
185  }
186 
187  if (vm.count("icp-config") == false)
188  {
189  cerr << "You must provide a YAMl file to evaluate it." << endl;
190  return 1;
191  }
192 
193  const string yaml_config = vm["icp-config"].as<string>();
194  {
195  ifstream cfgIfs(yaml_config.c_str());
196  if (!cfgIfs.good())
197  {
198  cerr << "Cannot open YAML file name: it must exist and be readable." << endl;
199  return 2;
200  }
201  }
202 
203  initscr(); // ncurse screen
204 
205  // Starting evaluation
206  for(BOOST_AUTO(it, config.dataSetStatus.begin()); it != config.dataSetStatus.end(); ++it)
207  {
208  if(vm.count("all") || vm.count(it->second.name))
209  {
210  if(it->second.downloaded == false)
211  {
212  endwin(); /* End curses mode */
213  cerr << ">> Please download data set first." << endl
214  << ">> You can use the option --download -A to download them all." << endl;
215  return 1;
216  }
217 
218  const string protocol_name = config.path_download + "protocols/" + it->second.name + "_protocol.csv";
219  const string data_directory = config.path_download + it->second.name + "/";
220 
221  if(!fs::exists(fs::path(protocol_name)))
222  {
223  endwin(); /* End curses mode */
224  cerr << ">> Missing protocol file: " << protocol_name << endl
225  << ">> You can use the option --download to download it back." << endl;
226  return 1;
227  }
228 
229  const PMIO::FileInfoVector eval_list(protocol_name, data_directory, "");
230 
231  // Ensure that all required columns are there
232  validateFileInfo(eval_list[0]);
233  move(0,0);
234  clrtoeol();
235  mvprintw(0, 0, " <<< Evaluating %s >>>", it->second.name.c_str());
236  //cout << endl << "<<< Evaluating " << it->second.name << " >>>" << endl;
237 
238  // Spawn threads
239  const int maxNbCore = 16;
240  int nbCore = 1;
241  if(vm["threads"].as<int>() > 1 || vm["threads"].as<int>() < maxNbCore)
242  {
243  nbCore = vm["threads"].as<int>();
244  }
245 
246  // List of thread
247  boost::thread a_threads[maxNbCore];
248  std::vector<EvaluationModule> v_evalModules;
249 
250  const int nbPerThread = eval_list.size()/nbCore;
251  PMIO::FileInfoVector::const_iterator it_start = eval_list.begin();
252  for (int j=0; j<nbCore; ++j)
253  {
254  v_evalModules.push_back(EvaluationModule());
255  v_evalModules[j].coreId = j;
256  stringstream name;
257  name << ".tmp_core" << j << "_" << rand() << ".csv";
258  v_evalModules[j].tmp_file_name = name.str();
259  // Start evaluation for every line
260  if(j == nbCore-1)
261  {
262  // last core receive the reste
263  a_threads[j] = boost::thread(&EvaluationModule::evaluateSolution, &v_evalModules[j], name.str(), yaml_config, j, it_start, eval_list.end());
264  //evalCore.evaluateSolution(yaml_config, j, it_start, eval_list.end());
265  }
266  else
267  {
268  a_threads[j] = boost::thread(&EvaluationModule::evaluateSolution, &v_evalModules[j], name.str(), yaml_config, j, it_start, it_start + nbPerThread);
269  //evalCore.evaluateSolution(yaml_config, j, it_start, it_start + nbPerThread);
270  it_start += nbPerThread;
271  }
272  cout << endl;
273  }
274 
275  // Wait for the results
276  for (int k=0; k<nbCore; ++k)
277  {
278  if(a_threads[k].joinable())
279  a_threads[k].join();
280  }
281 
282  // Write the results to a file
283  stringstream ss_path_time;
284  pt::time_facet *facet = new pt::time_facet("%d-%b-%Y-%H_%M_%S");
285  ss_path_time.imbue(locale(ss_path_time.getloc(), facet));
286 
287  ss_path_time << config.path_result << it->second.name << "_";
288  ss_path_time << pt::second_clock::local_time() << ".csv";
289 
290  move(nbCore+3,0);
291  clrtoeol();
292  mvprintw(nbCore+3, 0, "Last result written to: %s", ss_path_time.str().c_str());
293  std::ofstream fout(ss_path_time.str().c_str());
294  if (!fout.good())
295  {
296  cerr << "Warning, cannot open result file " << ss_path_time << ", results were not saved" << endl;
297  continue;
298  }
299 
300  // dump header
301  fout << "time";
302  for(int r=0; r<4;++r)
303  for(int c=0; c<4;++c)
304  fout << ", T" << r << c;
305 
306  fout << "\n";
307 
308  // dump results
309  // for all threads
310  for(unsigned i=0; i<v_evalModules.size(); ++i)
311  {
312  const string tmp_file_name = v_evalModules[i].tmp_file_name;
313  ifstream tmp_file(tmp_file_name.c_str());
314  if(tmp_file.is_open())
315  {
316  fout << tmp_file.rdbuf();
317  tmp_file.close();
318  fs::remove(fs::path(tmp_file_name));
319  }
320  else
321  {
322  endwin();/* End curses mode */
323  cerr << "Cannot find tmp file named "<< tmp_file_name << endl;
324  }
325  }
326 
327  fout.close();
328  }
329  }
330  endwin(); /* End curses mode */
331 
332  return 0;
333 }
334 
335 
336 po::options_description setupOptions(const string & name)
337 {
338  po::options_description desc("Allowed options");
339  desc.add_options()
340  ("help,h", "Print this message")
341  ("icp-config", po::value<string>(), "YAML configuration file")
342  ("config,C", "Interactive configuration")
343  ("download,D", "Download selected data sets from the web")
344  ("evaluate,E", "Evaluate a solution over selected data sets")
345  ("threads,j", po::value<int>()->default_value(1), "Number of threads to use. Max 16.")
346  ("apartment,a", "Apply action only on the data set Apartment")
347  ("eth,e", "Apply action only on the data set ETH Hauptgebaude")
348  ("plain,p", "Apply action only on the data set Mountain Plain")
349  ("stairs,s", "Apply action only on the data set Stairs")
350  ("gazebo,g", "Apply action only on the data set Gazebo Winter")
351  ("wood,w", "Apply action only on the data set Wood Summer")
352  ("all,A", "Apply action for all data sets")
353  ;
354 
355  return desc;
356 }
357 
358 string outputStatus(map<string, DataSetInfo> dataSetStatus)
359 {
360  stringstream ss;
361 
362  for(BOOST_AUTO(it, dataSetStatus.begin()); it != dataSetStatus.end(); ++it)
363  {
364  string paddedName = it->second.name + ":";
365  while (paddedName.length() < 12) paddedName += " ";
366  ss << "\t" << paddedName;
367  if(it->second.downloaded)
368  {
369  ss << "downloaded.";
370  }
371  else
372  {
373  ss << "not on your system.";
374  }
375 
376  ss << endl;
377  }
378 
379  return ss.str();
380 }
381 
382 
383 string enterValidPath(string message)
384 {
385  bool validPath = false;
386  string path_name;
387  while(!validPath)
388  {
389  cout << message;
390  getline(cin, path_name);
391  validPath = fs::is_directory(fs::path(path_name));
392  if(validPath == false)
393  cout << ">> Not a valid path" << endl;
394  }
395 
396  return path_name;
397 }
398 
399 
400 void setConfig(Config& config)
401 {
402  string answer = "0";
403  cout << "Current configuration:" << endl
404  << "\t Download path: " << config.path_download << endl
405  << "\t Result path: " << config.path_result << endl;
406 
407  cout << "Data set status:" << endl;
408  cout << outputStatus(config.dataSetStatus);
409 
410  while(!(answer == "" || answer == "y" ||answer == "Y" || answer == "n" || answer == "N"))
411  {
412  cout << endl << "Do you want to change something? [y/N]: ";
413  getline(cin, answer);
414 
415  //if(answer == "" || answer == "n" ||answer == "N" )
416  // return 1;
417  if(answer == "y" ||answer == "Y" )
418  {
419  config.path_download = enterValidPath("Enter data set path or where they will be downloaded: ");
420  cout << endl;
421  config.path_result = enterValidPath("Enter the result path (where the result of the test will be saved): ");
422 
423  }
424  }
425 }
426 
427 void saveConfig(Config& config)
428 {
429  YAML::Emitter emitter;
430 
431  emitter << YAML::BeginMap;
432  emitter << YAML::Key << "path_download";
433  emitter << YAML::Value << config.path_download;
434  emitter << YAML::Key << "path_result";
435  emitter << YAML::Value << config.path_result;
436 
437  for(BOOST_AUTO(it, config.dataSetStatus.begin()); it != config.dataSetStatus.end(); ++it)
438  {
439  emitter << YAML::Key << it->second.name;
440  emitter << YAML::Value;
441  emitter << YAML::BeginMap;
442  emitter << YAML::Key << "downloaded";
443  emitter << YAML::Value << it->second.downloaded;
444  emitter << YAML::EndMap;
445  }
446  emitter << YAML::EndMap;
447 
448  std::ofstream fout(config.path_config.c_str());
449  if (!fout.good())
450  {
451  cerr << "Warning, cannot open config file " << config.path_config << ", content was not saved" << endl;
452  return;
453  }
454  fout << emitter.c_str();
455  fout.close();
456 }
457 
458 void loadConfig(Config& config)
459 {
460  ifstream f_config(config.path_config.c_str());
461  if (!f_config.good())
462  {
463  cerr << "Warning, cannot open config file " << config.path_config << ", content was not loaded" << endl;
464  return;
465  }
466  YAML::Parser parser(f_config);
467 
468  YAML::Node doc;
469  while(parser.GetNextDocument(doc))
470  {
471  doc["path_download"] >> config.path_download;
472  doc["path_result"] >> config.path_result;
473  for(BOOST_AUTO(it, config.dataSetStatus.begin()); it != config.dataSetStatus.end(); ++it)
474  {
475  string dataSetName = it->second.name;
476  const YAML::Node &node = doc[dataSetName];
477  node["downloaded"] >> it->second.downloaded;
478  }
479  }
480 }
481 
482 void downloadDataSets(Config& config, po::variables_map &vm)
483 {
484  // Ensure that validation and protocol folders are there
485  fs::path extra_path(config.path_download+"/validation/");
486  if(!fs::is_directory(extra_path))
487  fs::create_directories(extra_path);
488  extra_path = fs::path(config.path_download+"/protocols/");
489  if(!fs::is_directory(extra_path))
490  fs::create_directories(extra_path);
491 
492  for(BOOST_AUTO(it, config.dataSetStatus.begin()); it != config.dataSetStatus.end(); ++it)
493  {
494  if(vm.count("all") || vm.count(it->second.name))
495  {
496  cout << ">> Fetching files for: " << it->second.name << "..." << endl << endl;
497  fs::path d_path(config.path_download+it->second.name);
498  if(!fs::is_directory(d_path))
499  fs::create_directories(d_path);
500 
501  string cmd;
502  int sysRes;
503  #define CHECK_RES if (sysRes != 0) { cerr << "Warning, system command \"" << cmd << "\" failed with result code " << sysRes << endl; }
504 
505  // Dowload validation
506  cout << ">> Downloading validation file ..." << endl;
507  cmd = "wget -P " + config.path_download + "/validation/ " + config.path_server_validation + "/" + it->second.name + "_validation.csv";
508  sysRes = system(cmd.c_str());
509  CHECK_RES
510 
511  // Dowload protocol
512  cout << ">> Downloading protocol file ..." << endl;
513  cmd = "wget -P " + config.path_download + "/protocols/ " + config.path_server_protocols + "/" + it->second.name + "_protocol.csv";
514  sysRes = system(cmd.c_str());
515  CHECK_RES
516 
517  // Download data set
518  cout << ">> Downloading data set files ..." << endl;
519  cmd = "wget -P " + d_path.string() + " " + it->second.path;
520  sysRes = system(cmd.c_str());
521  CHECK_RES
522 
523  cout << ">> Unzipping dataset..." << endl;
524  cmd = "unzip -q " + d_path.string() + "/local_frame.zip -d " + d_path.string() + "/";
525  sysRes = system(cmd.c_str());
526  CHECK_RES
527 
528  cmd = "rm " + d_path.string() + "/local_frame.zip";
529  sysRes = system(cmd.c_str());
530  CHECK_RES
531 
532  it->second.downloaded = true;
533  }
534  }
535 }
536 
537 void validateFileInfo(const PMIO::FileInfo &fileInfo)
538 {
539  if(fileInfo.initialTransformation.rows() == 0)
540  {
541  cout << "Missing columns representing initial transformation \"iTxy\"" << endl;
542  abort();
543  }
544 
545  if(fileInfo.readingFileName == "")
546  {
547  cout << "Missing column named \"reading\"" << endl;
548  abort();
549  }
550 
551  if(fileInfo.referenceFileName == "")
552  {
553  cout << "Missing column named \"reference\"" << endl;
554  abort();
555  }
556 
557 }
558 
559 boost::mutex m_display;
560 void displayLoadingBar(const int &coreId, const int &i, const int &total, const int &nbFailures, const double sec, const double total_time)
561 {
562  const double average_time = total_time/double(i+1);
563  int time = average_time*double(total-i);
564  const int h=time/3600;
565  time=time%3600;
566  const int m=time/60;
567  time=time%60;
568  const int s=time;
569 
570 
571  m_display.lock();
572  //ncurse output
573  move(coreId+1,0);
574  clrtoeol();
575  mvprintw(coreId+1, 10, " Core %2d: %5d/%5d failed: %2d last dur: %2.3f sec, avr: %2.3f sec, eta: %3dh%02dm%02d",coreId,i+1, total, nbFailures, sec, average_time, h, m, s);
576  refresh(); /* Print it on to the real screen */
577  m_display.unlock();
578 
579  //cout << "\r Core " << coreId << ": " << i+1 << "/" << total << " last dur: " << sec << " sec, avr: " << average_time << " sec, eta: " << h << "h" << m % 60 << "m" << eta % 60 << "s ";
580 }
581 
582 
583 
584 
585 
586 // ----------------------------------------------------
587 // EvaluationModule
588 // ----------------------------------------------------
590  coreId(0)
591 {
592 }
593 
594 void EvaluationModule::evaluateSolution(const string &tmp_file_name, const string &yaml_config, const int &coreId, PMIO::FileInfoVector::const_iterator it_eval, PMIO::FileInfoVector::const_iterator it_end)
595 {
596  PM::DataPoints refCloud, readCloud;
597  string last_read_name = "";
598  string last_ref_name = "";
599  const int count = std::distance(it_eval, it_end);
600  int current_line = 0;
601  timer t_eval_list;
602 
603  std::ofstream fout(tmp_file_name.c_str());
604  if (!fout.good())
605  {
606  cerr << "Warning, cannot open temporary result file " << tmp_file_name << ", evaluation was skipped" << endl;
607  return;
608  }
609 
610  for( ; it_eval < it_end; ++it_eval)
611  {
612  timer t_singleTest;
613 
614  // Load point clouds
615  if(last_read_name != it_eval->readingFileName)
616  {
617  readCloud = PM::DataPoints::load(it_eval->readingFileName);
618  last_read_name = it_eval->readingFileName;
619  }
620 
621  if(last_ref_name != it_eval->referenceFileName)
622  {
623  refCloud = PM::DataPoints::load(it_eval->referenceFileName);
624  last_ref_name = it_eval->referenceFileName;
625  }
626 
627  // Build ICP based on config file
628  PM::ICP icp;
629  ifstream ifs(yaml_config.c_str());
630  icp.loadFromYaml(ifs);
631 
632  const TP Tinit = it_eval->initialTransformation;
633 
634  timer t_icp;
635 
636  int nbFailures = 0;
637  TP Tresult = TP::Identity(4,4);
638  // Apply ICP
639  try
640  {
641  Tresult = icp(readCloud, refCloud, Tinit);
642  }
643  catch (PM::ConvergenceError error)
644  {
645  nbFailures ++;
646  }
647 
648  fout << t_icp.elapsed();
649 
650  for(int r=0; r<4;++r)
651  for(int c=0; c<4;++c)
652  fout << ", " << Tresult(r,c);
653 
654  fout << "\n";
655 
656  // Output eta to console
657  displayLoadingBar(coreId, current_line, count, nbFailures, t_singleTest.elapsed(), t_eval_list.elapsed());
658  current_line ++;
659  }
660 
661  fout.close();
662 }
po::options_description setupOptions(const string &name)
TransformationParameters initialTransformation
matrix of initial estimate transform
Definition: IO.h:237
public interface
DataSetInfo(string name, bool downloaded)
IO Functions and classes that are dependant on scalar type are defined in this templatized class...
Definition: IO.h:43
PointMatcherIO< float > PMIO
std::string referenceFileName
file name of the reference point cloud
Definition: IO.h:235
void validateFileInfo(const PMIO::FileInfo &fileInfo)
std::string readingFileName
file name of the reading point cloud
Definition: IO.h:234
void loadConfig(Config &config)
void downloadDataSets(Config &config, po::variables_map &vm)
PM::DataPoints DataPoints
string path_download
::std::string string
Definition: gtest.h:1979
string path_result
string outputStatus(map< string, DataSetInfo > dataSetStatus)
void saveConfig(Config &config)
string path_config
PointMatcher< float > PM
Functions and classes that are not dependant on scalar type are defined in this namespace.
bool GetNextDocument(Node &document)
Definition: parser.cpp:61
int main(int argc, char *argv[])
string path_server_validation
string path_server_protocols
Information to exploit a reading from a file using this library. Fields might be left blank if unused...
Definition: IO.h:230
const char * c_str() const
Definition: emitter.cpp:18
PM::TransformationParameters TP
#define CHECK_RES
double elapsed() const
boost::mutex m_display
A vector of file info, to be used in batch processing.
Definition: IO.h:245
PM::ICP ICP
void evaluateSolution(const string &tmp_file_name, const string &yaml_config, const int &coreId, PMIO::FileInfoVector::const_iterator it_eval, PMIO::FileInfoVector::const_iterator it_end)
string enterValidPath(string message)
map< string, DataSetInfo > dataSetStatus
void displayLoadingBar(const int &coreId, const int &i, const int &total, const int &nbFailures, const double sec, const double total_time)
Matrix TransformationParameters
A matrix holding the parameters a transformation.
Definition: PointMatcher.h:182
void setConfig(Config &config)


libpointmatcher
Author(s):
autogenerated on Sat May 27 2023 02:36:30