Skip to content

Commit af15f4c

Browse files
author
Fabien Servant
committed
Add two new nodes for feature matching geometric filter
1 parent 76eb659 commit af15f4c

12 files changed

+848
-42
lines changed
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
__version__ = "2.0"
2+
3+
from meshroom.core import desc
4+
from meshroom.core.utils import DESCRIBER_TYPES, VERBOSE_LEVEL
5+
6+
7+
class GeometricFilterApplying(desc.AVCommandLineNode):
8+
commandLine = 'aliceVision_geometricFilterApplying {allParams}'
9+
size = desc.DynamicNodeSize('input')
10+
parallelization = desc.Parallelization(blockSize=20)
11+
commandLineRange = '--rangeIteration {rangeIteration} --rangeBlocksCount {rangeBlocksCount}'
12+
13+
category = 'Sparse Reconstruction'
14+
documentation = '''
15+
Apply precomputed transforms to matches to filter geometric matches
16+
'''
17+
18+
inputs = [
19+
desc.File(
20+
name="input",
21+
label="SfMData",
22+
description="Input SfMData file.",
23+
value="",
24+
),
25+
desc.ListAttribute(
26+
elementDesc=desc.File(
27+
name="featuresFolder",
28+
label="Features Folder",
29+
description="Folder containing some extracted features and descriptors.",
30+
value="",
31+
),
32+
name="featuresFolders",
33+
label="Features Folders",
34+
description="Folder(s) containing the extracted features and descriptors.",
35+
exposed=True,
36+
),
37+
desc.ListAttribute(
38+
elementDesc=desc.File(
39+
name="matchesFolder",
40+
label="Matches Folder",
41+
description="Folder containing some matches.",
42+
value="",
43+
),
44+
name="matchesFolders",
45+
label="Matches Folders",
46+
description="Folder(s) in which computed matches are stored.",
47+
exposed=True,
48+
),
49+
desc.File(
50+
name="filters",
51+
label="Filters Folder",
52+
description="Path to a folder in which the computed filters are stored.",
53+
value="",
54+
exposed=True
55+
),
56+
desc.ChoiceParam(
57+
name="describerTypes",
58+
label="Describer Types",
59+
description="Describer types used to describe an image.",
60+
values=DESCRIBER_TYPES,
61+
value=["dspsift"],
62+
exclusive=False,
63+
joinChar=",",
64+
exposed=True,
65+
),
66+
desc.IntParam(
67+
name="maxMatches",
68+
label="Max Matches",
69+
description="Maximum number of matches to keep.",
70+
value=0,
71+
range=(0, 10000, 1),
72+
advanced=True,
73+
),
74+
desc.ChoiceParam(
75+
name="verboseLevel",
76+
label="Verbose Level",
77+
description="Verbosity level (fatal, error, warning, info, debug, trace).",
78+
values=VERBOSE_LEVEL,
79+
value="info",
80+
),
81+
]
82+
outputs = [
83+
desc.File(
84+
name="output",
85+
label="Matches Folder",
86+
description="Path to a folder in which the computed matches are stored.",
87+
value="{nodeCacheFolder}",
88+
),
89+
]
Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
__version__ = "2.0"
2+
3+
from meshroom.core import desc
4+
from meshroom.core.utils import DESCRIBER_TYPES, VERBOSE_LEVEL
5+
6+
7+
class GeometricFilterEstimating(desc.AVCommandLineNode):
8+
commandLine = 'aliceVision_geometricFilterEstimating {allParams}'
9+
size = desc.DynamicNodeSize('input')
10+
parallelization = desc.Parallelization(blockSize=20)
11+
commandLineRange = '--rangeIteration {rangeIteration} --rangeBlocksCount {rangeBlocksCount}'
12+
13+
category = 'Sparse Reconstruction'
14+
documentation = '''
15+
It performs a geometric filtering of the photometric match candidates.
16+
It uses the features positions in the images to make a geometric filtering by using epipolar geometry in an outlier detection framework
17+
called RANSAC (RANdom SAmple Consensus). It randomly selects a small set of feature correspondences and compute the fundamental (or essential) matrix,
18+
then it checks the number of features that validates this model and iterate through the RANSAC framework.
19+
20+
## Online
21+
[https://alicevision.org/#photogrammetry/feature_matching](https://alicevision.org/#photogrammetry/feature_matching)
22+
'''
23+
24+
inputs = [
25+
desc.File(
26+
name="input",
27+
label="SfMData",
28+
description="Input SfMData file.",
29+
value="",
30+
),
31+
desc.ListAttribute(
32+
elementDesc=desc.File(
33+
name="featuresFolder",
34+
label="Features Folder",
35+
description="Folder containing some extracted features and descriptors.",
36+
value="",
37+
),
38+
name="featuresFolders",
39+
label="Features Folders",
40+
description="Folder(s) containing the extracted features and descriptors.",
41+
exposed=True,
42+
),
43+
desc.ListAttribute(
44+
elementDesc=desc.File(
45+
name="matchesFolder",
46+
label="Matches Folder",
47+
description="Folder containing some matches.",
48+
value="",
49+
),
50+
name="matchesFolders",
51+
label="Matches Folders",
52+
description="Folder(s) in which computed matches are stored.",
53+
exposed=True,
54+
),
55+
desc.ChoiceParam(
56+
name="describerTypes",
57+
label="Describer Types",
58+
description="Describer types used to describe an image.",
59+
values=DESCRIBER_TYPES,
60+
value=["dspsift"],
61+
exclusive=False,
62+
joinChar=",",
63+
exposed=True,
64+
),
65+
desc.IntParam(
66+
name="maxIteration",
67+
label="Max Iterations",
68+
description="Maximum number of iterations allowed in the Ransac step.",
69+
value=50000,
70+
range=(1, 100000, 1),
71+
advanced=True,
72+
),
73+
desc.FloatParam(
74+
name="geometricError",
75+
label="Geometric Validation Error",
76+
description="Maximum error (in pixels) allowed for features matching during geometric verification",
77+
value=0.0,
78+
range=(0.0, 10.0, 0.1),
79+
advanced=True,
80+
),
81+
desc.IntParam(
82+
name="maxMatches",
83+
label="Max Matches",
84+
description="Maximum number of matches to keep.",
85+
value=0,
86+
range=(0, 10000, 1),
87+
advanced=True,
88+
),
89+
desc.ChoiceParam(
90+
name="verboseLevel",
91+
label="Verbose Level",
92+
description="Verbosity level (fatal, error, warning, info, debug, trace).",
93+
values=VERBOSE_LEVEL,
94+
value="info",
95+
),
96+
]
97+
outputs = [
98+
desc.File(
99+
name="output",
100+
label="Filters Folder",
101+
description="Path to a folder in which the computed filters are stored.",
102+
value="{nodeCacheFolder}",
103+
),
104+
]

src/aliceVision/matchingImageCollection/GeometricFilter.hpp

Lines changed: 61 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <aliceVision/matching/MatchesCollections.hpp>
1414
#include <aliceVision/matchingImageCollection/GeometricFilterMatrix.hpp>
1515
#include <aliceVision/system/ProgressDisplay.hpp>
16+
#include <aliceVision/matchingImageCollection/GeometricInfo.hpp>
1617

1718
#include <map>
1819
#include <random>
@@ -28,7 +29,7 @@ using namespace aliceVision::matching;
2829
* or all the pairs and regions correspondences contained in the putativeMatches set.
2930
* Allow to keep only geometrically coherent matches.
3031
* It discards pairs that do not lead to a valid robust model estimation.
31-
* @param[out] geometricMatches
32+
* @param[out] out_geometricMatches
3233
* @param[in] sfmData
3334
* @param[in] regionsPerView
3435
* @param[in] functor
@@ -39,7 +40,7 @@ using namespace aliceVision::matching;
3940
*/
4041
template<typename GeometryFunctor>
4142
void robustModelEstimation(PairwiseMatches& out_geometricMatches,
42-
const sfmData::SfMData* sfmData,
43+
const sfmData::SfMData & sfmData,
4344
const feature::RegionsPerView& regionsPerView,
4445
const GeometryFunctor& functor,
4546
const PairwiseMatches& putativeMatches,
@@ -73,7 +74,6 @@ void robustModelEstimation(PairwiseMatches& out_geometricMatches,
7374
{
7475
MatchesPerDescType guidedGeometricInliers;
7576
geometricFilter.Geometry_guided_matching(sfmData, regionsPerView, imagePair, distanceRatio, guidedGeometricInliers);
76-
// ALICEVISION_LOG_DEBUG("#before/#after: " << putative_inliers.size() << "/" << guided_geometric_inliers.size());
7777
std::swap(inliers, guidedGeometricInliers);
7878
}
7979

@@ -87,6 +87,64 @@ void robustModelEstimation(PairwiseMatches& out_geometricMatches,
8787
}
8888
}
8989

90+
/**
91+
* @brief Perform robust model estimation (with optional guided_matching)
92+
* or all the pairs and regions correspondences contained in the putativeMatches set.
93+
* Allow to keep only geometrically coherent matches.
94+
* It discards pairs that do not lead to a valid robust model estimation.
95+
* @param[out] out_geometricInfos
96+
* @param[in] sfmData
97+
* @param[in] regionsPerView
98+
* @param[in] functor
99+
* @param[in] putativeMatches
100+
* @param[in] randomNumberGenerator
101+
*/
102+
template<typename GeometryFunctor>
103+
void robustModelEstimation(PairwiseGeometricInfo& out_geometricInfos,
104+
const sfmData::SfMData & sfmData,
105+
const feature::RegionsPerView& regionsPerView,
106+
const GeometryFunctor& functor,
107+
const PairwiseMatches& putativeMatches,
108+
std::mt19937& randomNumberGenerator)
109+
{
110+
out_geometricInfos.clear();
111+
112+
auto progressDisplay = system::createConsoleProgressDisplay(putativeMatches.size(), std::cout, "Robust Model Estimation\n");
113+
114+
#pragma omp parallel for schedule(dynamic)
115+
for (int i = 0; i < (int)putativeMatches.size(); ++i)
116+
{
117+
PairwiseMatches::const_iterator iter = putativeMatches.begin();
118+
std::advance(iter, i);
119+
120+
const Pair currentPair = iter->first;
121+
const MatchesPerDescType& putativeMatchesPerType = iter->second;
122+
const Pair& imagePair = iter->first;
123+
124+
// apply the geometric filter (robust model estimation)
125+
{
126+
MatchesPerDescType inliers;
127+
GeometryFunctor geometricFilter = functor; // use a copy since we are in a multi-thread context
128+
const EstimationStatus state =
129+
geometricFilter.geometricEstimation(sfmData, regionsPerView, imagePair, putativeMatchesPerType, randomNumberGenerator, inliers);
130+
131+
if (state.hasStrongSupport)
132+
{
133+
#pragma omp critical
134+
{
135+
PairGeometricInfo info;
136+
info.model = geometricFilter.getMatrix();
137+
info.inliers = inliers.getNbAllMatches();
138+
info.threshold = geometricFilter.m_dPrecision_robust;
139+
info.type = geometricFilter.getType();
140+
out_geometricInfos.emplace(currentPair, info);
141+
}
142+
}
143+
}
144+
++progressDisplay;
145+
}
146+
}
147+
90148
/**
91149
* @brief removePoorlyOverlappingImagePairs Removes image pairs from the given list of geometric
92150
* matches that have poor overlap according to the supplied criteria.

src/aliceVision/matchingImageCollection/GeometricFilterMatrix.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
#pragma once
99

10+
#include <aliceVision/matchingImageCollection/GeometricFilterType.hpp>
11+
1012
namespace aliceVision {
1113

1214
namespace feature {
@@ -31,6 +33,10 @@ struct GeometricFilterMatrix
3133
m_stIteration(stIteration)
3234
{}
3335

36+
virtual Eigen::Matrix3d getMatrix() = 0;
37+
38+
virtual EGeometricFilterType getType() = 0;
39+
3440
/**
3541
* @brief Geometry_guided_matching
3642
* @param sfm_data
@@ -40,7 +46,7 @@ struct GeometricFilterMatrix
4046
* @param matches
4147
* @return
4248
*/
43-
virtual bool Geometry_guided_matching(const sfmData::SfMData* sfmData,
49+
virtual bool Geometry_guided_matching(const sfmData::SfMData& sfmData,
4450
const feature::RegionsPerView& regionsPerView,
4551
const Pair imageIdsPair,
4652
const double dDistanceRatio,

0 commit comments

Comments
 (0)