@@ -224,6 +224,111 @@ bool filterLandmarks(SfMData& sfmData, double radiusScale, bool useFeatureScale,
224224 }
225225 }
226226
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+
227332 if (radiusScale <= 0 )
228333 {
229334 std::vector<std::pair<IndexT, Landmark>> filteredLandmarks (landmarksData.size ());
0 commit comments