10
10
#include < lemon/list_graph.h>
11
11
#include < lemon/unionfind.h>
12
12
13
+ /* *
14
+ * @brief Contains necessary information to uniquely identify a duplicate feature
15
+ */
16
+ struct DuplicateFeatureId
17
+ {
18
+ DuplicateFeatureId (float x_, float y_, float scale_)
19
+ : x(x_),
20
+ y (y_),
21
+ scale(scale_)
22
+ {}
23
+
24
+ // for uniqueness test when used as a map key
25
+ bool operator <(const DuplicateFeatureId& other) const
26
+ {
27
+ if (x == other.x )
28
+ {
29
+ if (y == other.y )
30
+ return scale < other.scale ;
31
+ return y < other.y ;
32
+ }
33
+ return x < other.x ;
34
+ }
35
+
36
+ float x, y, scale;
37
+ };
38
+
13
39
namespace aliceVision {
14
40
namespace track {
15
41
16
42
using namespace aliceVision ::matching;
17
43
using namespace lemon ;
18
44
19
- // / IndexedFeaturePair is: map<viewId, keypointId>
20
- using IndexedFeaturePair = std::pair<std::size_t , KeypointId>;
21
45
using IndexMap = lemon::ListDigraph::NodeMap<std::size_t >;
22
46
using UnionFindObject = lemon::UnionFindEnum<IndexMap>;
23
47
@@ -42,7 +66,7 @@ TracksBuilder::TracksBuilder() { _d.reset(new TracksBuilderData()); }
42
66
43
67
TracksBuilder::~TracksBuilder () = default ;
44
68
45
- void TracksBuilder::build (const PairwiseMatches& pairwiseMatches)
69
+ void buildTracks (const PairwiseMatches& pairwiseMatches, std::unique_ptr<TracksBuilderData>& _d, MapIndexToNode& map_indexToNode )
46
70
{
47
71
typedef std::set<IndexedFeaturePair> SetIndexedPair;
48
72
@@ -72,7 +96,6 @@ void TracksBuilder::build(const PairwiseMatches& pairwiseMatches)
72
96
}
73
97
74
98
// build the node indirection for each referenced feature
75
- MapIndexToNode map_indexToNode;
76
99
map_indexToNode.reserve (allFeatures.size ());
77
100
_d->map_nodeToIndex .reserve (allFeatures.size ());
78
101
@@ -114,6 +137,119 @@ void TracksBuilder::build(const PairwiseMatches& pairwiseMatches)
114
137
}
115
138
}
116
139
140
+ // Merge tracks that have corresponding duplicate features.
141
+ // Make the union according to duplicate features
142
+ // (same position, scale and describer type, but different orientations)
143
+ void mergeTracks (const feature::MapFeaturesPerView& featuresPerView,
144
+ const MapIndexToNode& map_indexToNode,
145
+ const PairwiseMatches& pairwiseMatches,
146
+ std::unique_ptr<TracksBuilderData>& _d,
147
+ stl::flat_map<IndexedFeaturePair, size_t >& _duplicateFeaturesMap)
148
+ {
149
+ // map of (viewId) to
150
+ // map of (descType) to
151
+ // map of DuplicateFeatureId(x, y, scale) to
152
+ // pair of (set<featureId>, node)
153
+ HashMap<size_t ,
154
+ HashMap<feature::EImageDescriberType, HashMap<DuplicateFeatureId, std::pair<std::set<size_t >, const MapIndexToNode::mapped_type*>>>>
155
+ duplicateFeaturesPerView;
156
+
157
+ // per viewId pair
158
+ for (const auto & matchesPerDescIt : pairwiseMatches)
159
+ {
160
+ const std::size_t & I = matchesPerDescIt.first .first ;
161
+ const std::size_t & J = matchesPerDescIt.first .second ;
162
+ const MatchesPerDescType& matchesPerDesc = matchesPerDescIt.second ;
163
+
164
+ auto & featuresPerDescI = featuresPerView.at (I);
165
+ auto & featuresPerDescJ = featuresPerView.at (J);
166
+ auto & duplicateFeaturesPerDescI = duplicateFeaturesPerView[I];
167
+ auto & duplicateFeaturesPerDescJ = duplicateFeaturesPerView[J];
168
+
169
+ // per descType
170
+ for (const auto & matchesIt : matchesPerDesc)
171
+ {
172
+ const feature::EImageDescriberType descType = matchesIt.first ;
173
+ const IndMatches& matches = matchesIt.second ;
174
+
175
+ auto & featuresI = featuresPerDescI.at (descType);
176
+ auto & featuresJ = featuresPerDescJ.at (descType);
177
+ auto & duplicateFeaturesI = duplicateFeaturesPerDescI[descType];
178
+ auto & duplicateFeaturesJ = duplicateFeaturesPerDescJ[descType];
179
+
180
+ // per features match
181
+ for (const IndMatch& m : matches)
182
+ {
183
+ {
184
+ auto & featureI = featuresI[m._i ];
185
+ auto & [duplicateFeatureIdsI, duplicateFeatureNodeI] =
186
+ duplicateFeaturesI[DuplicateFeatureId (featureI.x (), featureI.y (), featureI.scale ())];
187
+ IndexedFeaturePair pairI (I, KeypointId (descType, m._i ));
188
+ auto & nodeI = map_indexToNode.at (pairI);
189
+ // if no duplicates yet found, add to map and update values
190
+ if (duplicateFeatureNodeI == nullptr )
191
+ {
192
+ duplicateFeatureIdsI.insert (m._i );
193
+ duplicateFeatureNodeI = &nodeI;
194
+ }
195
+ // if not already in corresponding duplicates set, add to set and join nodes
196
+ else if (duplicateFeatureIdsI.insert (m._i ).second )
197
+ {
198
+ _d->tracksUF ->join (nodeI, *duplicateFeatureNodeI);
199
+ }
200
+ }
201
+ {
202
+ auto & featureJ = featuresJ[m._j ];
203
+ auto & [duplicateFeatureIdsJ, duplicateFeatureNodeJ] =
204
+ duplicateFeaturesJ[DuplicateFeatureId (featureJ.x (), featureJ.y (), featureJ.scale ())];
205
+ IndexedFeaturePair pairJ (J, KeypointId (descType, m._j ));
206
+ auto & nodeJ = map_indexToNode.at (pairJ);
207
+ // if no duplicates yet found, add to map and update values
208
+ if (duplicateFeatureNodeJ == nullptr )
209
+ {
210
+ duplicateFeatureIdsJ.insert (m._j );
211
+ duplicateFeatureNodeJ = &nodeJ;
212
+ }
213
+ // if not already in corresponding duplicates set, add to set and join nodes
214
+ else if (duplicateFeatureIdsJ.insert (m._j ).second )
215
+ {
216
+ _d->tracksUF ->join (nodeJ, *duplicateFeatureNodeJ);
217
+ }
218
+ }
219
+ }
220
+ }
221
+ }
222
+
223
+ // fill duplicate features map
224
+ for (const auto & [viewId, duplicateFeaturesPerDesc] : duplicateFeaturesPerView)
225
+ for (const auto & [descType, duplicateFeatures] : duplicateFeaturesPerDesc)
226
+ for (const auto & [duplicateFeatureId, duplicateFeature] : duplicateFeatures)
227
+ {
228
+ auto & duplicateFeatureIdsSet = duplicateFeature.first ;
229
+ size_t indexedFeaturePair_0 = *duplicateFeatureIdsSet.begin ();
230
+ for (const auto & featureId : duplicateFeatureIdsSet)
231
+ {
232
+ const auto & indexedFeaturePair_i = IndexedFeaturePair (viewId, KeypointId (descType, featureId));
233
+ _duplicateFeaturesMap[indexedFeaturePair_i] = indexedFeaturePair_0;
234
+ }
235
+ }
236
+ }
237
+
238
+ void TracksBuilder::build (const PairwiseMatches& pairwiseMatches)
239
+ {
240
+ // the node indirection for each referenced feature
241
+ MapIndexToNode map_indexToNode;
242
+ buildTracks (pairwiseMatches, _d, map_indexToNode);
243
+ }
244
+
245
+ void TracksBuilder::build (const PairwiseMatches& pairwiseMatches, const feature::MapFeaturesPerView& featuresPerView)
246
+ {
247
+ // the node indirection for each referenced feature
248
+ MapIndexToNode map_indexToNode;
249
+ buildTracks (pairwiseMatches, _d, map_indexToNode);
250
+ mergeTracks (featuresPerView, map_indexToNode, pairwiseMatches, _d, _duplicateFeaturesMap);
251
+ }
252
+
117
253
void TracksBuilder::filter (bool clearForks, std::size_t minTrackLength, bool multithreaded)
118
254
{
119
255
// remove bad tracks:
@@ -129,14 +265,30 @@ void TracksBuilder::filter(bool clearForks, std::size_t minTrackLength, bool mul
129
265
{
130
266
#pragma omp single nowait
131
267
{
132
- std:: size_t cpt = 0 ;
133
- std::set<std:: size_t > myset;
268
+ bool flag = false ;
269
+ stl::flat_map< size_t , IndexedFeaturePair > myset;
134
270
for (lemon::UnionFindEnum<IndexMap>::ItemIt iit (*_d->tracksUF , cit); iit != INVALID; ++iit)
135
271
{
136
- myset.insert (_d->map_nodeToIndex [iit].first );
137
- ++cpt;
272
+ IndexedFeaturePair currentPair = _d->map_nodeToIndex [iit];
273
+ {
274
+ const auto & duplicateIt = _duplicateFeaturesMap.find (currentPair);
275
+ if (duplicateIt != _duplicateFeaturesMap.end ())
276
+ currentPair.second .featIndex = duplicateIt->second ;
277
+ }
278
+ const auto & myIt = myset.find (currentPair.first );
279
+ if (myIt != myset.end ())
280
+ {
281
+ if (myIt->second < currentPair || currentPair < myIt->second )
282
+ {
283
+ flag = true ;
284
+ }
285
+ }
286
+ else
287
+ {
288
+ myset[currentPair.first ] = currentPair;
289
+ }
138
290
}
139
- if ((clearForks && myset. size () != cpt ) || myset.size () < minTrackLength)
291
+ if ((clearForks && flag ) || myset.size () < minTrackLength)
140
292
{
141
293
#pragma omp critical
142
294
set_classToErase.insert (cit.operator int ());
@@ -186,7 +338,12 @@ void TracksBuilder::exportToSTL(TracksMap& allTracks) const
186
338
const IndexedFeaturePair& currentPair = _d->map_nodeToIndex .at (iit);
187
339
// all descType inside the track will be the same
188
340
outTrack.descType = currentPair.second .descType ;
189
- outTrack.featPerView [currentPair.first ] = currentPair.second .featIndex ;
341
+ // Warning: overwrites featureIndex if clearForks is False
342
+ const auto & duplicateIt = _duplicateFeaturesMap.find (currentPair);
343
+ if (duplicateIt != _duplicateFeaturesMap.end ())
344
+ outTrack.featPerView [currentPair.first ] = duplicateIt->second ;
345
+ else
346
+ outTrack.featPerView [currentPair.first ] = currentPair.second .featIndex ;
190
347
}
191
348
}
192
349
}
0 commit comments