Skip to content

Commit 827fea1

Browse files
author
Fabien Servant
committed
DepthMap based priors in sfm
Conflicts: src/aliceVision/sfm/pipeline/bootstrapping/PairsScoring.cpp src/aliceVision/sfmData/Landmark.hpp src/software/pipeline/main_sfmBootstrapping.cpp
1 parent 6ca0c37 commit 827fea1

22 files changed

+637
-27
lines changed

src/aliceVision/sfm/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ set(sfm_files_headers
2727
pipeline/bootstrapping/EstimateAngle.hpp
2828
pipeline/bootstrapping/PairsScoring.hpp
2929
pipeline/bootstrapping/Bootstrap.hpp
30+
pipeline/bootstrapping/TracksDepths.hpp
3031
pipeline/expanding/SfmTriangulation.hpp
3132
pipeline/expanding/SfmResection.hpp
3233
pipeline/expanding/SfmBundle.hpp
@@ -71,6 +72,7 @@ set(sfm_files_sources
7172
pipeline/bootstrapping/EstimateAngle.cpp
7273
pipeline/bootstrapping/PairsScoring.cpp
7374
pipeline/bootstrapping/Bootstrap.cpp
75+
pipeline/bootstrapping/TracksDepths.cpp
7476
pipeline/expanding/SfmTriangulation.cpp
7577
pipeline/expanding/SfmResection.cpp
7678
pipeline/expanding/SfmBundle.cpp

src/aliceVision/sfm/pipeline/bootstrapping/Bootstrap.cpp

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <aliceVision/track/tracksUtils.hpp>
99
#include <aliceVision/multiview/triangulation/triangulationDLT.hpp>
1010
#include <aliceVision/sfm/pipeline/expanding/SfmResection.hpp>
11+
#include <aliceVision/sfm/pipeline/bootstrapping/TracksDepths.hpp>
1112
#include <vector>
1213
#include <random>
1314

@@ -166,5 +167,96 @@ bool bootstrapMesh(sfmData::SfMData & sfmData,
166167
return true;
167168
}
168169

170+
bool bootstrapDepth(sfmData::SfMData & sfmData,
171+
const IndexT referenceViewId,
172+
const IndexT nextViewId,
173+
const track::TracksMap& tracksMap,
174+
const track::TracksPerView & tracksPerView)
175+
{
176+
std::mt19937 randomNumberGenerator;
177+
178+
const sfmData::View & viewReference = sfmData.getView(referenceViewId);
179+
const sfmData::View & viewNext = sfmData.getView(nextViewId);
180+
181+
camera::IntrinsicBase::sptr camReference = sfmData.getIntrinsicSharedPtr(viewReference.getIntrinsicId());
182+
camera::IntrinsicBase::sptr camNext = sfmData.getIntrinsicSharedPtr(viewNext.getIntrinsicId());
183+
184+
sfmData::CameraPose & poseReference = sfmData.getPoses()[viewReference.getPoseId()];
185+
sfmData::CameraPose & poseNext = sfmData.getPoses()[viewNext.getPoseId()];
186+
187+
188+
sfmData::SfMData miniSfm;
189+
if (!buildSfmDataFromDepthMap(miniSfm, sfmData, tracksMap, tracksPerView, referenceViewId))
190+
{
191+
return EXIT_FAILURE;
192+
}
193+
194+
sfm::SfmResection resection(50000, std::numeric_limits<double>::infinity());
195+
196+
Eigen::Matrix4d pose;
197+
double newThreshold;
198+
size_t inliersCount;
199+
200+
if (!resection.processView(miniSfm,
201+
tracksMap, tracksPerView,
202+
randomNumberGenerator,
203+
nextViewId, pose, newThreshold, inliersCount))
204+
{
205+
return EXIT_FAILURE;
206+
}
207+
208+
209+
geometry::Pose3 pose3(pose);
210+
poseNext.setTransform(pose3);
211+
212+
const auto & landmarks = miniSfm.getLandmarks();
213+
auto & outLandmarks = sfmData.getLandmarks();
214+
215+
for (const auto & [landmarkId, landmark] : landmarks)
216+
{
217+
//Retrieve track object
218+
const auto & track = tracksMap.at(landmarkId);
219+
220+
const track::TrackItem & itemReference = track.featPerView.at(referenceViewId);
221+
222+
//Maybe this track is not observed in the next view
223+
if (track.featPerView.find(nextViewId) == track.featPerView.end())
224+
{
225+
continue;
226+
}
227+
228+
//Compute error
229+
const track::TrackItem & item = track.featPerView.at(nextViewId);
230+
const Vec2 pt = item.coords;
231+
const Vec2 estpt = camNext->transformProject(pose3, landmark.X.homogeneous(), true);
232+
double err = (pt - estpt).norm();
233+
234+
//If error is ok, then we add it to the sfmData
235+
if (err <= newThreshold)
236+
{
237+
sfmData::Observation obs;
238+
obs.setFeatureId(item.featureId);
239+
obs.setScale(item.scale);
240+
obs.setCoordinates(item.coords);
241+
242+
sfmData::Observation obsReference;
243+
obsReference.setFeatureId(itemReference.featureId);
244+
obsReference.setScale(itemReference.scale);
245+
obsReference.setCoordinates(itemReference.coords);
246+
247+
//Add landmark to sfmData
248+
outLandmarks[landmarkId] = landmark;
249+
outLandmarks[landmarkId].setParallaxRobust(true);
250+
251+
//Add observation to landmark
252+
sfmData::Observations & observations = outLandmarks[landmarkId].getObservations();
253+
observations[referenceViewId] = obsReference;
254+
observations[nextViewId] = obs;
255+
}
256+
}
257+
258+
return true;
259+
}
260+
169261
}
170262
}

src/aliceVision/sfm/pipeline/bootstrapping/Bootstrap.hpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,5 +46,21 @@ bool bootstrapMesh(sfmData::SfMData & sfmData,
4646
const track::TracksMap& tracksMap,
4747
const track::TracksPerView & tracksPerView);
4848

49+
50+
/**
51+
* @brief Create a minimal SfmData with poses and landmarks for two views
52+
* @param sfmData the input sfmData which contains camera information
53+
* @param referenceViewId the reference view id
54+
* @param otherViewId the other view id
55+
* @param otherTreference the relative pose
56+
* @param tracksMap the input map of tracks
57+
* @param tracksPerView tracks grouped by views
58+
* @return true
59+
*/
60+
bool bootstrapDepth(sfmData::SfMData & sfmData,
61+
const IndexT referenceViewId,
62+
const IndexT otherViewId,
63+
const track::TracksMap& tracksMap,
64+
const track::TracksPerView & tracksPerView);
4965
}
5066
}

src/aliceVision/sfm/pipeline/bootstrapping/PairsScoring.cpp

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include <aliceVision/sfm/pipeline/bootstrapping/EstimateAngle.hpp>
99
#include <aliceVision/sfm/pipeline/expanding/ExpansionPolicyLegacy.hpp>
1010
#include <aliceVision/multiview/triangulation/triangulationDLT.hpp>
11+
#include <aliceVision/sfm/pipeline/bootstrapping/TracksDepths.hpp>
12+
#include <aliceVision/sfm/pipeline/expanding/SfmResection.hpp>
1113

1214
namespace aliceVision {
1315
namespace sfm {
@@ -116,5 +118,100 @@ IndexT findBestPair(const sfmData::SfMData & sfmData,
116118
return bestPair;
117119
}
118120

121+
sfm::ReconstructedPair findBestPairFromTrackDepths(const sfmData::SfMData & sfmData,
122+
const std::vector<sfm::ReconstructedPair> & pairs,
123+
const track::TracksMap& tracksMap,
124+
const track::TracksPerView & tracksPerView)
125+
{
126+
std::mt19937 randomNumberGenerator;
127+
128+
std::set<IndexT> views;
129+
for (IndexT pairId = 0; pairId < pairs.size(); pairId++)
130+
{
131+
views.insert(pairs[pairId].reference);
132+
views.insert(pairs[pairId].next);
133+
}
134+
135+
sfm::ReconstructedPair bestPair;
136+
bestPair.reference = UndefinedIndexT;
137+
138+
size_t bestCount = 0;
139+
140+
for (const auto & idView: views)
141+
{
142+
sfmData::SfMData miniSfm;
143+
if (!buildSfmDataFromDepthMap(miniSfm, sfmData, tracksMap, tracksPerView, idView))
144+
{
145+
continue;
146+
}
147+
148+
sfm::SfmResection resection(1024, std::numeric_limits<double>::infinity());
149+
150+
151+
sfm::ReconstructedPair bestPairLocal;
152+
size_t maxInliers = 0;
153+
size_t totalInliers = 0;
154+
155+
for (IndexT pairId = 0; pairId < pairs.size(); pairId++)
156+
{
157+
const auto & pairSource = pairs[pairId];
158+
sfm::ReconstructedPair pair;
159+
pair.reference = idView;
160+
161+
if (pairSource.reference == idView)
162+
{
163+
pair.next = pairSource.next;
164+
}
165+
else if (pairSource.next == idView)
166+
{
167+
pair.next = pairSource.reference;
168+
}
169+
else
170+
{
171+
continue;
172+
}
173+
174+
if (miniSfm.getViews().find(pair.next) == miniSfm.getViews().end())
175+
{
176+
continue;
177+
}
178+
179+
Eigen::Matrix4d pose;
180+
double newThreshold;
181+
size_t inliersCount;
182+
183+
if (!resection.processView(miniSfm,
184+
tracksMap,
185+
tracksPerView,
186+
randomNumberGenerator,
187+
pair.next,
188+
pose, newThreshold, inliersCount))
189+
{
190+
continue;
191+
}
192+
193+
pair.pose = geometry::Pose3(pose);
194+
pair.score = inliersCount;
195+
196+
if (inliersCount > maxInliers)
197+
{
198+
maxInliers = inliersCount;
199+
bestPairLocal = pair;
200+
}
201+
202+
totalInliers += inliersCount;
203+
}
204+
205+
if (totalInliers > bestCount)
206+
{
207+
bestPair = bestPairLocal;
208+
bestCount = totalInliers;
209+
}
210+
}
211+
212+
213+
return bestPair;
214+
}
215+
119216
}
120217
}

src/aliceVision/sfm/pipeline/bootstrapping/PairsScoring.hpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,18 @@ IndexT findBestPair(const sfmData::SfMData & sfmData,
3737
double softMinAngle,
3838
double maxAngle);
3939

40+
/**
41+
* @brief Get best pair from track Depths with highest score
42+
* @param sfmData the input sfmData which contains camera information
43+
* @param pairs the input list of reconstructed pairs
44+
* @param tracksMap the input map of tracks
45+
* @param tracksPerView tracks grouped by views
46+
* @return The best pair (pair.reference is UndefinedIndexT if nothing found)
47+
*/
48+
sfm::ReconstructedPair findBestPairFromTrackDepths(const sfmData::SfMData & sfmData,
49+
const std::vector<sfm::ReconstructedPair> & pairs,
50+
const track::TracksMap& tracksMap,
51+
const track::TracksPerView & tracksPerView);
52+
4053
}
4154
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// This file is part of the AliceVision project.
2+
// Copyright (c) 2025 AliceVision contributors.
3+
// This Source Code Form is subject to the terms of the Mozilla Public License,
4+
// v. 2.0. If a copy of the MPL was not distributed with this file,
5+
// You can obtain one at https://mozilla.org/MPL/2.0/.
6+
7+
#include <aliceVision/sfm/pipeline/bootstrapping/TracksDepths.hpp>
8+
9+
namespace aliceVision {
10+
namespace sfm {
11+
12+
bool buildSfmDataFromDepthMap(sfmData::SfMData & output,
13+
const sfmData::SfMData & sfmData,
14+
const track::TracksMap& tracksMap,
15+
const track::TracksPerView & tracksPerView,
16+
IndexT viewId)
17+
{
18+
output.clear();
19+
20+
const sfmData::View & view = sfmData.getView(viewId);
21+
const camera::IntrinsicBase & intrinsic = sfmData.getIntrinsic(view.getIntrinsicId());
22+
23+
if (tracksPerView.find(viewId) == tracksPerView.end())
24+
{
25+
return false;
26+
}
27+
28+
sfmData::Landmarks & landmarks = output.getLandmarks();
29+
30+
//Copy all intrinsics, because it's light.
31+
for (const auto & [intrinsicId, intrinsic] : sfmData.getIntrinsics())
32+
{
33+
output.getIntrinsics().insert(
34+
std::make_pair(intrinsicId,
35+
camera::IntrinsicBase::sptr(intrinsic->clone()))
36+
);
37+
}
38+
39+
std::set<IndexT> usedViewIds;
40+
const auto & trackIds = tracksPerView.at(viewId);
41+
for (const auto & trackId : trackIds)
42+
{
43+
const auto & track = tracksMap.at(trackId);
44+
const auto & feat = track.featPerView.at(viewId);
45+
const double & iZ = feat.idepth;
46+
47+
if (iZ < 0.0)
48+
{
49+
continue;
50+
}
51+
52+
const double Z = 1.0 / iZ;
53+
54+
const Vec2 meters = intrinsic.removeDistortion(intrinsic.ima2cam(feat.coords.cast<double>()));
55+
56+
sfmData::Landmark & landmark = landmarks[trackId];
57+
landmark.X.x() = meters.x() * Z;
58+
landmark.X.y() = meters.y() * Z;
59+
landmark.X.z() = Z;
60+
61+
landmark.descType = track.descType;
62+
63+
sfmData::Observations & observations = landmark.getObservations();
64+
for (const auto & [otherViewId, otherFeat] : track.featPerView)
65+
{
66+
usedViewIds.insert(otherViewId);
67+
}
68+
}
69+
70+
// Copy only used views
71+
for (const auto & usedViewId : usedViewIds)
72+
{
73+
const auto & iview = sfmData.getViewSharedPtr(usedViewId);
74+
75+
output.getViews().insert(
76+
std::make_pair(usedViewId,
77+
sfmData::View::sptr(iview->clone()))
78+
);
79+
}
80+
81+
return true;
82+
}
83+
84+
}
85+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// This file is part of the AliceVision project.
2+
// Copyright (c) 2025 AliceVision contributors.
3+
// This Source Code Form is subject to the terms of the Mozilla Public License,
4+
// v. 2.0. If a copy of the MPL was not distributed with this file,
5+
// You can obtain one at https://mozilla.org/MPL/2.0/.
6+
#pragma once
7+
8+
#include <aliceVision/track/Track.hpp>
9+
#include <aliceVision/sfmData/SfMData.hpp>
10+
11+
namespace aliceVision {
12+
namespace sfm {
13+
14+
/**
15+
* @brief Create a new sfmData cleared from any existing landmarks and poses
16+
* But with new landmarks created from tracks if depth exists
17+
* @param output the result sfmData
18+
* @param sfmData the input sfmData, used for views and intrinsics
19+
* @param tracksMap the input map of tracks
20+
* @param tracksPerView tracks grouped by views
21+
* @param viewId the view of interest identifier
22+
* @return false if an error occured
23+
*/
24+
bool buildSfmDataFromDepthMap(sfmData::SfMData & output,
25+
const sfmData::SfMData & sfmData,
26+
const track::TracksMap& tracksMap,
27+
const track::TracksPerView & tracksPerView,
28+
IndexT viewId);
29+
}
30+
}

0 commit comments

Comments
 (0)