// 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) #ifndef COLMAP_SRC_MVS_FUSION_H_ #define COLMAP_SRC_MVS_FUSION_H_ #include #include #include #include #include "mvs/depth_map.h" #include "mvs/image.h" #include "mvs/mat.h" #include "mvs/model.h" #include "mvs/normal_map.h" #include "mvs/workspace.h" #include "util/alignment.h" #include "util/cache.h" #include "util/math.h" #include "util/ply.h" #include "util/threading.h" namespace colmap { namespace mvs { struct StereoFusionOptions { // Path for PNG masks. Same format expected as ImageReaderOptions. std::string mask_path = ""; // The number of threads to use during fusion. int num_threads = -1; // Maximum image size in either dimension. int max_image_size = -1; // Minimum number of fused pixels to produce a point. int min_num_pixels = 5; // Maximum number of pixels to fuse into a single point. int max_num_pixels = 10000; // Maximum depth in consistency graph traversal. int max_traversal_depth = 100; // Maximum relative difference between measured and projected pixel. double max_reproj_error = 2.0f; // Maximum relative difference between measured and projected depth. double max_depth_error = 0.01f; // Maximum angular difference in degrees of normals of pixels to be fused. double max_normal_error = 10.0f; // Number of overlapping images to transitively check for fusing points. int check_num_images = 50; // Flag indicating whether to use LRU cache or pre-load all data bool use_cache = false; // Cache size in gigabytes for fusion. The fusion keeps the bitmaps, depth // maps, normal maps, and consistency graphs of this number of images in // memory. A higher value leads to less disk access and faster fusion, while // a lower value leads to reduced memory usage. Note that a single image can // consume a lot of memory, if the consistency graph is dense. double cache_size = 32.0; std::pair bounding_box = std::make_pair(Eigen::Vector3f(-FLT_MAX, -FLT_MAX, -FLT_MAX), Eigen::Vector3f(FLT_MAX, FLT_MAX, FLT_MAX)); // Check the options for validity. bool Check() const; // Print the options to stdout. void Print() const; }; class StereoFusion : public Thread { public: EIGEN_MAKE_ALIGNED_OPERATOR_NEW StereoFusion(const StereoFusionOptions& options, const std::string& workspace_path, const std::string& workspace_format, const std::string& pmvs_option_name, const std::string& input_type); const std::vector& GetFusedPoints() const; const std::vector>& GetFusedPointsVisibility() const; private: void Run(); void InitFusedPixelMask(int image_idx, size_t width, size_t height); void Fuse(const int thread_id, const int image_idx, const int row, const int col); const StereoFusionOptions options_; const std::string workspace_path_; const std::string workspace_format_; const std::string pmvs_option_name_; const std::string input_type_; const float max_squared_reproj_error_; const float min_cos_normal_error_; std::unique_ptr workspace_; std::vector used_images_; std::vector fused_images_; std::vector> overlapping_images_; // Contains image masks of pre-masked and already fused pixels. // Initialized from image masks if provided in StereoFusionOptions. std::vector> fused_pixel_masks_; std::vector> depth_map_sizes_; std::vector> bitmap_scales_; std::vector> P_; std::vector> inv_P_; std::vector> inv_R_; struct FusionData { int image_idx = kInvalidImageId; int row = 0; int col = 0; int traversal_depth = -1; FusionData(int image_idx, int row, int col, int traversal_depth) : image_idx(image_idx), row(row), col(col), traversal_depth(traversal_depth) {} bool operator()(const FusionData& data1, const FusionData& data2) { return data1.image_idx > data2.image_idx; } }; // Already fused points. std::vector fused_points_; std::vector> fused_points_visibility_; std::vector> task_fused_points_; std::vector>> task_fused_points_visibility_; }; // Write the visiblity information into a binary file of the following format: // // // // ... // // ... // ... // // Note that an image_idx in the case of the mvs::StereoFuser does not // correspond to the image_id of a Reconstruction, but the index of the image in // the mvs::Model, which is the location of the image in the images.bin/.txt. void WritePointsVisibility( const std::string& path, const std::vector>& points_visibility); } // namespace mvs } // namespace colmap #endif // COLMAP_SRC_MVS_FUSION_H_