camenduru's picture
ceres-solver and colmap
7b7496d
// Copyright (c) 2022, ETH Zurich and UNC Chapel Hill.
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// * Neither the name of ETH Zurich and UNC Chapel Hill nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// Author: Johannes L. Schoenberger (jsch-at-demuc-dot-de)
#include "exe/mvs.h"
#include "base/reconstruction.h"
#include "mvs/fusion.h"
#include "mvs/meshing.h"
#include "mvs/patch_match.h"
#include "util/misc.h"
#include "util/option_manager.h"
namespace colmap {
int RunDelaunayMesher(int argc, char** argv) {
#ifndef CGAL_ENABLED
std::cerr << "ERROR: Delaunay meshing requires CGAL, which is not "
"available on your system."
<< std::endl;
return EXIT_FAILURE;
#else // CGAL_ENABLED
std::string input_path;
std::string input_type = "dense";
std::string output_path;
OptionManager options;
options.AddRequiredOption(
"input_path", &input_path,
"Path to either the dense workspace folder or the sparse reconstruction");
options.AddDefaultOption("input_type", &input_type, "{dense, sparse}");
options.AddRequiredOption("output_path", &output_path);
options.AddDelaunayMeshingOptions();
options.Parse(argc, argv);
StringToLower(&input_type);
if (input_type == "sparse") {
mvs::SparseDelaunayMeshing(*options.delaunay_meshing, input_path,
output_path);
} else if (input_type == "dense") {
mvs::DenseDelaunayMeshing(*options.delaunay_meshing, input_path,
output_path);
} else {
std::cout << "ERROR: Invalid input type - "
"supported values are 'sparse' and 'dense'."
<< std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
#endif // CGAL_ENABLED
}
int RunPatchMatchStereo(int argc, char** argv) {
#ifndef CUDA_ENABLED
std::cerr << "ERROR: Dense stereo reconstruction requires CUDA, which is not "
"available on your system."
<< std::endl;
return EXIT_FAILURE;
#else // CUDA_ENABLED
std::string workspace_path;
std::string workspace_format = "COLMAP";
std::string pmvs_option_name = "option-all";
std::string config_path;
OptionManager options;
options.AddRequiredOption(
"workspace_path", &workspace_path,
"Path to the folder containing the undistorted images");
options.AddDefaultOption("workspace_format", &workspace_format,
"{COLMAP, PMVS}");
options.AddDefaultOption("pmvs_option_name", &pmvs_option_name);
options.AddDefaultOption("config_path", &config_path);
options.AddPatchMatchStereoOptions();
options.Parse(argc, argv);
StringToLower(&workspace_format);
if (workspace_format != "colmap" && workspace_format != "pmvs") {
std::cout << "ERROR: Invalid `workspace_format` - supported values are "
"'COLMAP' or 'PMVS'."
<< std::endl;
return EXIT_FAILURE;
}
mvs::PatchMatchController controller(*options.patch_match_stereo,
workspace_path, workspace_format,
pmvs_option_name, config_path);
controller.Start();
controller.Wait();
return EXIT_SUCCESS;
#endif // CUDA_ENABLED
}
int RunPoissonMesher(int argc, char** argv) {
std::string input_path;
std::string output_path;
OptionManager options;
options.AddRequiredOption("input_path", &input_path);
options.AddRequiredOption("output_path", &output_path);
options.AddPoissonMeshingOptions();
options.Parse(argc, argv);
CHECK(mvs::PoissonMeshing(*options.poisson_meshing, input_path, output_path));
return EXIT_SUCCESS;
}
int RunStereoFuser(int argc, char** argv) {
std::string workspace_path;
std::string input_type = "geometric";
std::string workspace_format = "COLMAP";
std::string pmvs_option_name = "option-all";
std::string output_type = "PLY";
std::string output_path;
std::string bbox_path;
OptionManager options;
options.AddRequiredOption("workspace_path", &workspace_path);
options.AddDefaultOption("workspace_format", &workspace_format,
"{COLMAP, PMVS}");
options.AddDefaultOption("pmvs_option_name", &pmvs_option_name);
options.AddDefaultOption("input_type", &input_type,
"{photometric, geometric}");
options.AddDefaultOption("output_type", &output_type, "{BIN, TXT, PLY}");
options.AddRequiredOption("output_path", &output_path);
options.AddDefaultOption("bbox_path", &bbox_path);
options.AddStereoFusionOptions();
options.Parse(argc, argv);
StringToLower(&workspace_format);
if (workspace_format != "colmap" && workspace_format != "pmvs") {
std::cout << "ERROR: Invalid `workspace_format` - supported values are "
"'COLMAP' or 'PMVS'."
<< std::endl;
return EXIT_FAILURE;
}
StringToLower(&input_type);
if (input_type != "photometric" && input_type != "geometric") {
std::cout << "ERROR: Invalid input type - supported values are "
"'photometric' and 'geometric'."
<< std::endl;
return EXIT_FAILURE;
}
if (!bbox_path.empty()) {
std::ifstream file(bbox_path);
if (file.is_open()) {
auto& min_bound = options.stereo_fusion->bounding_box.first;
auto& max_bound = options.stereo_fusion->bounding_box.second;
file >> min_bound(0) >> min_bound(1) >> min_bound(2);
file >> max_bound(0) >> max_bound(1) >> max_bound(2);
} else {
std::cout << "WARN: Invalid bounds path: \"" << bbox_path
<< "\" - continuing without bounds check" << std::endl;
}
}
mvs::StereoFusion fuser(*options.stereo_fusion, workspace_path,
workspace_format, pmvs_option_name, input_type);
fuser.Start();
fuser.Wait();
Reconstruction reconstruction;
// read data from sparse reconstruction
if (workspace_format == "colmap") {
reconstruction.Read(JoinPaths(workspace_path, "sparse"));
}
// overwrite sparse point cloud with dense point cloud from fuser
reconstruction.ImportPLY(fuser.GetFusedPoints());
std::cout << "Writing output: " << output_path << std::endl;
// write output
StringToLower(&output_type);
if (output_type == "bin") {
reconstruction.WriteBinary(output_path);
} else if (output_type == "txt") {
reconstruction.WriteText(output_path);
} else if (output_type == "ply") {
WriteBinaryPlyPoints(output_path, fuser.GetFusedPoints());
mvs::WritePointsVisibility(output_path + ".vis",
fuser.GetFusedPointsVisibility());
} else {
std::cerr << "ERROR: Invalid `output_type`" << std::endl;
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
} // namespace colmap