Skip to content

Commit ff24410

Browse files
committed
[sfm] Function to split a match file in component openMVG#1135
- Extend the unit test with a corner cases (empty input) - Simplify the main_plitMatchFileIntoMatchFiles cpp file
1 parent e66bb17 commit ff24410

4 files changed

+102
-83
lines changed

src/openMVG/sfm/sfm_data_graph_utils.cpp

+36-25
Original file line numberDiff line numberDiff line change
@@ -20,35 +20,39 @@
2020
namespace openMVG {
2121
namespace sfm {
2222

23-
/// Filter the toFilter iterable sequence into a new sequence without change the source sequence
24-
/// (keep only the element that share a common index with the provided Ids index list).
25-
/// See the reference: sfm_filters.hpp
26-
static void KeepOnlyReferencedElement(
23+
static void KeepOnlyReferencedElement
24+
(
2725
const std::set<IndexT> & set_remainingIds,
28-
const matching::PairWiseMatches & map_matches_in,
29-
matching::PairWiseMatches & map_matches_out)
26+
const matching::PairWiseMatches & matches_in,
27+
matching::PairWiseMatches & matches_out
28+
)
3029
{
31-
matching::PairWiseMatches map_matches_E_infered;
32-
for (const auto & iter_pairwise_matches : map_matches_in)
30+
matching::PairWiseMatches kept_matches;
31+
for (const auto & iter_pairwise_matches : matches_in)
3332
{
3433
if (set_remainingIds.count(iter_pairwise_matches.first.first) &&
35-
set_remainingIds.count(iter_pairwise_matches.first.second))
34+
set_remainingIds.count(iter_pairwise_matches.first.second))
3635
{
37-
map_matches_E_infered.insert(iter_pairwise_matches);
36+
kept_matches.insert(iter_pairwise_matches);
3837
}
3938
}
40-
map_matches_out.swap(map_matches_E_infered);
39+
matches_out.swap(kept_matches);
4140
}
4241

43-
bool PairsToConnectedComponents(const Pair_Set & pairs, bool is_biedge,
44-
int min_nodes, std::map<IndexT, std::set<IndexT>>& subgraphs_ids)
42+
bool PairsToConnectedComponents
43+
(
44+
const Pair_Set & pairs,
45+
bool is_biedge,
46+
int min_nodes,
47+
std::map<IndexT, std::set<IndexT>>& subgraphs_ids
48+
)
4549
{
4650
subgraphs_ids.clear();
4751

4852
using Graph = graph::indexedGraph::GraphT;
4953
graph::indexedGraph putativeGraph(pairs);
5054

51-
// For global SFM, firstly remove the not bi-edge element
55+
// For global SFM, firstly remove the not bi-edge element
5256
if (is_biedge)
5357
{
5458
using EdgeMapAlias = Graph::EdgeMap<bool>;
@@ -72,7 +76,7 @@ bool PairsToConnectedComponents(const Pair_Set & pairs, bool is_biedge,
7276
const int connectedComponentCount = lemon::countConnectedComponents(putativeGraph.g);
7377
if (connectedComponentCount >= 1)
7478
{
75-
const std::map<IndexT, std::set<Graph::Node> > map_subgraphs = graph::exportGraphToMapSubgraphs<Graph, IndexT>(putativeGraph.g);
79+
const auto map_subgraphs = graph::exportGraphToMapSubgraphs<Graph, IndexT>(putativeGraph.g);
7680
for (const auto & iter_map_subgraphs : map_subgraphs)
7781
{
7882
if (iter_map_subgraphs.second.size() > min_nodes)
@@ -88,27 +92,34 @@ bool PairsToConnectedComponents(const Pair_Set & pairs, bool is_biedge,
8892
}
8993
}
9094
}
91-
return true;
95+
return !subgraphs_ids.empty();
9296
}
9397

94-
bool SplitMatchesIntoSubgraphMatches(const Pair_Set & pairs, const matching::PairWiseMatches & matches,
95-
bool is_biedge, int min_nodes, std::vector<matching::PairWiseMatches> & subgraphs_matches)
98+
bool SplitMatchesIntoSubgraphMatches
99+
(
100+
const Pair_Set & pairs,
101+
const matching::PairWiseMatches & matches,
102+
bool is_biedge,
103+
int min_nodes,
104+
std::vector<matching::PairWiseMatches> & subgraphs_matches
105+
)
96106
{
97107
if (pairs.size() == 0 || matches.size() == 0)
98108
{
99109
return false;
100110
}
101111
subgraphs_matches.clear();
102112
std::map<IndexT, std::set<IndexT>> subgraphs_ids;
103-
PairsToConnectedComponents(pairs, is_biedge, min_nodes, subgraphs_ids);
104-
105-
for (const auto & iter_subgraphs_ids : subgraphs_ids)
113+
if (PairsToConnectedComponents(pairs, is_biedge, min_nodes, subgraphs_ids))
106114
{
107-
matching::PairWiseMatches subgraph_map_matches;
108-
KeepOnlyReferencedElement(iter_subgraphs_ids.second, matches, subgraph_map_matches);
109-
subgraphs_matches.emplace_back(subgraph_map_matches);
115+
for (const auto & iter_subgraphs_ids : subgraphs_ids)
116+
{
117+
matching::PairWiseMatches component_matches;
118+
KeepOnlyReferencedElement(iter_subgraphs_ids.second, matches, component_matches);
119+
subgraphs_matches.emplace_back(component_matches);
120+
}
110121
}
111-
return true;
122+
return !subgraphs_matches.empty();
112123
}
113124

114125
} // namespace sfm

src/openMVG/sfm/sfm_data_graph_utils.hpp

+29-17
Original file line numberDiff line numberDiff line change
@@ -8,45 +8,57 @@
88

99
#ifndef OPENMVG_SFM_DATA_GRAPH_UTILS_HPP
1010
#define OPENMVG_SFM_DATA_GRAPH_UTILS_HPP
11-
#include <string>
11+
1212
#include "openMVG/types.hpp"
1313
#include "openMVG/matching/indMatch.hpp"
14+
#include <string>
1415

1516
namespace openMVG {
1617
namespace sfm {
17-
/// @brief Split match pairs into connected match pairs
18+
/// @brief Split match pairs into connected match pairs
1819
/// @param[in] pairs The pair sets of the images.
1920
/// @param[in] is_biedge Set true for global SFM, false for sequential SFM.
20-
/// @param[in] min_nodes The minimum nodes of graph in the output match_file.Note: the value should be larger than 3.
21-
/// @param[out] subgraps_ids The pairs id of subgraphs splited from the whole graph.
21+
/// @param[in] min_nodes The minimum nodes of graph in the output match_file. Note: the value should be larger than 3.
22+
/// @param[out] subgraps_ids The pairs id of subgraphs split from the whole graph.
2223
///
23-
/// @return True if the area can be computed
24-
bool PairsToConnectedComponents(const Pair_Set & pairs, bool is_biedge,
25-
int min_nodes, std::map<IndexT, std::set<IndexT> > & subgraphs_ids);
24+
/// @return True if some components have been kept
25+
bool PairsToConnectedComponents
26+
(
27+
const Pair_Set & pairs,
28+
bool is_biedge,
29+
int min_nodes,
30+
std::map<IndexT, std::set<IndexT>> & subgraphs_ids
31+
);
2632

2733
/// @brief Split match_file into match_files
28-
/// When handling a scene which may contains many disconnected graphs,
34+
/// When handling a scene which may contains many disconnected graphs,
2935
/// for the moment OpenMVG consider only the largest connected component for SfM.
30-
/// Especially, when the GPS data of the images known, the disconnected graphs in a scene should be
36+
/// Especially, when the GPS data of the images known, the disconnected graphs in a scene should be
3137
/// merged since they all share the same coordinate system.
3238
/// Steps handling the above scenario.
33-
/// Step 1 : Use this function to compute the various connected component and export
39+
/// Step 1 : Use this function to compute the various connected component and export
3440
/// the matches of the each connected component in a different match file.
3541
/// Step 2 : Run the SfM pipeline of your choice on the produced matches file.
36-
/// Step 3 : Merge all the sfm_data into a single sfm_data and
42+
/// Step 3 : Merge all the sfm_data into a single sfm_data and
3743
/// triangulate the initial match file, when the GPS data of the images known.
38-
///
44+
///
3945
///
4046
/// @param[in] pairs The pair sets of the images.
4147
/// @param[in] matches The pairwise matches of the images corresponding to pairs.
4248
/// @param[in] is_biedge Set true for global SFM, false for sequential SFM.
43-
/// @param[in] min_nodes The minimum nodes of graph in the output match_file.Note: the value should be larger than 3.
44-
/// @param[out] subgraphs_matches The matches of subgraphs splited from the whole graph.
49+
/// @param[in] min_nodes The minimum nodes of graph in the output match_file. Note: the value should be larger than 3.
50+
/// @param[out] subgraphs_matches The matches of subgraphs split from the whole graph.
4551
///
46-
/// @return True if the area can be computed
52+
/// @return True if subgraphs_matches is not empty
4753
///
48-
bool SplitMatchesIntoSubgraphMatches(const Pair_Set & pairs, const matching::PairWiseMatches & matches,
49-
bool is_biedge, int min_nodes, std::vector<matching::PairWiseMatches> & subgraphs_matches);
54+
bool SplitMatchesIntoSubgraphMatches
55+
(
56+
const Pair_Set & pairs,
57+
const matching::PairWiseMatches & matches,
58+
bool is_biedge,
59+
int min_nodes,
60+
std::vector<matching::PairWiseMatches> & subgraphs_matches
61+
);
5062

5163
} // namespace sfm
5264
} // namespace openMVG

src/openMVG/sfm/sfm_data_graph_utils_test.cpp

+24-22
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,15 @@ using namespace openMVG;
1717
using namespace openMVG::matching;
1818
using namespace openMVG::sfm;
1919

20+
TEST(SFM_DATA_GRAPH, PairsToConnectedComponents_EmptyInput)
21+
{
22+
std::map<IndexT, std::set<IndexT>> subgraphs_ids;
23+
EXPECT_FALSE(PairsToConnectedComponents({}, true, 1, subgraphs_ids));
24+
}
2025

2126
TEST(SFM_DATA_GRAPH, PairsToConnectedComponents)
2227
{
23-
Pair_Set pair =
28+
const Pair_Set pairs =
2429
{
2530
// the first connected graph follows the biEdge condition: 0 -> 1 -> 2 ->3 ->4 -> 0
2631
{0, 1}, {0, 2}, {0, 3}, {1, 2}, {1, 3}, {2, 3},
@@ -33,39 +38,36 @@ TEST(SFM_DATA_GRAPH, PairsToConnectedComponents)
3338
std::map<IndexT, std::set<IndexT>> subgraphs_ids;
3439

3540
// test for GlobalSFM with the biEdge condition
36-
const bool flag1 = PairsToConnectedComponents(pair, true, 3, subgraphs_ids);
37-
EXPECT_TRUE(flag1);
41+
EXPECT_TRUE(PairsToConnectedComponents(pairs, true, 3, subgraphs_ids));
3842
EXPECT_EQ(1, subgraphs_ids.size());
3943
if (subgraphs_ids.size() == 1)
4044
{
41-
const auto & iter_begin = subgraphs_ids.begin();
42-
const std::set<IndexT> & pairs0 = iter_begin->second;
43-
EXPECT_EQ(4, pairs0.size());
44-
if (pairs0.size() == 4)
45+
const auto & iter_begin = subgraphs_ids.cbegin();
46+
const std::set<IndexT> & kept_idx = iter_begin->second;
47+
EXPECT_EQ(4, kept_idx.size());
4548
{
46-
EXPECT_TRUE(pairs0.find(0) != pairs0.end());
47-
EXPECT_TRUE(pairs0.find(1) != pairs0.end());
48-
EXPECT_TRUE(pairs0.find(2) != pairs0.end());
49-
EXPECT_TRUE(pairs0.find(3) != pairs0.end());
49+
EXPECT_TRUE(kept_idx.find(0) != kept_idx.cend());
50+
EXPECT_TRUE(kept_idx.find(1) != kept_idx.cend());
51+
EXPECT_TRUE(kept_idx.find(2) != kept_idx.cend());
52+
EXPECT_TRUE(kept_idx.find(3) != kept_idx.cend());
5053
}
5154
}
5255

5356
// test for IncrementalSFM with no biEdge condition
54-
const bool flag2 = PairsToConnectedComponents(pair, false, 3, subgraphs_ids);
55-
EXPECT_TRUE(flag2);
57+
// The smallest graph must disappear since it is too small
58+
EXPECT_TRUE(PairsToConnectedComponents(pairs, false, 3, subgraphs_ids));
5659
EXPECT_EQ(2, subgraphs_ids.size());
5760
if (subgraphs_ids.size() == 2)
5861
{
59-
auto iter_first = subgraphs_ids.begin();
60-
const std::set<IndexT> & pairs0 = iter_first->second;
61-
EXPECT_EQ(5, pairs0.size());
62-
if (pairs0.size() == 5)
62+
const auto iter_first = subgraphs_ids.cbegin();
63+
const std::set<IndexT> & kept_idx = iter_first->second;
64+
EXPECT_EQ(5, kept_idx.size());
6365
{
64-
EXPECT_TRUE(pairs0.find(4) != pairs0.end());
65-
EXPECT_TRUE(pairs0.find(5) != pairs0.end());
66-
EXPECT_TRUE(pairs0.find(6) != pairs0.end());
67-
EXPECT_TRUE(pairs0.find(7) != pairs0.end());
68-
EXPECT_TRUE(pairs0.find(8) != pairs0.end());
66+
EXPECT_TRUE(kept_idx.find(4) != kept_idx.cend());
67+
EXPECT_TRUE(kept_idx.find(5) != kept_idx.cend());
68+
EXPECT_TRUE(kept_idx.find(6) != kept_idx.cend());
69+
EXPECT_TRUE(kept_idx.find(7) != kept_idx.cend());
70+
EXPECT_TRUE(kept_idx.find(8) != kept_idx.cend());
6971
}
7072

7173
auto iter_second = subgraphs_ids.begin();

src/software/SfM/main_SplitMatchFileIntoMatchFiles.cpp

+13-19
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,16 @@
1414
#include "third_party/stlplus3/filesystemSimplified/file_system.hpp"
1515

1616
#include <cstdlib>
17+
#include <fstream>
1718
#include <memory>
1819
#include <string>
19-
#include <fstream>
2020

2121
using namespace openMVG;
2222
using namespace openMVG::sfm;
2323

2424
int main(int argc, char **argv)
2525
{
2626
using namespace std;
27-
std::cout << std::endl;
2827

2928
CmdLine cmd;
3029

@@ -57,23 +56,13 @@ int main(int argc, char **argv)
5756
return EXIT_FAILURE;
5857
}
5958

60-
if (!stlplus::file_exists(sfm_data_filename))
61-
{
62-
return EXIT_FAILURE;
63-
}
64-
65-
if (!stlplus::file_exists(match_filename))
66-
{
67-
return EXIT_FAILURE;
68-
}
69-
7059
const std::string &match_component_dir = stlplus::folder_part(match_component_filename);
7160
if (!stlplus::folder_exists(match_component_dir))
7261
{
7362
const bool folder_create_flag = stlplus::folder_create(match_component_dir);
7463
if (!folder_create_flag)
7564
{
76-
std::cerr << "Cannot create the output directory" << std::endl;
65+
std::cerr << "Cannot create the output directory: " << match_component_dir << std::endl;
7766
return EXIT_FAILURE;
7867
}
7968
}
@@ -99,9 +88,13 @@ int main(int argc, char **argv)
9988
std::vector<matching::PairWiseMatches> subgraphs_matches;
10089

10190
// Split match_filename by connected components;
102-
const bool success_flag = SplitMatchesIntoSubgraphMatches(matches_provider->getPairs(), matches_provider->pairWise_matches_,
103-
is_biedge, min_nodes, subgraphs_matches);
104-
if (success_flag)
91+
const bool success_flag =
92+
SplitMatchesIntoSubgraphMatches(matches_provider->getPairs(),
93+
matches_provider->pairWise_matches_,
94+
is_biedge,
95+
min_nodes,
96+
subgraphs_matches);
97+
if (!success_flag)
10598
{
10699
std::cerr << std::endl
107100
<< "Failed to split matches file into subgraph matches." << std::endl;
@@ -118,12 +111,13 @@ int main(int argc, char **argv)
118111
for (const auto & subgraph : subgraphs_matches)
119112
{
120113
std::stringstream strstream_subgraph_match_filename;
121-
strstream_subgraph_match_filename << file_basename << "_" << index << "_" << subgraph.size() << "." << match_file_extension;
114+
strstream_subgraph_match_filename << file_basename
115+
<< "_" << index
116+
<< "_" << subgraph.size() << "." << match_file_extension;
122117
const std::string &subgraph_match_filename = strstream_subgraph_match_filename.str();
123118
const std::string &subgraph_match_file = stlplus::create_filespec(output_folder, subgraph_match_filename);
124119

125-
const bool success_flag = matching::Save(subgraph, subgraph_match_file);
126-
if (success_flag)
120+
if (matching::Save(subgraph, subgraph_match_file))
127121
{
128122
set_filenames.insert(subgraph_match_filename);
129123
}

0 commit comments

Comments
 (0)