@@ -224,6 +224,111 @@ bool filterLandmarks(SfMData& sfmData, double radiusScale, bool useFeatureScale,
224
224
}
225
225
}
226
226
227
+ {
228
+ ALICEVISION_LOG_INFO (" Build nanoflann KdTree index for landmarks in 3D." );
229
+ LandmarksAdaptator data (landmarksData);
230
+ KdTree3D tree (3 , data, nanoflann::KDTreeSingleIndexAdaptorParams (MAX_LEAF_ELEMENTS));
231
+ tree.buildIndex ();
232
+ ALICEVISION_LOG_INFO (" KdTree created for " << landmarksData.size () << " points." );
233
+
234
+ // TODO as parameter
235
+ int nbNeighbors3D = 10 ;
236
+ // note that the landmark is a neighbor to itself with zero distance, hence the +/- 1
237
+ int nbNeighbors_ = std::min (nbNeighbors3D, static_cast <int >(landmarksData.size () - 1 )) + 1 ;
238
+
239
+ // contains the observing view ids and neighbors for each landmark
240
+ std::vector<std::pair<std::vector<IndexT>, std::vector<size_t >>> viewData (landmarksData.size ());
241
+
242
+ #pragma omp parallel for
243
+ for (auto i = 0 ; i < landmarksData.size (); i++)
244
+ {
245
+ const sfmData::Landmark& landmark = landmarksData[i];
246
+ const auto & nbObservations = landmark.observations .size ();
247
+ auto & [viewIds, neighbors] = viewData[i];
248
+ viewIds.reserve (nbObservations);
249
+ for (const auto & observationPair : landmark.observations )
250
+ {
251
+ const IndexT viewId = observationPair.first ;
252
+ viewIds.push_back (viewId);
253
+ }
254
+ // sort by ascending view id order for consequent faster access
255
+ std::stable_sort (viewIds.begin (), viewIds.end ());
256
+
257
+ neighbors.resize (nbNeighbors_);
258
+ std::vector<double > weights_ (nbNeighbors_);
259
+ tree.knnSearch (landmark.X .data (), nbNeighbors_, &neighbors[0 ], &weights_[0 ]);
260
+ // a landmark is a neighbor to itself with zero distance, remove it
261
+ neighbors.erase (neighbors.begin ());
262
+ }
263
+
264
+ std::vector<bool > toRemove (landmarksData.size (), false );
265
+ size_t nbToRemove = 0 ;
266
+ // TODO as parameter
267
+ int maxNbObservationsPerLandmark = 2 ;
268
+ const auto initialNbLandmarks = sfmData.getLandmarks ().size ();
269
+ #pragma omp parallel for reduction(+ : nbToRemove)
270
+ for (auto i = 0 ; i < landmarksData.size (); i++)
271
+ {
272
+ int score = 0 ;
273
+ auto & [viewIds, neighbors] = viewData[i];
274
+ for (auto j = 0 ; j < neighbors.size (); j++)
275
+ {
276
+ int scoreNeighbor = 0 ;
277
+ const auto & neighborId = neighbors[j];
278
+ const auto & viewIds_neighbor = viewData[neighborId].first ;
279
+ // loop over common views
280
+ auto viewIds_it = viewIds.begin ();
281
+ auto viewIds_neighbor_it = viewIds_neighbor.begin ();
282
+ while (viewIds_it != viewIds.end () && viewIds_neighbor_it != viewIds_neighbor.end ())
283
+ {
284
+ if (*viewIds_it < *viewIds_neighbor_it)
285
+ {
286
+ ++viewIds_it;
287
+ }
288
+ else
289
+ {
290
+ // if same view
291
+ if (!(*viewIds_neighbor_it < *viewIds_it))
292
+ {
293
+ scoreNeighbor++;
294
+ if (scoreNeighbor == maxNbObservationsPerLandmark)
295
+ {
296
+ score++;
297
+ break ;
298
+ }
299
+ ++viewIds_it;
300
+ }
301
+ ++viewIds_neighbor_it;
302
+ }
303
+ }
304
+ }
305
+ if (score < nbNeighbors3D / 2 )
306
+ {
307
+ toRemove[i] = true ;
308
+ nbToRemove++;
309
+ }
310
+ }
311
+ ALICEVISION_LOG_INFO (" Identified " << nbToRemove << " landmarks to remove out of " << initialNbLandmarks
312
+ << " , i.e. " << (nbToRemove * 100 .f / initialNbLandmarks) << " % " );
313
+ ALICEVISION_LOG_INFO (" Identifying landmarks to remove: done." );
314
+
315
+ ALICEVISION_LOG_INFO (" Removing landmarks based on TODO: started." );
316
+ std::vector<std::pair<IndexT, Landmark>> filteredLandmarks (landmarksData.size () - nbToRemove);
317
+ std::vector<Landmark> landmarksData_filtered (landmarksData.size () - nbToRemove);
318
+ IndexT newIdx = 0 ;
319
+ for (size_t i = 0 ; i < landmarksData.size (); i++)
320
+ {
321
+ if (!toRemove[i])
322
+ {
323
+ landmarksData_filtered[newIdx] = landmarksData[i];
324
+ filteredLandmarks[newIdx++] = std::make_pair (newIdx, landmarksData[i]);
325
+ }
326
+ }
327
+ sfmData.getLandmarks () = std::move (Landmarks (filteredLandmarks.begin (), filteredLandmarks.end ()));
328
+ landmarksData = std::move (landmarksData_filtered);
329
+ ALICEVISION_LOG_INFO (" Removing landmarks based on TODO: done." );
330
+ }
331
+
227
332
if (radiusScale <= 0 )
228
333
{
229
334
std::vector<std::pair<IndexT, Landmark>> filteredLandmarks (landmarksData.size ());
0 commit comments