@@ -249,64 +249,8 @@ bool filterLandmarks(SfMData& sfmData, double radiusScale, bool useFeatureScale,
249249 return true ;
250250}
251251
252- bool filterObservations (SfMData& sfmData, int maxNbObservationsPerLandmark)
253- {
254- std::vector<Landmark*> landmarksData (sfmData.getLandmarks ().size ());
255- {
256- size_t i = 0 ;
257- for (auto & it : sfmData.getLandmarks ())
258- {
259- landmarksData[i++] = &it.second ;
260- }
261- }
262-
263- #pragma omp parallel for
264- for (auto i = 0 ; i < landmarksData.size (); i++)
265- {
266- sfmData::Landmark& landmark = *landmarksData[i];
267-
268- // check number of observations
269- if (landmark.observations .size () <= maxNbObservationsPerLandmark)
270- continue ;
271-
272- // // check angle between observations
273- // if(!checkLandmarkMinObservationAngle(sfmData, landmark, minObservationAngle))
274-
275- // compute observation scores
276-
277- std::vector<std::pair<double , IndexT>> observationScores;
278- observationScores.reserve (landmark.observations .size ());
279-
280- for (const auto & observationPair : landmark.observations )
281- {
282- const IndexT viewId = observationPair.first ;
283- const sfmData::View& view = *(sfmData.getViews ().at (viewId));
284- const geometry::Pose3 pose = sfmData.getPose (view).getTransform ();
285-
286- observationScores.push_back (std::pair<double , IndexT>(
287- (pose.center () - landmark.X ).squaredNorm (),
288- viewId
289- ));
290- }
291-
292- // sort observations by ascending score order
293- std::stable_sort (observationScores.begin (), observationScores.end ());
294- // take only best observations
295- observationScores.resize (maxNbObservationsPerLandmark);
296-
297- // replace the observations
298- Observations filteredObservations;
299- for (const auto & observationScorePair : observationScores)
300- {
301- filteredObservations[observationScorePair.second ] = landmark.observations [observationScorePair.second ];
302- }
303- landmark.observations = std::move (filteredObservations);
304- }
305- return true ;
306- }
307-
308- bool filterObservations2 (SfMData& sfmData, int maxNbObservationsPerLandmark, int nbNeighbors = 10 , int nbIterations = 5 ,
309- double fraction = 0.5 )
252+ bool filterObservations (SfMData& sfmData, int maxNbObservationsPerLandmark, int nbNeighbors, double neighborsInfluence,
253+ int nbIterations)
310254{
311255 std::vector<Landmark*> landmarksData (sfmData.getLandmarks ().size ());
312256 {
@@ -371,16 +315,18 @@ bool filterObservations2(SfMData& sfmData, int maxNbObservationsPerLandmark, int
371315 KdTree tree (3 , dataAdaptor, nanoflann::KDTreeSingleIndexAdaptorParams (MAX_LEAF_ELEMENTS));
372316 tree.buildIndex ();
373317 ALICEVISION_LOG_INFO (" KdTree created for " << landmarksData.size () << " points." );
318+ // note that the landmark is a neighbor to itself with zero distance, hence the +/- 1
319+ int nbNeighbors_ = std::min (nbNeighbors, static_cast <int >(landmarksData.size () - 1 )) + 1 ;
374320 std::vector<std::pair<std::vector<size_t >, std::vector<double >>> neighborsData (landmarksData.size ());
375321#pragma omp parallel for
376322 for (auto i = 0 ; i < landmarksData.size (); i++)
377323 {
378324 const sfmData::Landmark& landmark = *landmarksData[i];
379325 auto & [indices_, weights_] = neighborsData[i];
380- // a landmark is a neighbor to itself with zero distance
381- indices_ .resize (nbNeighbors + 1 );
382- weights_. resize (nbNeighbors + 1 );
383- tree. knnSearch ( landmark. X . data (), nbNeighbors + 1 , &indices_[ 0 ], &weights_[ 0 ]);
326+ indices_. resize (nbNeighbors_);
327+ weights_ .resize (nbNeighbors_ );
328+ tree. knnSearch (landmark. X . data (), nbNeighbors_, &indices_[ 0 ], &weights_[ 0 ] );
329+ // a landmark is a neighbor to itself with zero distance, remove it
384330 indices_.erase (indices_.begin ());
385331 weights_.erase (weights_.begin ());
386332 double total = 0 .;
@@ -442,8 +388,8 @@ bool filterObservations2(SfMData& sfmData, int maxNbObservationsPerLandmark, int
442388 }
443389 for (auto j = 0 ; j < viewScores_acc.size (); j++)
444390 {
445- viewScores_acc[j] *= fraction / viewScores_total;
446- viewScores_acc[j] += (1 - fraction ) * viewScores[j];
391+ viewScores_acc[j] *= neighborsInfluence / viewScores_total;
392+ viewScores_acc[j] += (1 - neighborsInfluence ) * viewScores[j];
447393 }
448394 }
449395#pragma omp parallel for
@@ -485,13 +431,15 @@ int aliceVision_main(int argc, char *argv[])
485431{
486432 // command-line parameters
487433
488- // std::string verboseLevel = system::EVerboseLevel_enumToString(system::Logger::getDefaultVerboseLevel());
489434 std::string inputSfmFilename;
490435 std::string outputSfmFilename;
491436 int maxNbObservationsPerLandmark = 2 ;
492437 int minNbObservationsPerLandmark = 5 ;
493438 double radiusScale = 2 ;
494439 bool useFeatureScale = true ;
440+ int nbNeighbors = 10 ;
441+ double neighborsInfluence = 0.5 ;
442+ int nbIterations = 5 ;
495443
496444 // user optional parameters
497445 std::vector<std::string> featuresFolders;
@@ -515,14 +463,21 @@ int aliceVision_main(int argc, char *argv[])
515463 " Scale factor applied to pixel size based radius filter applied to landmarks." )
516464 (" useFeatureScale" , po::value<bool >(&useFeatureScale)->default_value (useFeatureScale),
517465 " If true, use feature scale for computing pixel size. Otherwise, use a scale of 1 pixel." )
466+ (" nbNeighbors" , po::value<int >(&nbNeighbors)->default_value (nbNeighbors),
467+ " Number of neighbor landmarks used in making the decision for best observations." )
468+ (" neighborsInfluence" , po::value<double >(&neighborsInfluence)->default_value (neighborsInfluence),
469+ " Specifies how much influential the neighbors are in selecting the best observations."
470+ " Between 0. and 1., the closer to 1., the more influencial the neighborhood is." )
471+ (" nbIterations" , po::value<int >(&nbIterations)->default_value (nbIterations),
472+ " Number of iterations to propagate neighbors information." )
518473 (" featuresFolders,f" , po::value<std::vector<std::string>>(&featuresFolders)->multitoken (),
519474 " Path to folder(s) containing the extracted features." )
520475 (" matchesFolders,m" , po::value<std::vector<std::string>>(&matchesFolders)->multitoken (),
521476 " Path to folder(s) in which computed matches are stored." )
522477 (" describerTypes,d" , po::value<std::string>(&describerTypesName)->default_value (describerTypesName),
523478 feature::EImageDescriberType_informations ().c_str ());
524479
525- CmdLine cmdline (" AliceVision SfM filtering." );
480+ CmdLine cmdline (" AliceVision SfM filtering." ); // TODO add description
526481 cmdline.add (requiredParams);
527482 cmdline.add (optionalParams);
528483 if (!cmdline.execute (argc, argv))
@@ -557,7 +512,7 @@ int aliceVision_main(int argc, char *argv[])
557512 if (maxNbObservationsPerLandmark > 0 )
558513 {
559514 ALICEVISION_LOG_INFO (" Filtering observations: started." );
560- filterObservations2 (sfmData, maxNbObservationsPerLandmark);
515+ filterObservations (sfmData, maxNbObservationsPerLandmark, nbNeighbors, neighborsInfluence, nbIterations );
561516 ALICEVISION_LOG_INFO (" Filtering observations: done." );
562517 }
563518
0 commit comments