Colmap最终编译结果为一个可执行程序,可以通过命令行调用,具体代码如下
#include "colmap/exe/database.h"
#include "colmap/exe/feature.h"
#include "colmap/exe/gui.h"
#include "colmap/exe/image.h"
#include "colmap/exe/model.h"
#include "colmap/exe/mvs.h"
#include "colmap/exe/sfm.h"
#include "colmap/exe/vocab_tree.h"
#include "colmap/util/version.h"
namespace {
typedef std::function<int(int, char**)> command_func_t;
int ShowHelp(
const std::vector<std::pair<std::string, command_func_t>>& commands) {
std::cout << colmap::StringPrintf(
"%s -- Structure-from-Motion and Multi-View Stereo\n(%s)",
colmap::GetVersionInfo().c_str(),
colmap::GetBuildInfo().c_str())
<< std::endl
<< std::endl;
std::cout << "Usage:" << std::endl;
std::cout << " colmap [command] [options]" << std::endl << std::endl;
std::cout << "Documentation:" << std::endl;
std::cout << " https://colmap.github.io/" << std::endl << std::endl;
std::cout << "Example usage:" << std::endl;
std::cout << " colmap help [ -h, --help ]" << std::endl;
std::cout << " colmap gui" << std::endl;
std::cout << " colmap gui -h [ --help ]" << std::endl;
std::cout << " colmap automatic_reconstructor -h [ --help ]" << std::endl;
std::cout << " colmap automatic_reconstructor --image_path IMAGES "
"--workspace_path WORKSPACE"
<< std::endl;
std::cout << " colmap feature_extractor --image_path IMAGES --database_path "
"DATABASE"
<< std::endl;
std::cout << " colmap exhaustive_matcher --database_path DATABASE"
<< std::endl;
std::cout << " colmap mapper --image_path IMAGES --database_path DATABASE "
"--output_path MODEL"
<< std::endl;
std::cout << " ..." << std::endl << std::endl;
std::cout << "Available commands:" << std::endl;
std::cout << " help" << std::endl;
for (const auto& command : commands) {
std::cout << " " << command.first << std::endl;
}
std::cout << std::endl;
return EXIT_SUCCESS;
}
} // namespace
int main(int argc, char** argv) {
colmap::InitializeGlog(argv);
#if defined(COLMAP_GUI_ENABLED)
Q_INIT_RESOURCE(resources);
#endif
//string - function
std::vector<std::pair<std::string, command_func_t>> commands;
commands.emplace_back("gui", &colmap::RunGraphicalUserInterface);
commands.emplace_back("automatic_reconstructor",&colmap::RunAutomaticReconstructor);
commands.emplace_back("bundle_adjuster", &colmap::RunBundleAdjuster);
commands.emplace_back("color_extractor", &colmap::RunColorExtractor);
commands.emplace_back("database_cleaner", &colmap::RunDatabaseCleaner);
commands.emplace_back("database_creator", &colmap::RunDatabaseCreator);
commands.emplace_back("database_merger", &colmap::RunDatabaseMerger);
commands.emplace_back("delaunay_mesher", &colmap::RunDelaunayMesher);
commands.emplace_back("exhaustive_matcher", &colmap::RunExhaustiveMatcher);
commands.emplace_back("feature_extractor", &colmap::RunFeatureExtractor);
commands.emplace_back("feature_importer", &colmap::RunFeatureImporter);
commands.emplace_back("hierarchical_mapper", &colmap::RunHierarchicalMapper);
commands.emplace_back("image_deleter", &colmap::RunImageDeleter);
commands.emplace_back("image_filterer", &colmap::RunImageFilterer);
commands.emplace_back("image_rectifier", &colmap::RunImageRectifier);
commands.emplace_back("image_registrator", &colmap::RunImageRegistrator);
commands.emplace_back("image_undistorter", &colmap::RunImageUndistorter);
commands.emplace_back("image_undistorter_standalone",&colmap::RunImageUndistorterStandalone);
commands.emplace_back("mapper", &colmap::RunMapper);
commands.emplace_back("matches_importer", &colmap::RunMatchesImporter);
commands.emplace_back("model_aligner", &colmap::RunModelAligner);
commands.emplace_back("model_analyzer", &colmap::RunModelAnalyzer);
commands.emplace_back("model_comparer", &colmap::RunModelComparer);
commands.emplace_back("model_converter", &colmap::RunModelConverter);
commands.emplace_back("model_cropper", &colmap::RunModelCropper);
commands.emplace_back("model_merger", &colmap::RunModelMerger);
commands.emplace_back("model_orientation_aligner",&colmap::RunModelOrientationAligner);
commands.emplace_back("model_splitter", &colmap::RunModelSplitter);
commands.emplace_back("model_transformer", &colmap::RunModelTransformer);
commands.emplace_back("patch_match_stereo", &colmap::RunPatchMatchStereo);
commands.emplace_back("point_filtering", &colmap::RunPointFiltering);
commands.emplace_back("point_triangulator", &colmap::RunPointTriangulator);
commands.emplace_back("poisson_mesher", &colmap::RunPoissonMesher);
commands.emplace_back("project_generator", &colmap::RunProjectGenerator);
commands.emplace_back("rig_bundle_adjuster", &colmap::RunRigBundleAdjuster);
commands.emplace_back("sequential_matcher", &colmap::RunSequentialMatcher);
commands.emplace_back("spatial_matcher", &colmap::RunSpatialMatcher);
commands.emplace_back("stereo_fusion", &colmap::RunStereoFuser);
commands.emplace_back("transitive_matcher", &colmap::RunTransitiveMatcher);
commands.emplace_back("vocab_tree_builder", &colmap::RunVocabTreeBuilder);
commands.emplace_back("vocab_tree_matcher", &colmap::RunVocabTreeMatcher);
commands.emplace_back("vocab_tree_retriever", &colmap::RunVocabTreeRetriever);
if (argc == 1) {
return ShowHelp(commands);
}
const std::string command = argv[1];
if (command == "help" || command == "-h" || command == "--help") {
return ShowHelp(commands);
} else {
//find call func
command_func_t matched_command_func = nullptr;
for (const auto& command_func : commands) {
if (command == command_func.first) {
matched_command_func = command_func.second;
break;
}
}
//if not find
if (matched_command_func == nullptr) {
LOG(ERROR) << colmap::StringPrintf(
"Command `%s` not recognized. To list the "
"available commands, run `colmap help`.",
command.c_str());
return EXIT_FAILURE;
} else {
//start func
int command_argc = argc - 1;
char** command_argv = &argv[1];
command_argv[0] = argv[0];
return matched_command_func(command_argc, command_argv);
}
}
return ShowHelp(commands);
}
可以看出commands中存储了所有可以执行的功能,接下来看一下RunAutomaticReconstructor中是如何执行的。首先需要设置 reconstruction_options,从命令行中读取的参数设置工作空间的目录以及AutomaticReconstructionController::Options中存储了一些默认值参数。然后构造 auto reconstruction_manager = std::make_shared();然后构造 AutomaticReconstructionController controller(reconstruction_options,reconstruction_manager)线程(源代码中controllers中都是线程;然后启动这个主线程,主线程中再执行其他线程
int RunAutomaticReconstructor(int argc, char** argv) {
AutomaticReconstructionController::Options reconstruction_options;
std::string data_type = "individual";
std::string quality = "high";
std::string mesher = "poisson";
OptionManager options;
options.AddRequiredOption("workspace_path",
&reconstruction_options.workspace_path);
options.AddRequiredOption("image_path", &reconstruction_options.image_path);
options.AddDefaultOption("mask_path", &reconstruction_options.mask_path);
options.AddDefaultOption("vocab_tree_path",
&reconstruction_options.vocab_tree_path);
options.AddDefaultOption(
"data_type", &data_type, "{individual, video, internet}");
options.AddDefaultOption("quality", &quality, "{low, medium, high, extreme}");
options.AddDefaultOption("camera_model",
&reconstruction_options.camera_model);
options.AddDefaultOption("single_camera",
&reconstruction_options.single_camera);
options.AddDefaultOption("camera_params",
&reconstruction_options.camera_params);
options.AddDefaultOption("sparse", &reconstruction_options.sparse);
options.AddDefaultOption("dense", &reconstruction_options.dense);
options.AddDefaultOption("mesher", &mesher, "{poisson, delaunay}");
options.AddDefaultOption("num_threads", &reconstruction_options.num_threads);
options.AddDefaultOption("use_gpu", &reconstruction_options.use_gpu);
options.AddDefaultOption("gpu_index", &reconstruction_options.gpu_index);
options.Parse(argc, argv);
StringToLower(&data_type);
if (data_type == "individual") {
reconstruction_options.data_type =
AutomaticReconstructionController::DataType::INDIVIDUAL;
} else if (data_type == "video") {
reconstruction_options.data_type =
AutomaticReconstructionController::DataType::VIDEO;
} else if (data_type == "internet") {
reconstruction_options.data_type =
AutomaticReconstructionController::DataType::INTERNET;
} else {
LOG(FATAL) << "Invalid data type provided";
}
StringToLower(&quality);
if (quality == "low") {
reconstruction_options.quality =
AutomaticReconstructionController::Quality::LOW;
} else if (quality == "medium") {
reconstruction_options.quality =
AutomaticReconstructionController::Quality::MEDIUM;
} else if (quality == "high") {
reconstruction_options.quality =
AutomaticReconstructionController::Quality::HIGH;
} else if (quality == "extreme") {
reconstruction_options.quality =
AutomaticReconstructionController::Quality::EXTREME;
} else {
LOG(FATAL) << "Invalid quality provided";
}
StringToLower(&mesher);
if (mesher == "poisson") {
reconstruction_options.mesher =
AutomaticReconstructionController::Mesher::POISSON;
} else if (mesher == "delaunay") {
reconstruction_options.mesher =
AutomaticReconstructionController::Mesher::DELAUNAY;
} else {
LOG(FATAL) << "Invalid mesher provided";
}
auto reconstruction_manager = std::make_shared<ReconstructionManager>();
if (reconstruction_options.use_gpu && kUseOpenGL) {
QApplication app(argc, argv);
AutomaticReconstructionController controller(reconstruction_options,
reconstruction_manager);
RunThreadWithOpenGLContext(&controller);
} else {
AutomaticReconstructionController controller(reconstruction_options,
reconstruction_manager);
controller.Start();
controller.Wait();
}
return EXIT_SUCCESS;
}
线程启动后,依次执行特征提取、特征匹配、稀疏重建和稠密重建线程:
void AutomaticReconstructionController::Run() {
if (IsStopped()) {
return;
}
RunFeatureExtraction();
if (IsStopped()) {
return;
}
RunFeatureMatching();
if (IsStopped()) {
return;
}
if (options_.sparse) {
RunSparseMapper();
}
if (IsStopped()) {
return;
}
if (options_.dense) {
RunDenseMapper();
}
}
剩下的源代码需要慢慢品味了。。。下次再补上