Skip to content

Commit 103f92d

Browse files
committed
[filterSfM] improve observation selection strategy
- add a re-distribution of observation scores at each iteration by favouring best N observations that will be selected at the end - fix hard-coded parameters
1 parent 65e47e5 commit 103f92d

File tree

1 file changed

+32
-15
lines changed

1 file changed

+32
-15
lines changed

src/software/pipeline/main_filterSfM.cpp

+32-15
Original file line numberDiff line numberDiff line change
@@ -215,7 +215,8 @@ ObservationsPerView getObservationsPerViews(SfMData& sfmData)
215215
return observationsPerView;
216216
}
217217

218-
bool filterLandmarks(SfMData& sfmData, double radiusScale, bool useFeatureScale, int minNbObservationsPerLandmark)
218+
bool filterLandmarks(SfMData& sfmData, double radiusScale, bool useFeatureScale, int minNbObservationsPerLandmark,
219+
int nbNeighbors3D, int maxNbObservationsPerLandmark)
219220
{
220221
const auto initialNbLandmarks = sfmData.getLandmarks().size();
221222
std::vector<Landmark> landmarksData(initialNbLandmarks);
@@ -255,11 +256,8 @@ bool filterLandmarks(SfMData& sfmData, double radiusScale, bool useFeatureScale,
255256
tree.buildIndex();
256257
ALICEVISION_LOG_INFO("KdTree created for " << landmarksData.size() << " points.");
257258

258-
// TODO as parameter
259-
int nbNeighbors3D = 10;
260259
// note that the landmark is a neighbor to itself with zero distance, hence the +/- 1
261260
int nbNeighbors_ = std::min(nbNeighbors3D, static_cast<int>(landmarksData.size() - 1)) + 1;
262-
263261
// contains the observing view ids and neighbors for each landmark
264262
std::vector<std::pair<std::vector<IndexT>, std::vector<size_t>>> viewData(landmarksData.size());
265263

@@ -287,8 +285,6 @@ bool filterLandmarks(SfMData& sfmData, double radiusScale, bool useFeatureScale,
287285

288286
std::vector<bool> toRemove(landmarksData.size(), false);
289287
size_t nbToRemove = 0;
290-
// TODO as parameter
291-
int maxNbObservationsPerLandmark = 2;
292288
const auto initialNbLandmarks = sfmData.getLandmarks().size();
293289
#pragma omp parallel for reduction(+ : nbToRemove)
294290
for(auto i = 0; i < landmarksData.size(); i++)
@@ -552,7 +548,6 @@ bool filterObservations3D(SfMData& sfmData, int maxNbObservationsPerLandmark, in
552548
std::vector<std::vector<double>> viewScoresData_t(landmarksData.size());
553549
for(auto i = 0; i < nbIterations; i++)
554550
{
555-
ALICEVISION_LOG_INFO("Iteration " << i << "...");
556551
#pragma omp parallel for
557552
for(auto id = 0; id < landmarksData.size(); id++)
558553
{
@@ -603,23 +598,44 @@ bool filterObservations3D(SfMData& sfmData, int maxNbObservationsPerLandmark, in
603598
{
604599
// normalize score and apply influence factor
605600
viewScores_acc[j] *= neighborsInfluence / viewScores_total;
606-
// combine weghted neighbor scores and the landmark's own scores
601+
// combine weighted neighbor scores and the landmark's own scores
607602
viewScores_acc[j] += (1 - neighborsInfluence) * viewScores[j];
608603
}
604+
// dampen scores of non-chosen observations
605+
if(viewScores_acc.size() <= maxNbObservationsPerLandmark)
606+
continue;
607+
// sort by descending view score order
608+
std::vector<size_t> idx(viewScores_acc.size());
609+
std::iota(idx.begin(), idx.end(), 0);
610+
std::stable_sort(idx.begin(), idx.end(),
611+
[&v = viewScores_acc](size_t i1, size_t i2) { return v[i1] > v[i2]; });
612+
viewScores_total = 1.;
613+
for(auto j = maxNbObservationsPerLandmark; j < viewScores_acc.size(); j++)
614+
{
615+
const double& v = 0.5 * viewScores_acc[j];
616+
viewScores_acc[j] = v;
617+
viewScores_total -= v;
618+
}
619+
// re-normalize
620+
for(auto j = 0; j < viewScores_acc.size(); j++)
621+
viewScores_acc[j] /= viewScores_total;
609622
}
610623
// update scores at end of iteration
611624
double error = 0.;
612625
#pragma omp parallel for reduction(+:error)
613626
for(auto id = 0; id < landmarksData.size(); id++)
614627
{
615-
double error_j = 0.;
616-
for(auto j = 0; j < viewScoresData_t[id].size(); j++)
628+
// compute MSE
617629
{
618-
const auto& v = viewScoresData_t[id][j] - viewScoresData[id].second[j];
619-
error_j += v * v;
630+
double error_j = 0.;
631+
for(auto j = 0; j < viewScoresData_t[id].size(); j++)
632+
{
633+
const auto& v = viewScoresData_t[id][j] - viewScoresData[id].second[j];
634+
error_j += v * v;
635+
}
636+
error_j /= viewScoresData_t[id].size();
637+
error += error_j;
620638
}
621-
error_j /= viewScoresData_t[id].size();
622-
error += error_j;
623639
viewScoresData[id].second = std::move(viewScoresData_t[id]);
624640
}
625641
error /= landmarksData.size();
@@ -850,7 +866,8 @@ int aliceVision_main(int argc, char *argv[])
850866
if(radiusScale > 0 || minNbObservationsPerLandmark > 0)
851867
{
852868
ALICEVISION_LOG_INFO("Filtering landmarks: started.");
853-
filterLandmarks(sfmData, radiusScale, useFeatureScale, minNbObservationsPerLandmark);
869+
filterLandmarks(sfmData, radiusScale, useFeatureScale, minNbObservationsPerLandmark, nbNeighbors3D,
870+
maxNbObservationsPerLandmark);
854871
ALICEVISION_LOG_INFO("Filtering landmarks: done.");
855872
}
856873

0 commit comments

Comments
 (0)