34 #include <boost/property_tree/json_parser.hpp>
35 #include <boost/property_tree/ptree.hpp>
50 std::string data_type =
"individual";
51 std::string quality =
"high";
52 std::string mesher =
"poisson";
62 "{individual, video, internet}");
63 options.
AddDefaultOption(
"quality", &quality,
"{low, medium, high, extreme}");
74 options.
Parse(argc, argv);
77 if (data_type ==
"individual") {
80 }
else if (data_type ==
"video") {
83 }
else if (data_type ==
"internet") {
87 LOG(FATAL) <<
"Invalid data type provided";
91 if (quality ==
"low") {
92 reconstruction_options.
quality =
94 }
else if (quality ==
"medium") {
95 reconstruction_options.
quality =
97 }
else if (quality ==
"high") {
98 reconstruction_options.
quality =
100 }
else if (quality ==
"extreme") {
101 reconstruction_options.
quality =
104 LOG(FATAL) <<
"Invalid quality provided";
108 if (mesher ==
"poisson") {
109 reconstruction_options.
mesher =
111 }
else if (mesher ==
"delaunay") {
112 reconstruction_options.
mesher =
115 LOG(FATAL) <<
"Invalid mesher provided";
123 &reconstruction_manager);
127 &reconstruction_manager);
136 std::string input_path;
137 std::string output_path;
143 options.
Parse(argc, argv);
146 std::cerr <<
"ERROR: `input_path` is not a directory" <<
std::endl;
151 std::cerr <<
"ERROR: `output_path` is not a directory" <<
std::endl;
156 reconstruction.
Read(input_path);
159 ba_controller.
Start();
160 ba_controller.
Wait();
162 reconstruction.
Write(output_path);
168 std::string input_path;
169 std::string output_path;
175 options.
Parse(argc, argv);
178 reconstruction.
Read(input_path);
180 reconstruction.
Write(output_path);
186 std::string input_path;
187 std::string output_path;
188 std::string image_list_path;
197 options.
Parse(argc, argv);
200 std::cerr <<
"ERROR: `output_path` is not a directory." <<
std::endl;
204 if (!image_list_path.empty()) {
206 options.
mapper->image_names =
207 std::unordered_set<std::string>(image_names.begin(), image_names.end());
211 if (input_path !=
"") {
213 std::cerr <<
"ERROR: `input_path` is not a directory." <<
std::endl;
216 reconstruction_manager.
Read(input_path);
221 &reconstruction_manager);
226 size_t prev_num_reconstructions = 0;
227 if (input_path ==
"") {
232 if (reconstruction_manager.
Size() > prev_num_reconstructions) {
233 const std::string reconstruction_path = JoinPaths(
234 output_path, std::to_string(prev_num_reconstructions));
235 const auto& reconstruction =
236 reconstruction_manager.Get(prev_num_reconstructions);
237 CreateDirIfNotExists(reconstruction_path);
238 reconstruction.Write(reconstruction_path);
239 options.Write(JoinPaths(reconstruction_path,
"project.ini"));
240 prev_num_reconstructions = reconstruction_manager.Size();
248 if (reconstruction_manager.
Size() == 0) {
249 std::cerr <<
"ERROR: failed to create sparse model" <<
std::endl;
255 if (input_path !=
"" && reconstruction_manager.
Size() > 0) {
256 reconstruction_manager.
Get(0).
Write(output_path);
265 std::string output_path;
277 options.
Parse(argc, argv);
280 std::cerr <<
"ERROR: `output_path` is not a directory." <<
std::endl;
287 hierarchical_options, clustering_options, *options.
mapper,
288 &reconstruction_manager);
289 hierarchical_mapper.
Start();
290 hierarchical_mapper.
Wait();
292 if (reconstruction_manager.
Size() == 0) {
293 std::cerr <<
"ERROR: failed to create sparse model" <<
std::endl;
297 reconstruction_manager.
Write(output_path, &options);
303 std::string input_path;
304 std::string output_path;
306 size_t min_track_len = 2;
307 double max_reproj_error = 4.0;
308 double min_tri_angle = 1.5;
316 options.
Parse(argc, argv);
319 reconstruction.
Read(input_path);
321 size_t num_filtered =
324 for (
const auto point3D_id : reconstruction.
Point3DIds()) {
325 const auto& point3D = reconstruction.
Point3D(point3D_id);
326 if (point3D.Track().Length() < min_track_len) {
332 std::cout <<
"Filtered observations: " << num_filtered <<
std::endl;
334 reconstruction.
Write(output_path);
340 std::string input_path;
341 std::string output_path;
342 bool clear_points =
false;
350 "clear_points", &clear_points,
351 "Whether to clear all existing points and observations");
353 options.
Parse(argc, argv);
356 std::cerr <<
"ERROR: `input_path` is not a directory" <<
std::endl;
361 std::cerr <<
"ERROR: `output_path` is not a directory" <<
std::endl;
365 const auto& mapper_options = *options.
mapper;
370 reconstruction.
Read(input_path);
382 const size_t min_num_matches =
383 static_cast<size_t>(mapper_options.min_num_matches);
384 database_cache.
Load(database, min_num_matches,
385 mapper_options.ignore_watermarks,
386 mapper_options.image_names);
400 <<
"Need at least two images for triangulation";
409 const auto tri_options = mapper_options.Triangulation();
411 const auto& reg_image_ids = reconstruction.
RegImageIds();
413 for (
size_t i = 0; i < reg_image_ids.size(); ++i) {
414 const image_t image_id = reg_image_ids[i];
416 const auto&
image = reconstruction.
Image(image_id);
420 const size_t num_existing_points3D =
image.NumPoints3D();
422 std::cout <<
" => Image sees " << num_existing_points3D <<
" / "
427 std::cout <<
" => Triangulated "
428 << (
image.NumPoints3D() - num_existing_points3D) <<
" points"
444 auto ba_options = mapper_options.GlobalBundleAdjustment();
445 ba_options.refine_focal_length =
false;
446 ba_options.refine_principal_point =
false;
447 ba_options.refine_extra_params =
false;
448 ba_options.refine_extrinsics =
false;
456 for (
int i = 0; i < mapper_options.ba_global_max_refinements; ++i) {
464 CHECK(bundle_adjuster.
Solve(&reconstruction));
466 size_t num_changed_observations = 0;
468 num_changed_observations +=
FilterPoints(mapper_options, &mapper);
469 const double changed =
470 static_cast<double>(num_changed_observations) / num_observations;
471 std::cout <<
StringPrintf(
" => Changed observations: %.6f", changed)
473 if (changed < mapper_options.ba_global_max_refinement_change) {
481 const bool kDiscardReconstruction =
false;
484 reconstruction.
Write(output_path);
570 std::vector<CameraRig> ReadCameraRigConfig(
const std::string& rig_config_path,
571 const Reconstruction& reconstruction,
572 bool estimate_rig_relative_poses) {
573 boost::property_tree::ptree pt;
574 boost::property_tree::read_json(rig_config_path.c_str(), pt);
576 std::vector<CameraRig> camera_rigs;
577 for (
const auto& rig_config : pt) {
578 CameraRig camera_rig;
580 std::vector<std::string> image_prefixes;
581 for (
const auto& camera : rig_config.second.get_child(
"cameras")) {
582 const int camera_id = camera.second.get<
int>(
"camera_id");
583 image_prefixes.push_back(camera.second.get<std::string>(
"image_prefix"));
584 Eigen::Vector3d rel_tvec;
585 Eigen::Vector4d rel_qvec;
587 auto rel_tvec_node = camera.second.get_child_optional(
"rel_tvec");
589 for (
const auto& node : rel_tvec_node.get()) {
590 rel_tvec[index++] = node.second.get_value<
double>();
593 estimate_rig_relative_poses =
true;
596 auto rel_qvec_node = camera.second.get_child_optional(
"rel_qvec");
598 for (
const auto& node : rel_qvec_node.get()) {
599 rel_qvec[index++] = node.second.get_value<
double>();
602 estimate_rig_relative_poses =
true;
605 camera_rig.AddCamera(camera_id, rel_qvec, rel_tvec);
608 camera_rig.SetRefCameraId(rig_config.second.get<
int>(
"ref_camera_id"));
610 std::unordered_map<std::string, std::vector<image_t>> snapshots;
611 for (
const auto image_id : reconstruction.RegImageIds()) {
612 const auto&
image = reconstruction.Image(image_id);
613 for (
const auto& image_prefix : image_prefixes) {
615 const std::string image_suffix =
617 snapshots[image_suffix].push_back(image_id);
622 for (
const auto& snapshot : snapshots) {
623 bool has_ref_camera =
false;
624 for (
const auto image_id : snapshot.second) {
625 const auto&
image = reconstruction.Image(image_id);
626 if (
image.CameraId() == camera_rig.RefCameraId()) {
627 has_ref_camera =
true;
631 if (has_ref_camera) {
632 camera_rig.AddSnapshot(snapshot.second);
636 camera_rig.Check(reconstruction);
637 if (estimate_rig_relative_poses) {
639 if (!camera_rig.ComputeRelativePoses(reconstruction)) {
640 std::cout <<
"WARN: Failed to estimate rig poses from reconstruction; "
643 return std::vector<CameraRig>();
647 camera_rigs.push_back(camera_rig);
656 std::string input_path;
657 std::string output_path;
658 std::string rig_config_path;
659 bool estimate_rig_relative_poses =
true;
668 &estimate_rig_relative_poses);
672 options.
Parse(argc, argv);
675 reconstruction.
Read(input_path);
679 auto camera_rigs = ReadCameraRigConfig(rig_config_path, reconstruction,
680 estimate_rig_relative_poses);
683 for (
size_t i = 0; i < camera_rigs.size(); ++i) {
684 const auto& camera_rig = camera_rigs[i];
686 std::cout <<
StringPrintf(
"Cameras: %d", camera_rig.NumCameras())
688 std::cout <<
StringPrintf(
"Snapshots: %d", camera_rig.NumSnapshots())
692 for (
const auto image_id : reconstruction.
RegImageIds()) {
702 CHECK(bundle_adjuster.
Solve(&reconstruction, &camera_rigs));
704 reconstruction.
Write(output_path);
std::shared_ptr< core::Tensor > image
bool Solve(Reconstruction *reconstruction)
void AddImage(const image_t image_id)
void Load(const Database &database, const size_t min_num_matches, const bool ignore_watermarks, const std::unordered_set< std::string > &image_names)
@ LAST_IMAGE_REG_CALLBACK
void EndReconstruction(const bool discard)
void BeginReconstruction(Reconstruction *reconstruction)
size_t TriangulateImage(const IncrementalTriangulator::Options &tri_options, const image_t image_id)
void AddRequiredOption(const std::string &name, T *option, const std::string &help_text="")
void AddBundleAdjustmentOptions()
void AddDefaultOption(const std::string &name, T *option, const std::string &help_text="")
std::shared_ptr< std::string > database_path
std::shared_ptr< BundleAdjustmentOptions > bundle_adjustment
std::shared_ptr< IncrementalMapperOptions > mapper
void AddDatabaseOptions()
void Parse(const int argc, char **argv)
std::shared_ptr< std::string > image_path
const class Track & Track() const
const Reconstruction & Get(const size_t idx) const
size_t Read(const std::string &path)
void Write(const std::string &path, const OptionManager *options) const
void ExtractColorsForAllImages(const std::string &path)
size_t FilterAllPoints3D(const double max_reproj_error, const double min_tri_angle)
size_t NumRegImages() const
size_t FilterObservationsWithNegativeDepth()
void Write(const std::string &path) const
void DeleteAllPoints2DAndPoints3D()
size_t ComputeNumObservations() const
const class Image & Image(const image_t image_id) const
std::unordered_set< point3D_t > Point3DIds() const
const std::vector< image_t > & RegImageIds() const
void DeletePoint3D(const point3D_t point3D_id)
void Read(const std::string &path)
const class Point3D & Point3D(const point3D_t point3D_id) const
void TranscribeImageIdsToDatabase(const Database &database)
bool Solve(Reconstruction *reconstruction, std::vector< CameraRig > *camera_rigs)
void AddCallback(const int id, const std::function< void()> &func)
void PrintMinutes() const
QTextStream & endl(QTextStream &stream)
std::string StringGetAfter(const std::string &str, const std::string &key)
void PrintHeading2(const std::string &heading)
void RunThreadWithOpenGLContext(Thread *thread)
int RunColorExtractor(int argc, char **argv)
void StringToLower(std::string *str)
size_t CompleteAndMergeTracks(const IncrementalMapperOptions &options, IncrementalMapper *mapper)
int RunPointTriangulator(int argc, char **argv)
int RunHierarchicalMapper(int argc, char **argv)
std::vector< std::string > ReadTextFileLines(const std::string &path)
bool ExistsDir(const std::string &path)
int RunMapper(int argc, char **argv)
int RunRigBundleAdjuster(int argc, char **argv)
void PrintHeading1(const std::string &heading)
std::string StringPrintf(const char *format,...)
int RunAutomaticReconstructor(int argc, char **argv)
int RunBundleAdjuster(int argc, char **argv)
bool StringContains(const std::string &str, const std::string &sub_str)
int RunPointFiltering(int argc, char **argv)
size_t FilterPoints(const IncrementalMapperOptions &options, IncrementalMapper *mapper)
std::string workspace_path
std::string vocab_tree_path
ceres::Solver::Options solver_options
std::string database_path
bool refine_relative_poses