| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| |
|
| | #include "base/database_cache.h" |
| |
|
| | #include <unordered_set> |
| |
|
| | #include "feature/utils.h" |
| | #include "util/string.h" |
| | #include "util/timer.h" |
| |
|
| | namespace colmap { |
| |
|
| | DatabaseCache::DatabaseCache() {} |
| |
|
| | void DatabaseCache::AddCamera(class Camera camera) { |
| | const camera_t camera_id = camera.CameraId(); |
| | CHECK(!ExistsCamera(camera_id)); |
| | cameras_.emplace(camera_id, std::move(camera)); |
| | } |
| |
|
| | void DatabaseCache::AddImage(class Image image) { |
| | const image_t image_id = image.ImageId(); |
| | CHECK(!ExistsImage(image_id)); |
| | correspondence_graph_.AddImage(image_id, image.NumPoints2D()); |
| | images_.emplace(image_id, std::move(image)); |
| | } |
| |
|
| | void DatabaseCache::Load(const Database& database, const size_t min_num_matches, |
| | const bool ignore_watermarks, |
| | const std::unordered_set<std::string>& image_names) { |
| | |
| | |
| | |
| |
|
| | Timer timer; |
| |
|
| | timer.Start(); |
| | std::cout << "Loading cameras..." << std::flush; |
| |
|
| | { |
| | std::vector<class Camera> cameras = database.ReadAllCameras(); |
| | cameras_.reserve(cameras.size()); |
| | for (auto& camera : cameras) { |
| | const camera_t camera_id = camera.CameraId(); |
| | cameras_.emplace(camera_id, std::move(camera)); |
| | } |
| | } |
| |
|
| | std::cout << StringPrintf(" %d in %.3fs", cameras_.size(), |
| | timer.ElapsedSeconds()) |
| | << std::endl; |
| |
|
| | |
| | |
| | |
| |
|
| | timer.Restart(); |
| | std::cout << "Loading matches..." << std::flush; |
| |
|
| | std::vector<image_pair_t> image_pair_ids; |
| | std::vector<TwoViewGeometry> two_view_geometries; |
| | database.ReadTwoViewGeometries(&image_pair_ids, &two_view_geometries); |
| |
|
| | std::cout << StringPrintf(" %d in %.3fs", image_pair_ids.size(), |
| | timer.ElapsedSeconds()) |
| | << std::endl; |
| |
|
| | auto UseInlierMatchesCheck = [min_num_matches, ignore_watermarks]( |
| | const TwoViewGeometry& two_view_geometry) { |
| | return static_cast<size_t>(two_view_geometry.inlier_matches.size()) >= |
| | min_num_matches && |
| | (!ignore_watermarks || |
| | two_view_geometry.config != TwoViewGeometry::WATERMARK); |
| | }; |
| |
|
| | |
| | |
| | |
| |
|
| | timer.Restart(); |
| | std::cout << "Loading images..." << std::flush; |
| |
|
| | std::unordered_set<image_t> image_ids; |
| |
|
| | { |
| | std::vector<class Image> images = database.ReadAllImages(); |
| | const size_t num_images = images.size(); |
| |
|
| | |
| | if (image_names.empty()) { |
| | for (const auto& image : images) { |
| | image_ids.insert(image.ImageId()); |
| | } |
| | } else { |
| | for (const auto& image : images) { |
| | if (image_names.count(image.Name()) > 0) { |
| | image_ids.insert(image.ImageId()); |
| | } |
| | } |
| | } |
| |
|
| | |
| | std::unordered_set<image_t> connected_image_ids; |
| | connected_image_ids.reserve(image_ids.size()); |
| | for (size_t i = 0; i < image_pair_ids.size(); ++i) { |
| | if (UseInlierMatchesCheck(two_view_geometries[i])) { |
| | image_t image_id1; |
| | image_t image_id2; |
| | Database::PairIdToImagePair(image_pair_ids[i], &image_id1, &image_id2); |
| | if (image_ids.count(image_id1) > 0 && image_ids.count(image_id2) > 0) { |
| | connected_image_ids.insert(image_id1); |
| | connected_image_ids.insert(image_id2); |
| | } |
| | } |
| | } |
| |
|
| | |
| | |
| | images_.reserve(connected_image_ids.size()); |
| | for (auto& image : images) { |
| | const image_t image_id = image.ImageId(); |
| | if (image_ids.count(image_id) > 0 && |
| | connected_image_ids.count(image_id) > 0) { |
| | images_.emplace(image_id, std::move(image)); |
| | const FeatureKeypoints keypoints = database.ReadKeypoints(image_id); |
| | const std::vector<Eigen::Vector2d> points = |
| | FeatureKeypointsToPointsVector(keypoints); |
| | images_[image_id].SetPoints2D(points); |
| | } |
| | } |
| |
|
| | std::cout << StringPrintf(" %d in %.3fs (connected %d)", num_images, |
| | timer.ElapsedSeconds(), |
| | connected_image_ids.size()) |
| | << std::endl; |
| | } |
| |
|
| | |
| | |
| | |
| |
|
| | timer.Restart(); |
| | std::cout << "Building correspondence graph..." << std::flush; |
| |
|
| | for (const auto& image : images_) { |
| | correspondence_graph_.AddImage(image.first, image.second.NumPoints2D()); |
| | } |
| |
|
| | size_t num_ignored_image_pairs = 0; |
| | for (size_t i = 0; i < image_pair_ids.size(); ++i) { |
| | if (UseInlierMatchesCheck(two_view_geometries[i])) { |
| | image_t image_id1; |
| | image_t image_id2; |
| | Database::PairIdToImagePair(image_pair_ids[i], &image_id1, &image_id2); |
| | if (image_ids.count(image_id1) > 0 && image_ids.count(image_id2) > 0) { |
| | correspondence_graph_.AddCorrespondences( |
| | image_id1, image_id2, two_view_geometries[i].inlier_matches); |
| | } else { |
| | num_ignored_image_pairs += 1; |
| | } |
| | } else { |
| | num_ignored_image_pairs += 1; |
| | } |
| | } |
| |
|
| | correspondence_graph_.Finalize(); |
| |
|
| | |
| | for (auto& image : images_) { |
| | image.second.SetNumObservations( |
| | correspondence_graph_.NumObservationsForImage(image.first)); |
| | image.second.SetNumCorrespondences( |
| | correspondence_graph_.NumCorrespondencesForImage(image.first)); |
| | } |
| |
|
| | std::cout << StringPrintf(" in %.3fs (ignored %d)", timer.ElapsedSeconds(), |
| | num_ignored_image_pairs) |
| | << std::endl; |
| | } |
| |
|
| | const class Image* DatabaseCache::FindImageWithName( |
| | const std::string& name) const { |
| | for (const auto& image : images_) { |
| | if (image.second.Name() == name) { |
| | return &image.second; |
| | } |
| | } |
| | return nullptr; |
| | } |
| |
|
| | } |
| |
|