MVE - Multi-View Environment mve-devel
Loading...
Searching...
No Matches
bundler_matching.cc
Go to the documentation of this file.
1/*
2 * Copyright (C) 2015, Simon Fuhrmann
3 * TU Darmstadt - Graphics, Capture and Massively Parallel Computing
4 * All rights reserved.
5 *
6 * This software may be modified and distributed under the terms
7 * of the BSD 3-Clause license. See the LICENSE.txt file for details.
8 */
9
10#include <iostream>
11#include <fstream>
12#include <cstring>
13#include <cerrno>
14#include <stdexcept>
15
16#include "util/exception.h"
17#include "util/timer.h"
18#include "sfm/sift.h"
19#include "sfm/ransac.h"
21#include "sfm/cascade_hashing.h"
23
26
27Matching::Matching (Options const& options, Progress* progress)
28 : opts(options)
29 , progress(progress)
30{
31 switch (this->opts.matcher_type)
32 {
34 this->matcher.reset(new ExhaustiveMatching());
35 break;
37 this->matcher.reset(new CascadeHashing());
38 break;
39 default:
40 throw std::runtime_error("Unhandled matcher type");
41 }
42}
43
44void
46{
47 if (viewports == nullptr)
48 throw std::invalid_argument("Viewports must not be null");
49
50 this->viewports = viewports;
51 this->matcher->init(viewports);
52
53 /* Free descriptors. */
54 for (std::size_t i = 0; i < viewports->size(); i++)
55 viewports->at(i).features.clear_descriptors();
56}
57
58void
60{
61 if (this->viewports == nullptr)
62 throw std::runtime_error("Viewports must not be null");
63
64 std::size_t num_viewports = this->viewports->size();
65 std::size_t num_pairs = num_viewports * (num_viewports - 1) / 2;
66 std::size_t num_done = 0;
67
68 if (this->progress != nullptr)
69 {
70 this->progress->num_total = num_pairs;
71 this->progress->num_done = 0;
72 }
73
74#pragma omp parallel for schedule(dynamic)
75 for (std::size_t i = 0; i < num_pairs; ++i)
76 {
77#pragma omp critical
78 {
79 num_done += 1;
80 if (this->progress != nullptr)
81 this->progress->num_done += 1;
82
83 float percent = (num_done * 1000 / num_pairs) / 10.0f;
84 std::cout << "\rMatching pair " << num_done << " of "
85 << num_pairs << " (" << percent << "%)..." << std::flush;
86 }
87
88 int const view_1_id = (int)(0.5 + std::sqrt(0.25 + 2.0 * i));
89 int const view_2_id = (int)i - view_1_id * (view_1_id - 1) / 2;
90 if (this->opts.match_num_previous_frames != 0
91 && view_2_id + this->opts.match_num_previous_frames < view_1_id)
92 continue;
93
94 FeatureSet const& view_1 = this->viewports->at(view_1_id).features;
95 FeatureSet const& view_2 = this->viewports->at(view_2_id).features;
96 if (view_1.positions.empty() || view_2.positions.empty())
97 continue;
98
99 /* Match the views. */
100 util::WallTimer timer;
101 std::stringstream message;
102 CorrespondenceIndices matches;
103 this->two_view_matching(view_1_id, view_2_id, &matches, message);
104 std::size_t matching_time = timer.get_elapsed();
105
106 if (matches.empty())
107 {
108#pragma omp critical
109 std::cout << "\rPair (" << view_1_id << ","
110 << view_2_id << ") rejected, "
111 << message.str() << std::endl;
112 continue;
113 }
114
115 /* Successful two view matching. Add the pair. */
116 TwoViewMatching matching;
117 matching.view_1_id = view_1_id;
118 matching.view_2_id = view_2_id;
119 std::swap(matching.matches, matches);
120
121#pragma omp critical
122 {
123 pairwise_matching->push_back(matching);
124 std::cout << "\rPair (" << view_1_id << ","
125 << view_2_id << ") matched, " << matching.matches.size()
126 << " inliers, took " << matching_time << " ms." << std::endl;
127 }
128 }
129
130 std::cout << "\rFound a total of " << pairwise_matching->size()
131 << " matching image pairs." << std::endl;
132}
133
134void
135Matching::two_view_matching (int view_1_id, int view_2_id,
136 CorrespondenceIndices* matches, std::stringstream& message)
137{
138 FeatureSet const& view_1 = this->viewports->at(view_1_id).features;
139 FeatureSet const& view_2 = this->viewports->at(view_2_id).features;
140
141 /* Low-res matching if number of features is large. */
142 if (this->opts.use_lowres_matching
143 && view_1.positions.size() * view_2.positions.size() > 1000000)
144 {
145 int const num_matches = this->matcher->pairwise_match_lowres(view_1_id,
146 view_2_id, this->opts.num_lowres_features);
147 if (num_matches < this->opts.min_lowres_matches)
148 {
149 message << "only " << num_matches
150 << " of " << this->opts.min_lowres_matches
151 << " low-res matches.";
152 return;
153 }
154 }
155
156 /* Perform two-view descriptor matching. */
157 sfm::Matching::Result matching_result;
158 this->matcher->pairwise_match(view_1_id, view_2_id, &matching_result);
159 int num_matches = sfm::Matching::count_consistent_matches(matching_result);
160
161 /* Require at least 8 matches. Check threshold. */
162 int const min_matches_thres = std::max(8, this->opts.min_feature_matches);
163 if (num_matches < min_matches_thres)
164 {
165 message << "matches below threshold of "
166 << min_matches_thres << ".";
167 return;
168 }
169
170 /* Build correspondences from feature matching result. */
171 sfm::Correspondences2D2D unfiltered_matches;
172 sfm::CorrespondenceIndices unfiltered_indices;
173 {
174 std::vector<int> const& m12 = matching_result.matches_1_2;
175 for (std::size_t i = 0; i < m12.size(); ++i)
176 {
177 if (m12[i] < 0)
178 continue;
179
181 match.p1[0] = view_1.positions[i][0];
182 match.p1[1] = view_1.positions[i][1];
183 match.p2[0] = view_2.positions[m12[i]][0];
184 match.p2[1] = view_2.positions[m12[i]][1];
185 unfiltered_matches.push_back(match);
186 unfiltered_indices.push_back(std::make_pair(i, m12[i]));
187 }
188 }
189
190 /* Compute fundamental matrix using RANSAC. */
191 sfm::RansacFundamental::Result ransac_result;
192 int num_inliers = 0;
193 {
194 sfm::RansacFundamental ransac(this->opts.ransac_opts);
195 ransac.estimate(unfiltered_matches, &ransac_result);
196 num_inliers = ransac_result.inliers.size();
197 }
198
199 /* Require at least 8 inlier matches. */
200 int const min_inlier_thres = std::max(8, this->opts.min_matching_inliers);
201 if (num_inliers < min_inlier_thres)
202 {
203 message << "inliers below threshold of "
204 << min_inlier_thres << ".";
205 return;
206 }
207
208 /* Create Two-View matching result. */
209 matches->clear();
210 matches->reserve(num_inliers);
211 for (int i = 0; i < num_inliers; ++i)
212 {
213 int const inlier_id = ransac_result.inliers[i];
214 matches->push_back(unfiltered_indices[inlier_id]);
215 }
216}
217
The FeatureSet holds per-feature information for a single view, and allows to transparently compute a...
Definition feature_set.h:28
std::vector< math::Vec2f > positions
Per-feature image position.
Definition feature_set.h:66
static int count_consistent_matches(Result const &matches)
Function that counts the number of valid matches.
Definition matching.cc:39
RANSAC pose estimation from noisy 2D-2D image correspondences.
void init(ViewportList *viewports)
Initialize matching by passing features to the matcher for preprocessing.
void compute(PairwiseMatching *pairwise_matching)
Computes the pairwise matching between all pairs of views.
Cross-platform high-resolution real-time timer.
Definition timer.h:30
std::size_t get_elapsed(void) const
Returns the milli seconds since last reset.
Definition timer.h:94
std::vector< Viewport > ViewportList
The list of all viewports considered for bundling.
std::vector< TwoViewMatching > PairwiseMatching
The matching result between several pairs of views.
std::vector< CorrespondenceIndex > CorrespondenceIndices
A list of all matching feature pairs in two images.
std::vector< Correspondence2D2D > Correspondences2D2D
void swap(mve::Image< T > &a, mve::Image< T > &b)
Specialization of std::swap for efficient image swapping.
Definition image.h:478
#define SFM_BUNDLER_NAMESPACE_END
Definition defines.h:17
#define SFM_BUNDLER_NAMESPACE_BEGIN
Definition defines.h:16
#define SFM_NAMESPACE_END
Definition defines.h:14
#define SFM_NAMESPACE_BEGIN
Definition defines.h:13
Two image coordinates which correspond to each other in terms of observing the same point in the scen...
Feature matching result reported as two lists, each with indices in the other set.
Definition matching.h:57
std::vector< int > matches_1_2
Definition matching.h:59
std::vector< int > inliers
The indices of inliers in the correspondences which led to the homography matrix.
Options for feature matching.
int min_matching_inliers
Minimum number of matching features after RANSAC.
int min_feature_matches
Minimum number of matching features before RANSAC.
int min_lowres_matches
Minimum number of matches from low-res matching.
int match_num_previous_frames
Only match to a few previous frames.
MatcherType matcher_type
Matcher type.
bool use_lowres_matching
Perform low-resolution matching to reject unlikely pairs.
sfm::RansacFundamental::Options ransac_opts
Options for RANSAC computation of the fundamental matrix.
int num_lowres_features
Number of features used for low-res matching.
The matching result between two views.
CorrespondenceIndices matches