@@ -252,6 +252,7 @@ bool filterLandmarks(SfMData& sfmData, double radiusScale, bool useFeatureScale,
252
252
bool filterObservations (SfMData& sfmData, int maxNbObservationsPerLandmark, int nbNeighbors, double neighborsInfluence,
253
253
int nbIterations)
254
254
{
255
+ // store in vector for faster access
255
256
std::vector<Landmark*> landmarksData (sfmData.getLandmarks ().size ());
256
257
{
257
258
size_t i = 0 ;
@@ -261,6 +262,7 @@ bool filterObservations(SfMData& sfmData, int maxNbObservationsPerLandmark, int
261
262
}
262
263
}
263
264
265
+ // contains the observing view ids for each landmark with their corresponding scores
264
266
std::vector<std::pair<std::vector<IndexT>, std::vector<double >>> viewScoresData (landmarksData.size ());
265
267
266
268
ALICEVISION_LOG_INFO (" Computing initial observation scores based on distance to observing view: started" );
@@ -270,11 +272,11 @@ bool filterObservations(SfMData& sfmData, int maxNbObservationsPerLandmark, int
270
272
const sfmData::Landmark& landmark = *landmarksData[i];
271
273
272
274
// compute observation scores
273
-
274
275
const auto & nbObservations = landmark.observations .size ();
275
276
auto & [viewIds, viewScores] = viewScoresData[i];
276
277
viewIds.reserve (nbObservations);
277
278
viewScores.reserve (nbObservations);
279
+ // accumulator for normalizing the scores
278
280
double total = 0 .;
279
281
for (const auto & observationPair : landmark.observations )
280
282
{
@@ -283,6 +285,7 @@ bool filterObservations(SfMData& sfmData, int maxNbObservationsPerLandmark, int
283
285
const geometry::Pose3 pose = sfmData.getPose (view).getTransform ();
284
286
285
287
viewIds.push_back (viewId);
288
+ // score is the inverse of distance to observations
286
289
const auto & v = 1 . / (pose.center () - landmark.X ).squaredNorm ();
287
290
total += v;
288
291
viewScores.push_back (v);
@@ -296,9 +299,12 @@ bool filterObservations(SfMData& sfmData, int maxNbObservationsPerLandmark, int
296
299
297
300
// sort by ascending view id order
298
301
// for consequent faster access
302
+
303
+ // indices that sort the view ids
299
304
std::vector<size_t > idx (nbObservations);
300
305
std::iota (idx.begin (), idx.end (), 0 );
301
306
std::stable_sort (idx.begin (), idx.end (), [&v = viewIds](size_t i1, size_t i2) { return v[i1] < v[i2]; });
307
+ // apply sorting to both view ids and view scores for correspondance
302
308
auto ids_temp = viewIds;
303
309
auto scores_temp = viewScores;
304
310
for (auto j = 0 ; j < nbObservations; j++)
@@ -317,6 +323,7 @@ bool filterObservations(SfMData& sfmData, int maxNbObservationsPerLandmark, int
317
323
ALICEVISION_LOG_INFO (" KdTree created for " << landmarksData.size () << " points." );
318
324
// note that the landmark is a neighbor to itself with zero distance, hence the +/- 1
319
325
int nbNeighbors_ = std::min (nbNeighbors, static_cast <int >(landmarksData.size () - 1 )) + 1 ;
326
+ // contains the neighbor landmarks ids with their corresponding weights
320
327
std::vector<std::pair<std::vector<size_t >, std::vector<double >>> neighborsData (landmarksData.size ());
321
328
#pragma omp parallel for
322
329
for (auto i = 0 ; i < landmarksData.size (); i++)
@@ -329,12 +336,15 @@ bool filterObservations(SfMData& sfmData, int maxNbObservationsPerLandmark, int
329
336
// a landmark is a neighbor to itself with zero distance, remove it
330
337
indices_.erase (indices_.begin ());
331
338
weights_.erase (weights_.begin ());
339
+ // accumulator used for normalisation
332
340
double total = 0 .;
333
341
for (auto & w : weights_)
334
342
{
343
+ // weight is the inverse of distance between a landmark and its neighbor
335
344
w = 1 . / std::sqrt (w);
336
345
total += w;
337
346
}
347
+ // normalize weights
338
348
for (auto & w : weights_)
339
349
{
340
350
w /= total;
@@ -343,6 +353,7 @@ bool filterObservations(SfMData& sfmData, int maxNbObservationsPerLandmark, int
343
353
ALICEVISION_LOG_INFO (" Computing landmark neighbors and distance-based weights: done" );
344
354
345
355
ALICEVISION_LOG_INFO (" Propagating neighbors observation scores: started" );
356
+ // new view scores at iteration t
346
357
std::vector<std::vector<double >> viewScoresData_t (landmarksData.size ());
347
358
for (auto i = 0 ; i < nbIterations; i++)
348
359
{
@@ -352,14 +363,17 @@ bool filterObservations(SfMData& sfmData, int maxNbObservationsPerLandmark, int
352
363
{
353
364
const auto & [viewIds, viewScores] = viewScoresData[id];
354
365
auto & viewScores_acc = viewScoresData_t[id];
366
+ // initialize to zero, will first contain the weighted average scores of neighbors
355
367
viewScores_acc.assign (viewScores.size (), 0 .);
368
+ // accumulator for normalisation
356
369
double viewScores_total = 0 .;
357
370
auto & [indices_, weights_] = neighborsData[id];
358
371
for (auto j = 0 ; j < nbNeighbors; j++)
359
372
{
360
373
const auto & neighborId = indices_[j];
361
374
const auto & neighborWeight = weights_[j];
362
375
const auto & [viewIds_neighbor, viewScores_neighbor] = viewScoresData[neighborId];
376
+ // loop over common views
363
377
auto viewIds_it = viewIds.begin ();
364
378
auto viewIds_neighbor_it = viewIds_neighbor.begin ();
365
379
auto viewScores_neighbor_it = viewScores_neighbor.begin ();
@@ -373,6 +387,7 @@ bool filterObservations(SfMData& sfmData, int maxNbObservationsPerLandmark, int
373
387
}
374
388
else
375
389
{
390
+ // if same view, accumulate weighted scores
376
391
if (!(*viewIds_neighbor_it < *viewIds_it))
377
392
{
378
393
const auto & v = *viewScores_neighbor_it * neighborWeight;
@@ -388,10 +403,13 @@ bool filterObservations(SfMData& sfmData, int maxNbObservationsPerLandmark, int
388
403
}
389
404
for (auto j = 0 ; j < viewScores_acc.size (); j++)
390
405
{
406
+ // normalize score and apply influence factor
391
407
viewScores_acc[j] *= neighborsInfluence / viewScores_total;
408
+ // combine weghted neighbor scores and the landmark's own scores
392
409
viewScores_acc[j] += (1 - neighborsInfluence) * viewScores[j];
393
410
}
394
411
}
412
+ // update scores at end of iteration
395
413
#pragma omp parallel for
396
414
for (auto id = 0 ; id < landmarksData.size (); id++)
397
415
{
@@ -417,7 +435,7 @@ bool filterObservations(SfMData& sfmData, int maxNbObservationsPerLandmark, int
417
435
std::iota (idx.begin (), idx.end (), 0 );
418
436
std::stable_sort (idx.begin (), idx.end (), [&v = viewScores](size_t i1, size_t i2) { return v[i1] > v[i2]; });
419
437
420
- // replace the observations
438
+ // keep only observations with best scores
421
439
Observations filteredObservations;
422
440
for (auto j = 0 ; j < maxNbObservationsPerLandmark; j++)
423
441
{
0 commit comments