55 string& outputBaseFile,
56 string& initTranslation,
string& initRotation);
58 const int cloudDimension);
60 const int cloudDimension);
61 void usage(
const char *argv[]);
70 int main(
int argc,
const char *argv[])
72 bool isTransfoSaved =
false;
74 string outputBaseFile(
"test");
75 string initTranslation(
"0,0,0");
76 string initRotation(
"1,0,0;0,1,0;0,0,1");
77 const int ret =
validateArgs(argc, argv, isTransfoSaved, configFile,
78 outputBaseFile, initTranslation, initRotation);
83 const char *refFile(argv[argc-2]);
84 const char *dataFile(argv[argc-1]);
93 if (configFile.empty())
101 ifstream ifs(configFile.c_str());
104 cerr <<
"Cannot open config file " << configFile <<
", usage:";
usage(argv); exit(1);
106 icp.loadFromYaml(ifs);
109 int cloudDimension =
ref.getEuclideanDim();
111 if (!(cloudDimension == 2 || cloudDimension == 3))
113 cerr <<
"Invalid input point clouds dimension" << endl;
123 std::shared_ptr<PM::Transformation> rigidTrans;
126 if (!rigidTrans->checkParameters(initTransfo)) {
128 <<
"Initial transformation is not rigid, identiy will be used"
130 initTransfo = PM::TransformationParameters::Identity(
131 cloudDimension+1,cloudDimension+1);
134 const DP initializedData = rigidTrans->compute(
data, initTransfo);
138 float matchRatio =
icp.errorMinimizer->getWeightedPointUsedRatio();
139 cout <<
"match ratio: " << matchRatio << endl;
147 cout << endl <<
"------------------" << endl;
166 std::shared_ptr<PM::Matcher> matcherHausdorff =
PM::get().MatcherRegistrar.create(
"KDTreeMatcher",
params);
169 matcherHausdorff->init(
ref);
171 float maxDist1 =
matches.getDistsQuantile(1.0);
172 float maxDistRobust1 =
matches.getDistsQuantile(0.85);
176 matches = matcherHausdorff->findClosests(
ref);
177 float maxDist2 =
matches.getDistsQuantile(1.0);
178 float maxDistRobust2 =
matches.getDistsQuantile(0.85);
180 float haussdorffDist = std::max(maxDist1, maxDist2);
181 float haussdorffQuantileDist = std::max(maxDistRobust1, maxDistRobust2);
183 cout <<
"Haussdorff distance: " << std::sqrt(haussdorffDist) <<
" m" << endl;
184 cout <<
"Haussdorff quantile distance: " << std::sqrt(haussdorffQuantileDist) <<
" m" << endl;
208 const int dim = matchedPoints.reading.getEuclideanDim();
209 const int nbMatchedPoints = matchedPoints.reading.getNbPoints();
210 const PM::Matrix matchedRead = matchedPoints.reading.features.topRows(
dim);
211 const PM::Matrix matchedRef = matchedPoints.reference.features.topRows(
dim);
214 const PM::Matrix dist = (matchedRead - matchedRef).colwise().norm();
215 const float meanDist =
dist.sum()/nbMatchedPoints;
216 cout <<
"Robust mean distance: " << meanDist <<
" m" << endl;
220 cout <<
"------------------" << endl << endl;
224 ref.save(outputBaseFile +
"_ref.vtk");
225 data.save(outputBaseFile +
"_data_in.vtk");
226 data_out.save(outputBaseFile +
"_data_out.vtk");
228 ofstream transfoFile;
229 string initFileName = outputBaseFile +
"_init_transfo.txt";
230 string icpFileName = outputBaseFile +
"_icp_transfo.txt";
231 string completeFileName = outputBaseFile +
"_complete_transfo.txt";
233 transfoFile.open(initFileName.c_str());
234 if(transfoFile.is_open()) {
235 transfoFile << initTransfo << endl;
238 cout <<
"Unable to write the initial transformation file\n" << endl;
241 transfoFile.open(icpFileName.c_str());
242 if(transfoFile.is_open()) {
243 transfoFile <<
T << endl;
246 cout <<
"Unable to write the ICP transformation file\n" << endl;
249 transfoFile.open(completeFileName.c_str());
250 if(transfoFile.is_open()) {
251 transfoFile <<
T*initTransfo << endl;
254 cout <<
"Unable to write the complete transformation file\n" << endl;
258 cout <<
"ICP transformation:" << endl <<
T << endl;
269 cout <<
"* " <<
name <<
" *\n" << endl;
270 for (BOOST_AUTO(it, registrar.begin()); it != registrar.end(); ++it)
272 cout << it->first << endl;
274 cout << it->second->availableParameters() << endl;
279 #define DUMP_REGISTRAR_CONTENT(pm, name, bib) \
280 dumpRegistrar(pm, pm.REG(name), # name, bib);
295 cout <<
"* Bibliography *" << endl << endl;
301 bool& isTransfoSaved,
303 string& outputBaseFile,
304 string& initTranslation,
string& initRotation)
308 cerr <<
"Not enough arguments, usage:";
314 if (
string(argv[1]) ==
"-l")
321 cerr <<
"Wrong option, usage:";
327 const int endOpt(argc - 2);
328 for (
int i = 1; i < endOpt; i += 2)
330 const string opt(argv[i]);
333 cerr <<
"Missing value for option " << opt <<
", usage:";
usage(argv); exit(1);
335 if (opt ==
"--isTransfoSaved") {
336 if (strcmp(argv[i+1],
"1") == 0 || strcmp(argv[i+1],
"true") == 0) {
337 isTransfoSaved =
true;
339 else if (strcmp(argv[i+1],
"0") == 0
340 || strcmp(argv[i+1],
"false") == 0) {
341 isTransfoSaved =
false;
344 cerr <<
"Invalid value for parameter isTransfoSaved." << endl
345 <<
"Value must be true or false or 1 or 0." << endl
346 <<
"Default value will be used." << endl;
349 else if (opt ==
"--config") {
350 configFile = argv[i+1];
352 else if (opt ==
"--output") {
353 outputBaseFile = argv[i+1];
355 else if (opt ==
"--initTranslation") {
356 initTranslation = argv[i+1];
358 else if (opt ==
"--initRotation") {
359 initRotation = argv[i+1];
363 cerr <<
"Unknown option " << opt <<
", usage:";
usage(argv); exit(1);
370 const int cloudDimension) {
372 parsedTranslation = PM::TransformationParameters::Identity(
373 cloudDimension+1,cloudDimension+1);
382 float translationValues[3] = {0};
384 for(
int i = 0; i < cloudDimension; i++) {
385 if(!(translationStringStream >> translationValues[i])) {
386 cerr <<
"An error occured while trying to parse the initial "
387 <<
"translation." << endl
388 <<
"No initial translation will be used" << endl;
389 return parsedTranslation;
392 float extraOutput = 0;
393 if((translationStringStream >> extraOutput)) {
394 cerr <<
"Wrong initial translation size" << endl
395 <<
"No initial translation will be used" << endl;
396 return parsedTranslation;
399 for(
int i = 0; i < cloudDimension; i++) {
400 parsedTranslation(i,cloudDimension) = translationValues[i];
403 return parsedTranslation;
407 const int cloudDimension){
409 parsedRotation = PM::TransformationParameters::Identity(
410 cloudDimension+1,cloudDimension+1);
419 float rotationMatrix[9] = {0};
420 stringstream rotationStringStream(
rotation);
421 for(
int i = 0; i < cloudDimension*cloudDimension; i++) {
422 if(!(rotationStringStream >> rotationMatrix[i])) {
423 cerr <<
"An error occured while trying to parse the initial "
424 <<
"rotation." << endl
425 <<
"No initial rotation will be used" << endl;
426 return parsedRotation;
429 float extraOutput = 0;
430 if((rotationStringStream >> extraOutput)) {
431 cerr <<
"Wrong initial rotation size" << endl
432 <<
"No initial rotation will be used" << endl;
433 return parsedRotation;
436 for(
int i = 0; i < cloudDimension*cloudDimension; i++) {
437 parsedRotation(i/cloudDimension,i%cloudDimension) = rotationMatrix[i];
440 return parsedRotation;
447 cerr << endl << endl;
448 cerr <<
"* To list modules:" << endl;
449 cerr <<
" " << argv[0] <<
" -l" << endl;
451 cerr <<
"* To run ICP:" << endl;
452 cerr <<
" " << argv[0] <<
" [OPTIONS] reference.csv reading.csv" << endl;
454 cerr <<
"OPTIONS can be a combination of:" << endl;
455 cerr <<
"--config YAML_CONFIG_FILE Load the config from a YAML file (default: default parameters)" << endl;
456 cerr <<
"--output BASEFILENAME Name of output files (default: test)" << endl;
457 cerr <<
"--initTranslation [x,y,z] Add an initial 3D translation before applying ICP (default: 0,0,0)" << endl;
458 cerr <<
"--initTranslation [x,y] Add an initial 2D translation before applying ICP (default: 0,0)" << endl;
459 cerr <<
"--initRotation [r00,r01,r02,r10,r11,r12,r20,r21,r22]" << endl;
460 cerr <<
" Add an initial 3D rotation before applying ICP (default: 1,0,0,0,1,0,0,0,1)" << endl;
461 cerr <<
"--initRotation [r00,r01,r10,r11]" << endl;
462 cerr <<
" Add an initial 2D rotation before applying ICP (default: 1,0,0,1)" << endl;
463 cerr <<
"--isTransfoSaved BOOL Save transformation matrix in three different files:" << endl;
464 cerr <<
" - BASEFILENAME_inti_transfo.txt" << endl;
465 cerr <<
" - BASEFILENAME_icp_transfo.txt" << endl;
466 cerr <<
" - BASEFILENAME_complete_transfo.txt" << endl;
467 cerr <<
" (default: false)" << endl;
469 cerr <<
"Running this program with a VTKFileInspector as Inspector will create three" << endl;
470 cerr <<
"vtk ouptput files: ./test_ref.vtk, ./test_data_in.vtk and ./test_data_out.vtk" << endl;
471 cerr << endl <<
"2D Example:" << endl;
472 cerr <<
" " << argv[0] <<
" ../examples/data/2D_twoBoxes.csv ../examples/data/2D_oneBox.csv" << endl;
473 cerr << endl <<
"3D Example:" << endl;
474 cerr <<
" " << argv[0] <<
" ../examples/data/car_cloud400.csv ../examples/data/car_cloud401.csv" << endl;