// 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/feature.h" #include "base/camera_models.h" #include "base/image_reader.h" #include "exe/gui.h" #include "feature/extraction.h" #include "feature/matching.h" #include "util/misc.h" #include "util/opengl_utils.h" #include "util/option_manager.h" namespace colmap { namespace { bool VerifyCameraParams(const std::string& camera_model, const std::string& params) { if (!ExistsCameraModelWithName(camera_model)) { std::cerr << "ERROR: Camera model does not exist" << std::endl; return false; } const std::vector camera_params = CSVToVector(params); const int camera_model_id = CameraModelNameToId(camera_model); if (camera_params.size() > 0 && !CameraModelVerifyParams(camera_model_id, camera_params)) { std::cerr << "ERROR: Invalid camera parameters" << std::endl; return false; } return true; } bool VerifySiftGPUParams(const bool use_gpu) { #if !defined(CUDA_ENABLED) && !defined(OPENGL_ENABLED) if (use_gpu) { std::cerr << "ERROR: Cannot use Sift GPU without CUDA or OpenGL support; " "set SiftExtraction.use_gpu or SiftMatching.use_gpu to false." << std::endl; return false; } #endif return true; } } // namespace void UpdateImageReaderOptionsFromCameraMode(ImageReaderOptions& options, CameraMode mode) { switch (mode) { case CameraMode::AUTO: options.single_camera = false; options.single_camera_per_folder = false; options.single_camera_per_image = false; break; case CameraMode::SINGLE: options.single_camera = true; options.single_camera_per_folder = false; options.single_camera_per_image = false; break; case CameraMode::PER_FOLDER: options.single_camera = false; options.single_camera_per_folder = true; options.single_camera_per_image = false; break; case CameraMode::PER_IMAGE: options.single_camera = false; options.single_camera_per_folder = false; options.single_camera_per_image = true; break; } } int RunFeatureExtractor(int argc, char** argv) { std::string image_list_path; int camera_mode = -1; std::string descriptor_normalization = "l1_root"; OptionManager options; options.AddDatabaseOptions(); options.AddImageOptions(); options.AddDefaultOption("camera_mode", &camera_mode); options.AddDefaultOption("image_list_path", &image_list_path); options.AddDefaultOption("descriptor_normalization", &descriptor_normalization, "{'l1_root', 'l2'}"); options.AddExtractionOptions(); options.Parse(argc, argv); ImageReaderOptions reader_options = *options.image_reader; reader_options.database_path = *options.database_path; reader_options.image_path = *options.image_path; if (camera_mode >= 0) { UpdateImageReaderOptionsFromCameraMode(reader_options, (CameraMode)camera_mode); } StringToLower(&descriptor_normalization); if (descriptor_normalization == "l1_root") { options.sift_extraction->normalization = SiftExtractionOptions::Normalization::L1_ROOT; } else if (descriptor_normalization == "l2") { options.sift_extraction->normalization = SiftExtractionOptions::Normalization::L2; } else { std::cerr << "ERROR: Invalid `descriptor_normalization`" << std::endl; return EXIT_FAILURE; } if (!image_list_path.empty()) { reader_options.image_list = ReadTextFileLines(image_list_path); if (reader_options.image_list.empty()) { return EXIT_SUCCESS; } } if (!ExistsCameraModelWithName(reader_options.camera_model)) { std::cerr << "ERROR: Camera model does not exist" << std::endl; } if (!VerifyCameraParams(reader_options.camera_model, reader_options.camera_params)) { return EXIT_FAILURE; } if (!VerifySiftGPUParams(options.sift_extraction->use_gpu)) { return EXIT_FAILURE; } std::unique_ptr app; if (options.sift_extraction->use_gpu && kUseOpenGL) { app.reset(new QApplication(argc, argv)); } SiftFeatureExtractor feature_extractor(reader_options, *options.sift_extraction); if (options.sift_extraction->use_gpu && kUseOpenGL) { RunThreadWithOpenGLContext(&feature_extractor); } else { feature_extractor.Start(); feature_extractor.Wait(); } return EXIT_SUCCESS; } int RunFeatureImporter(int argc, char** argv) { std::string import_path; std::string image_list_path; int camera_mode = -1; OptionManager options; options.AddDatabaseOptions(); options.AddImageOptions(); options.AddDefaultOption("camera_mode", &camera_mode); options.AddRequiredOption("import_path", &import_path); options.AddDefaultOption("image_list_path", &image_list_path); options.AddExtractionOptions(); options.Parse(argc, argv); ImageReaderOptions reader_options = *options.image_reader; reader_options.database_path = *options.database_path; reader_options.image_path = *options.image_path; if (camera_mode >= 0) { UpdateImageReaderOptionsFromCameraMode(reader_options, (CameraMode)camera_mode); } if (!image_list_path.empty()) { reader_options.image_list = ReadTextFileLines(image_list_path); if (reader_options.image_list.empty()) { return EXIT_SUCCESS; } } if (!VerifyCameraParams(reader_options.camera_model, reader_options.camera_params)) { return EXIT_FAILURE; } FeatureImporter feature_importer(reader_options, import_path); feature_importer.Start(); feature_importer.Wait(); return EXIT_SUCCESS; } int RunExhaustiveMatcher(int argc, char** argv) { OptionManager options; options.AddDatabaseOptions(); options.AddExhaustiveMatchingOptions(); options.Parse(argc, argv); if (!VerifySiftGPUParams(options.sift_matching->use_gpu)) { return EXIT_FAILURE; } std::unique_ptr app; if (options.sift_matching->use_gpu && kUseOpenGL) { app.reset(new QApplication(argc, argv)); } ExhaustiveFeatureMatcher feature_matcher(*options.exhaustive_matching, *options.sift_matching, *options.database_path); if (options.sift_matching->use_gpu && kUseOpenGL) { RunThreadWithOpenGLContext(&feature_matcher); } else { feature_matcher.Start(); feature_matcher.Wait(); } return EXIT_SUCCESS; } int RunMatchesImporter(int argc, char** argv) { std::string match_list_path; std::string match_type = "pairs"; OptionManager options; options.AddDatabaseOptions(); options.AddRequiredOption("match_list_path", &match_list_path); options.AddDefaultOption("match_type", &match_type, "{'pairs', 'raw', 'inliers'}"); options.AddMatchingOptions(); options.Parse(argc, argv); if (!VerifySiftGPUParams(options.sift_matching->use_gpu)) { return EXIT_FAILURE; } std::unique_ptr app; if (options.sift_matching->use_gpu && kUseOpenGL) { app.reset(new QApplication(argc, argv)); } std::unique_ptr feature_matcher; if (match_type == "pairs") { ImagePairsMatchingOptions matcher_options; matcher_options.match_list_path = match_list_path; feature_matcher.reset(new ImagePairsFeatureMatcher( matcher_options, *options.sift_matching, *options.database_path)); } else if (match_type == "raw" || match_type == "inliers") { FeaturePairsMatchingOptions matcher_options; matcher_options.match_list_path = match_list_path; matcher_options.verify_matches = match_type == "raw"; feature_matcher.reset(new FeaturePairsFeatureMatcher( matcher_options, *options.sift_matching, *options.database_path)); } else { std::cerr << "ERROR: Invalid `match_type`"; return EXIT_FAILURE; } if (options.sift_matching->use_gpu && kUseOpenGL) { RunThreadWithOpenGLContext(feature_matcher.get()); } else { feature_matcher->Start(); feature_matcher->Wait(); } return EXIT_SUCCESS; } int RunSequentialMatcher(int argc, char** argv) { OptionManager options; options.AddDatabaseOptions(); options.AddSequentialMatchingOptions(); options.Parse(argc, argv); if (!VerifySiftGPUParams(options.sift_matching->use_gpu)) { return EXIT_FAILURE; } std::unique_ptr app; if (options.sift_matching->use_gpu && kUseOpenGL) { app.reset(new QApplication(argc, argv)); } SequentialFeatureMatcher feature_matcher(*options.sequential_matching, *options.sift_matching, *options.database_path); if (options.sift_matching->use_gpu && kUseOpenGL) { RunThreadWithOpenGLContext(&feature_matcher); } else { feature_matcher.Start(); feature_matcher.Wait(); } return EXIT_SUCCESS; } int RunSpatialMatcher(int argc, char** argv) { OptionManager options; options.AddDatabaseOptions(); options.AddSpatialMatchingOptions(); options.Parse(argc, argv); if (!VerifySiftGPUParams(options.sift_matching->use_gpu)) { return EXIT_FAILURE; } std::unique_ptr app; if (options.sift_matching->use_gpu && kUseOpenGL) { app.reset(new QApplication(argc, argv)); } SpatialFeatureMatcher feature_matcher(*options.spatial_matching, *options.sift_matching, *options.database_path); if (options.sift_matching->use_gpu && kUseOpenGL) { RunThreadWithOpenGLContext(&feature_matcher); } else { feature_matcher.Start(); feature_matcher.Wait(); } return EXIT_SUCCESS; } int RunTransitiveMatcher(int argc, char** argv) { OptionManager options; options.AddDatabaseOptions(); options.AddTransitiveMatchingOptions(); options.Parse(argc, argv); if (!VerifySiftGPUParams(options.sift_matching->use_gpu)) { return EXIT_FAILURE; } std::unique_ptr app; if (options.sift_matching->use_gpu && kUseOpenGL) { app.reset(new QApplication(argc, argv)); } TransitiveFeatureMatcher feature_matcher(*options.transitive_matching, *options.sift_matching, *options.database_path); if (options.sift_matching->use_gpu && kUseOpenGL) { RunThreadWithOpenGLContext(&feature_matcher); } else { feature_matcher.Start(); feature_matcher.Wait(); } return EXIT_SUCCESS; } int RunVocabTreeMatcher(int argc, char** argv) { OptionManager options; options.AddDatabaseOptions(); options.AddVocabTreeMatchingOptions(); options.Parse(argc, argv); if (!VerifySiftGPUParams(options.sift_matching->use_gpu)) { return EXIT_FAILURE; } std::unique_ptr app; if (options.sift_matching->use_gpu && kUseOpenGL) { app.reset(new QApplication(argc, argv)); } VocabTreeFeatureMatcher feature_matcher(*options.vocab_tree_matching, *options.sift_matching, *options.database_path); if (options.sift_matching->use_gpu && kUseOpenGL) { RunThreadWithOpenGLContext(&feature_matcher); } else { feature_matcher.Start(); feature_matcher.Wait(); } return EXIT_SUCCESS; } } // namespace colmap