126 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			126 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			C++
		
	
	
/* ----------------------------------------------------------------------------
 | 
						|
 | 
						|
* GTSAM Copyright 2010, Georgia Tech Research Corporation,
 | 
						|
* Atlanta, Georgia 30332-0415
 | 
						|
* All Rights Reserved
 | 
						|
* Authors: Frank Dellaert, et al. (see THANKS for the full author list)
 | 
						|
 | 
						|
* See LICENSE for the license information
 | 
						|
* -------------------------------------------------------------------------- */
 | 
						|
 | 
						|
/**
 | 
						|
 * @file    ShonanAveragingCLI.cpp
 | 
						|
 * @brief   Run Shonan Rotation Averaging Algorithm on a file or example dataset
 | 
						|
 * @author  Frank Dellaert
 | 
						|
 * @date    August, 2020
 | 
						|
 *
 | 
						|
 * Example usage:
 | 
						|
 *
 | 
						|
 * Running without arguments will run on tiny 3D example pose3example-grid
 | 
						|
 * ./ShonanAveragingCLI
 | 
						|
 *
 | 
						|
 * Read 2D dataset w10000 (in examples/data) and output to w10000-rotations.g2o
 | 
						|
 * ./ShonanAveragingCLI -d 2 -n w10000 -o w10000-rotations.g2o
 | 
						|
 *
 | 
						|
 * Read 3D dataset sphere25000.txt and output to shonan.g2o (default)
 | 
						|
 * ./ShonanAveragingCLI -i spere2500.txt
 | 
						|
 *
 | 
						|
 */
 | 
						|
 | 
						|
#include <gtsam/base/timing.h>
 | 
						|
#include <gtsam/sfm/ShonanAveraging.h>
 | 
						|
#include <gtsam/slam/InitializePose.h>
 | 
						|
#include <gtsam/slam/dataset.h>
 | 
						|
 | 
						|
#include <boost/program_options.hpp>
 | 
						|
 | 
						|
using namespace std;
 | 
						|
using namespace gtsam;
 | 
						|
namespace po = boost::program_options;
 | 
						|
 | 
						|
/* ************************************************************************* */
 | 
						|
int main(int argc, char* argv[]) {
 | 
						|
  string datasetName;
 | 
						|
  string inputFile;
 | 
						|
  string outputFile;
 | 
						|
  int d, seed;
 | 
						|
  po::options_description desc(
 | 
						|
      "Shonan Rotation Averaging CLI reads a *pose* graph, extracts the "
 | 
						|
      "rotation constraints, and runs the Shonan algorithm.");
 | 
						|
  desc.add_options()("help", "Print help message")(
 | 
						|
      "named_dataset,n",
 | 
						|
      po::value<string>(&datasetName)->default_value("pose3example-grid"),
 | 
						|
      "Find and read frome example dataset file")(
 | 
						|
      "input_file,i", po::value<string>(&inputFile)->default_value(""),
 | 
						|
      "Read pose constraints graph from the specified file")(
 | 
						|
      "output_file,o",
 | 
						|
      po::value<string>(&outputFile)->default_value("shonan.g2o"),
 | 
						|
      "Write solution to the specified file")(
 | 
						|
      "dimension,d", po::value<int>(&d)->default_value(3),
 | 
						|
      "Optimize over 2D or 3D rotations")(
 | 
						|
      "seed,s", po::value<int>(&seed)->default_value(42),
 | 
						|
      "Random seed for initial estimate");
 | 
						|
  po::variables_map vm;
 | 
						|
  po::store(po::command_line_parser(argc, argv).options(desc).run(), vm);
 | 
						|
  po::notify(vm);
 | 
						|
 | 
						|
  if (vm.count("help")) {
 | 
						|
    cout << desc << "\n";
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
 | 
						|
  // Get input file
 | 
						|
  if (inputFile.empty()) {
 | 
						|
    if (datasetName.empty()) {
 | 
						|
      cout << "You must either specify a named dataset or an input file\n"
 | 
						|
           << desc << endl;
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
    inputFile = findExampleDataFile(datasetName);
 | 
						|
  }
 | 
						|
 | 
						|
  // Seed random number generator
 | 
						|
  static std::mt19937 rng(seed);
 | 
						|
 | 
						|
  NonlinearFactorGraph::shared_ptr inputGraph;
 | 
						|
  Values::shared_ptr posesInFile;
 | 
						|
  Values poses;
 | 
						|
  if (d == 2) {
 | 
						|
    cout << "Running Shonan averaging for SO(2) on " << inputFile << endl;
 | 
						|
    ShonanAveraging2 shonan(inputFile);
 | 
						|
    auto initial = shonan.initializeRandomly(rng);
 | 
						|
    auto result = shonan.run(initial);
 | 
						|
 | 
						|
    // Parse file again to set up translation problem, adding a prior
 | 
						|
    boost::tie(inputGraph, posesInFile) = load2D(inputFile);
 | 
						|
    auto priorModel = noiseModel::Unit::Create(3);
 | 
						|
    inputGraph->addPrior(0, posesInFile->at<Pose2>(0), priorModel);
 | 
						|
 | 
						|
    cout << "recovering 2D translations" << endl;
 | 
						|
    auto poseGraph = initialize::buildPoseGraph<Pose2>(*inputGraph);
 | 
						|
    poses = initialize::computePoses<Pose2>(result.first, &poseGraph);
 | 
						|
  } else if (d == 3) {
 | 
						|
    cout << "Running Shonan averaging for SO(3) on " << inputFile << endl;
 | 
						|
    ShonanAveraging3 shonan(inputFile);
 | 
						|
    auto initial = shonan.initializeRandomly(rng);
 | 
						|
    auto result = shonan.run(initial);
 | 
						|
 | 
						|
    // Parse file again to set up translation problem, adding a prior
 | 
						|
    boost::tie(inputGraph, posesInFile) = load3D(inputFile);
 | 
						|
    auto priorModel = noiseModel::Unit::Create(6);
 | 
						|
    inputGraph->addPrior(0, posesInFile->at<Pose3>(0), priorModel);
 | 
						|
 | 
						|
    cout << "recovering 3D translations" << endl;
 | 
						|
    auto poseGraph = initialize::buildPoseGraph<Pose3>(*inputGraph);
 | 
						|
    poses = initialize::computePoses<Pose3>(result.first, &poseGraph);
 | 
						|
  } else {
 | 
						|
    cout << "Can only run SO(2) or SO(3) averaging\n" << desc << endl;
 | 
						|
    return 1;
 | 
						|
  }
 | 
						|
  cout << "Writing result to " << outputFile << endl;
 | 
						|
  writeG2o(NonlinearFactorGraph(), poses, outputFile);
 | 
						|
  return 0;
 | 
						|
}
 | 
						|
 | 
						|
/* ************************************************************************* */
 |