Skip to content

Commit 5141d75

Browse files
almaroukcbentejac
authored andcommitted
[incrementalSfM] add option to enable/disable track merging based on duplicate features
1 parent fdd68ed commit 5141d75

File tree

3 files changed

+126
-90
lines changed

3 files changed

+126
-90
lines changed

src/aliceVision/sfm/pipeline/sequential/ReconstructionEngine_sequentialSfM.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,10 @@ std::size_t ReconstructionEngine_sequentialSfM::fuseMatchesIntoTracks()
246246
const aliceVision::matching::PairwiseMatches& matches = *_pairwiseMatches;
247247

248248
ALICEVISION_LOG_DEBUG("Track building");
249-
tracksBuilder.build(matches, _featuresPerView->getData());
249+
if (_params.mergeTracks)
250+
tracksBuilder.build(matches, _featuresPerView->getData());
251+
else
252+
tracksBuilder.build(matches);
250253

251254
ALICEVISION_LOG_DEBUG("Track filtering");
252255
tracksBuilder.filter(_params.filterTrackForks, _params.minInputTrackLength);

src/aliceVision/sfm/pipeline/sequential/ReconstructionEngine_sequentialSfM.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ class ReconstructionEngine_sequentialSfM : public ReconstructionEngine
6363
EFeatureConstraint featureConstraint = EFeatureConstraint::BASIC;
6464
float minAngleInitialPair = 5.0f;
6565
float maxAngleInitialPair = 40.0f;
66+
bool mergeTracks = false;
6667
bool filterTrackForks = true;
6768
robustEstimation::ERobustEstimator localizerEstimator = robustEstimation::ERobustEstimator::ACRANSAC;
6869
double localizerEstimatorError = std::numeric_limits<double>::infinity();

src/software/pipeline/main_incrementalSfM.cpp

+121-89
Original file line numberDiff line numberDiff line change
@@ -105,95 +105,127 @@ int aliceVision_main(int argc, char **argv)
105105
"Path to the output SfMData file.");
106106

107107
po::options_description optionalParams("Optional parameters");
108-
optionalParams.add_options()
109-
("featuresFolders,f", po::value<std::vector<std::string>>(&featuresFolders)->multitoken(),
110-
"Path to folder(s) containing the extracted features.")
111-
("matchesFolders,m", po::value<std::vector<std::string>>(&matchesFolders)->multitoken(),
112-
"Path to folder(s) in which computed matches are stored.")
113-
("outputViewsAndPoses", po::value<std::string>(&outputSfMViewsAndPoses)->default_value(outputSfMViewsAndPoses),
114-
"Path to the output SfMData file (with only views and poses).")
115-
("extraInfoFolder", po::value<std::string>(&extraInfoFolder)->default_value(extraInfoFolder),
116-
"Folder for intermediate reconstruction files and additional reconstruction information files.")
117-
("describerTypes,d", po::value<std::string>(&describerTypesName)->default_value(describerTypesName),
118-
feature::EImageDescriberType_informations().c_str())
119-
("interFileExtension", po::value<std::string>(&sfmParams.sfmStepFileExtension)->default_value(sfmParams.sfmStepFileExtension),
120-
"Extension of the intermediate file export.")
121-
("maxNumberOfMatches", po::value<int>(&maxNbMatches)->default_value(maxNbMatches),
122-
"Maximum number of matches per image pair (and per feature type). "
123-
"This can be useful to have a quick reconstruction overview. 0 means no limit.")
124-
("minNumberOfMatches", po::value<int>(&minNbMatches)->default_value(minNbMatches),
125-
"Minimum number of matches per image pair (and per feature type). "
126-
"This can be useful to have a meaningful reconstruction with accurate keypoints. 0 means no limit.")
127-
("minInputTrackLength", po::value<int>(&sfmParams.minInputTrackLength)->default_value(sfmParams.minInputTrackLength),
128-
"Minimum track length in input of SfM.")
129-
("minAngleForTriangulation", po::value<double>(&sfmParams.minAngleForTriangulation)->default_value(sfmParams.minAngleForTriangulation),
130-
"Minimum angle for triangulation.")
131-
("minAngleForLandmark", po::value<double>(&sfmParams.minAngleForLandmark)->default_value(sfmParams.minAngleForLandmark),
132-
"Minimum angle for landmark.")
133-
("maxReprojectionError", po::value<double>(&sfmParams.maxReprojectionError)->default_value(sfmParams.maxReprojectionError),
134-
"Maximum reprojection error.")
135-
("minAngleInitialPair", po::value<float>(&sfmParams.minAngleInitialPair)->default_value(sfmParams.minAngleInitialPair),
136-
"Minimum angle for the initial pair.")
137-
("maxAngleInitialPair", po::value<float>(&sfmParams.maxAngleInitialPair)->default_value(sfmParams.maxAngleInitialPair),
138-
"Maximum angle for the initial pair.")
139-
("minNumberOfObservationsForTriangulation", po::value<std::size_t>(&sfmParams.minNbObservationsForTriangulation)->default_value(sfmParams.minNbObservationsForTriangulation),
140-
"Minimum number of observations to triangulate a point.\n"
141-
"Set it to 3 (or more) reduces drastically the noise in the point cloud, but the number of final poses is a little bit reduced (from 1.5% to 11% on the tested datasets).\n"
142-
"Note: set it to 0 or 1 to use the old triangulation algorithm (using 2 views only) during resection.")
143-
("initialPairA", po::value<std::string>(&initialPairString.first)->default_value(initialPairString.first),
144-
"UID or filepath or filename of the first image.")
145-
("initialPairB", po::value<std::string>(&initialPairString.second)->default_value(initialPairString.second),
146-
"UID or filepath or filename of the second image.")
147-
("lockAllIntrinsics", po::value<bool>(&sfmParams.lockAllIntrinsics)->default_value(sfmParams.lockAllIntrinsics),
148-
"Force lock of all camera intrinsic parameters, so they will not be refined during Bundle Adjustment.")
149-
("minNbCamerasToRefinePrincipalPoint", po::value<int>(&sfmParams.minNbCamerasToRefinePrincipalPoint)->default_value(sfmParams.minNbCamerasToRefinePrincipalPoint),
150-
"Minimal number of cameras to refine the principal point of the cameras (one of the intrinsic parameters of the camera). "
151-
"If we do not have enough cameras, the principal point in consider is considered in the center of the image. "
152-
"If minNbCamerasToRefinePrincipalPoint<=0, the principal point is never refined. "
153-
"If minNbCamerasToRefinePrincipalPoint==1, the principal point is always refined.")
154-
("useLocalBA,l", po::value<bool>(&sfmParams.useLocalBundleAdjustment)->default_value(sfmParams.useLocalBundleAdjustment),
155-
"Enable/Disable the Local bundle adjustment strategy.\n"
156-
"It reduces the reconstruction time, especially for big datasets (500+ images).")
157-
("localBAGraphDistance", po::value<int>(&sfmParams.localBundelAdjustementGraphDistanceLimit)->default_value(sfmParams.localBundelAdjustementGraphDistanceLimit),
158-
"Graph-distance limit setting the Active region in the Local Bundle Adjustment strategy.")
159-
("nbFirstUnstableCameras", po::value<std::size_t>(&sfmParams.nbFirstUnstableCameras)->default_value(sfmParams.nbFirstUnstableCameras),
160-
"Number of cameras for which the bundle adjustment is performed every single time a camera is added, leading to more stable "
161-
"results while the computations are not too expensive since there is not much data. Past this number, the bundle adjustment "
162-
"will only be performed once for N added cameras.")
163-
("maxImagesPerGroup", po::value<std::size_t>(&sfmParams.maxImagesPerGroup)->default_value(sfmParams.maxImagesPerGroup),
164-
"Maximum number of cameras that can be added before the bundle adjustment is performed. This prevents adding too much data "
165-
"at once without performing the bundle adjustment.")
166-
("bundleAdjustmentMaxOutliers", po::value<int>(&sfmParams.bundleAdjustmentMaxOutliers)->default_value(sfmParams.bundleAdjustmentMaxOutliers),
167-
"Threshold for the maximum number of outliers allowed at the end of a bundle adjustment iteration."
168-
"Using a negative value for this threshold will disable BA iterations.")
169-
("localizerEstimator", po::value<robustEstimation::ERobustEstimator>(&sfmParams.localizerEstimator)->default_value(sfmParams.localizerEstimator),
170-
"Estimator type used to localize cameras (acransac (default), ransac, lsmeds, loransac, maxconsensus)")
171-
("localizerEstimatorError", po::value<double>(&sfmParams.localizerEstimatorError)->default_value(0.0),
172-
"Reprojection error threshold (in pixels) for the localizer estimator (0 for default value according to the estimator).")
173-
("localizerEstimatorMaxIterations", po::value<std::size_t>(&sfmParams.localizerEstimatorMaxIterations)->default_value(sfmParams.localizerEstimatorMaxIterations),
174-
"Max number of RANSAC iterations.")
175-
("useOnlyMatchesFromInputFolder", po::value<bool>(&useOnlyMatchesFromInputFolder)->default_value(useOnlyMatchesFromInputFolder),
176-
"Use only matches from the input matchesFolder parameter.\n"
177-
"Matches folders previously added to the SfMData file will be ignored.")
178-
("filterTrackForks", po::value<bool>(&sfmParams.filterTrackForks)->default_value(sfmParams.filterTrackForks),
179-
"Enable/Disable the track forks removal. A track contains a fork when incoherent matches leads to multiple features in the same image for a single track.\n")
180-
("useRigConstraint", po::value<bool>(&sfmParams.rig.useRigConstraint)->default_value(sfmParams.rig.useRigConstraint),
181-
"Enable/Disable rig constraint.\n")
182-
("rigMinNbCamerasForCalibration", po::value<int>(&sfmParams.rig.minNbCamerasForCalibration)->default_value(sfmParams.rig.minNbCamerasForCalibration),
183-
"Minimal number of cameras to start the calibration of the rig.\n")
184-
("lockScenePreviouslyReconstructed", po::value<bool>(&lockScenePreviouslyReconstructed)->default_value(lockScenePreviouslyReconstructed),
185-
"Lock/Unlock scene previously reconstructed.\n")
186-
("observationConstraint", po::value<EFeatureConstraint>(&sfmParams.featureConstraint)->default_value(sfmParams.featureConstraint),
187-
"Use of an observation constraint : basic, scale the observation or use of the covariance.\n")
188-
("computeStructureColor", po::value<bool>(&computeStructureColor)->default_value(computeStructureColor),
189-
"Compute each 3D point color.\n")
190-
("useAutoTransform", po::value<bool>(&useAutoTransform)->default_value(useAutoTransform),
191-
"Transform the result with the alignment method 'AUTO'.\n")
192-
("randomSeed", po::value<int>(&randomSeed)->default_value(randomSeed),
193-
"This seed value will generate a sequence using a linear random generator. Set -1 to use a random seed.")
194-
("logIntermediateSteps", po::value<bool>(&sfmParams.logIntermediateSteps)->default_value(logIntermediateSteps),
195-
"If set to true, the current state of the scene will be dumped as an SfMData file every 3 resections.")
196-
;
108+
optionalParams.add_options()(
109+
"featuresFolders,f", po::value<std::vector<std::string>>(&featuresFolders)->multitoken(), "Path to folder(s) containing the extracted features.")(
110+
"matchesFolders,m",
111+
po::value<std::vector<std::string>>(&matchesFolders)->multitoken(),
112+
"Path to folder(s) in which computed matches are stored.")("outputViewsAndPoses",
113+
po::value<std::string>(&outputSfMViewsAndPoses)->default_value(outputSfMViewsAndPoses),
114+
"Path to the output SfMData file (with only views and poses).")(
115+
"extraInfoFolder",
116+
po::value<std::string>(&extraInfoFolder)->default_value(extraInfoFolder),
117+
"Folder for intermediate reconstruction files and additional reconstruction information files.")(
118+
"describerTypes,d",
119+
po::value<std::string>(&describerTypesName)->default_value(describerTypesName),
120+
feature::EImageDescriberType_informations().c_str())(
121+
"interFileExtension",
122+
po::value<std::string>(&sfmParams.sfmStepFileExtension)->default_value(sfmParams.sfmStepFileExtension),
123+
"Extension of the intermediate file export.")("maxNumberOfMatches",
124+
po::value<int>(&maxNbMatches)->default_value(maxNbMatches),
125+
"Maximum number of matches per image pair (and per feature type). "
126+
"This can be useful to have a quick reconstruction overview. 0 means no limit.")(
127+
"minNumberOfMatches",
128+
po::value<int>(&minNbMatches)->default_value(minNbMatches),
129+
"Minimum number of matches per image pair (and per feature type). "
130+
"This can be useful to have a meaningful reconstruction with accurate keypoints. 0 means no limit.")(
131+
"minInputTrackLength",
132+
po::value<int>(&sfmParams.minInputTrackLength)->default_value(sfmParams.minInputTrackLength),
133+
"Minimum track length in input of SfM.")(
134+
"minAngleForTriangulation",
135+
po::value<double>(&sfmParams.minAngleForTriangulation)->default_value(sfmParams.minAngleForTriangulation),
136+
"Minimum angle for triangulation.")("minAngleForLandmark",
137+
po::value<double>(&sfmParams.minAngleForLandmark)->default_value(sfmParams.minAngleForLandmark),
138+
"Minimum angle for landmark.")(
139+
"maxReprojectionError",
140+
po::value<double>(&sfmParams.maxReprojectionError)->default_value(sfmParams.maxReprojectionError),
141+
"Maximum reprojection error.")("minAngleInitialPair",
142+
po::value<float>(&sfmParams.minAngleInitialPair)->default_value(sfmParams.minAngleInitialPair),
143+
"Minimum angle for the initial pair.")(
144+
"maxAngleInitialPair",
145+
po::value<float>(&sfmParams.maxAngleInitialPair)->default_value(sfmParams.maxAngleInitialPair),
146+
"Maximum angle for the initial pair.")(
147+
"minNumberOfObservationsForTriangulation",
148+
po::value<std::size_t>(&sfmParams.minNbObservationsForTriangulation)->default_value(sfmParams.minNbObservationsForTriangulation),
149+
"Minimum number of observations to triangulate a point.\n"
150+
"Set it to 3 (or more) reduces drastically the noise in the point cloud, but the number of final poses is a little bit reduced (from 1.5% to 11% "
151+
"on the tested datasets).\n"
152+
"Note: set it to 0 or 1 to use the old triangulation algorithm (using 2 views only) during resection.")(
153+
"initialPairA",
154+
po::value<std::string>(&initialPairString.first)->default_value(initialPairString.first),
155+
"UID or filepath or filename of the first image.")("initialPairB",
156+
po::value<std::string>(&initialPairString.second)->default_value(initialPairString.second),
157+
"UID or filepath or filename of the second image.")(
158+
"lockAllIntrinsics",
159+
po::value<bool>(&sfmParams.lockAllIntrinsics)->default_value(sfmParams.lockAllIntrinsics),
160+
"Force lock of all camera intrinsic parameters, so they will not be refined during Bundle Adjustment.")(
161+
"minNbCamerasToRefinePrincipalPoint",
162+
po::value<int>(&sfmParams.minNbCamerasToRefinePrincipalPoint)->default_value(sfmParams.minNbCamerasToRefinePrincipalPoint),
163+
"Minimal number of cameras to refine the principal point of the cameras (one of the intrinsic parameters of the camera). "
164+
"If we do not have enough cameras, the principal point in consider is considered in the center of the image. "
165+
"If minNbCamerasToRefinePrincipalPoint<=0, the principal point is never refined. "
166+
"If minNbCamerasToRefinePrincipalPoint==1, the principal point is always refined.")(
167+
"useLocalBA,l",
168+
po::value<bool>(&sfmParams.useLocalBundleAdjustment)->default_value(sfmParams.useLocalBundleAdjustment),
169+
"Enable/Disable the Local bundle adjustment strategy.\n"
170+
"It reduces the reconstruction time, especially for big datasets (500+ images).")(
171+
"localBAGraphDistance",
172+
po::value<int>(&sfmParams.localBundelAdjustementGraphDistanceLimit)->default_value(sfmParams.localBundelAdjustementGraphDistanceLimit),
173+
"Graph-distance limit setting the Active region in the Local Bundle Adjustment strategy.")(
174+
"nbFirstUnstableCameras",
175+
po::value<std::size_t>(&sfmParams.nbFirstUnstableCameras)->default_value(sfmParams.nbFirstUnstableCameras),
176+
"Number of cameras for which the bundle adjustment is performed every single time a camera is added, leading to more stable "
177+
"results while the computations are not too expensive since there is not much data. Past this number, the bundle adjustment "
178+
"will only be performed once for N added cameras.")(
179+
"maxImagesPerGroup",
180+
po::value<std::size_t>(&sfmParams.maxImagesPerGroup)->default_value(sfmParams.maxImagesPerGroup),
181+
"Maximum number of cameras that can be added before the bundle adjustment is performed. This prevents adding too much data "
182+
"at once without performing the bundle adjustment.")(
183+
"bundleAdjustmentMaxOutliers",
184+
po::value<int>(&sfmParams.bundleAdjustmentMaxOutliers)->default_value(sfmParams.bundleAdjustmentMaxOutliers),
185+
"Threshold for the maximum number of outliers allowed at the end of a bundle adjustment iteration."
186+
"Using a negative value for this threshold will disable BA iterations.")(
187+
"localizerEstimator",
188+
po::value<robustEstimation::ERobustEstimator>(&sfmParams.localizerEstimator)->default_value(sfmParams.localizerEstimator),
189+
"Estimator type used to localize cameras (acransac (default), ransac, lsmeds, loransac, maxconsensus)")(
190+
"localizerEstimatorError",
191+
po::value<double>(&sfmParams.localizerEstimatorError)->default_value(0.0),
192+
"Reprojection error threshold (in pixels) for the localizer estimator (0 for default value according to the estimator).")(
193+
"localizerEstimatorMaxIterations",
194+
po::value<std::size_t>(&sfmParams.localizerEstimatorMaxIterations)->default_value(sfmParams.localizerEstimatorMaxIterations),
195+
"Max number of RANSAC iterations.")("useOnlyMatchesFromInputFolder",
196+
po::value<bool>(&useOnlyMatchesFromInputFolder)->default_value(useOnlyMatchesFromInputFolder),
197+
"Use only matches from the input matchesFolder parameter.\n"
198+
"Matches folders previously added to the SfMData file will be ignored.")(
199+
"mergeTracks",
200+
po::value<bool>(&sfmParams.mergeTracks)->default_value(sfmParams.mergeTracks),
201+
"Enable/Disable the track merging. The merging between two tracks is made when they have duplicate features coming from the same original "
202+
"feature "
203+
"(same describer type, same 2D position in the same view, same scale, but different rotations and different feature id).\n")(
204+
"filterTrackForks",
205+
po::value<bool>(&sfmParams.filterTrackForks)->default_value(sfmParams.filterTrackForks),
206+
"Enable/Disable the track forks removal. A track contains a fork when incoherent matches leads to multiple features in the same image for a "
207+
"single track.\n")("useRigConstraint",
208+
po::value<bool>(&sfmParams.rig.useRigConstraint)->default_value(sfmParams.rig.useRigConstraint),
209+
"Enable/Disable rig constraint.\n")(
210+
"rigMinNbCamerasForCalibration",
211+
po::value<int>(&sfmParams.rig.minNbCamerasForCalibration)->default_value(sfmParams.rig.minNbCamerasForCalibration),
212+
"Minimal number of cameras to start the calibration of the rig.\n")(
213+
"lockScenePreviouslyReconstructed",
214+
po::value<bool>(&lockScenePreviouslyReconstructed)->default_value(lockScenePreviouslyReconstructed),
215+
"Lock/Unlock scene previously reconstructed.\n")(
216+
"observationConstraint",
217+
po::value<EFeatureConstraint>(&sfmParams.featureConstraint)->default_value(sfmParams.featureConstraint),
218+
"Use of an observation constraint : basic, scale the observation or use of the covariance.\n")(
219+
"computeStructureColor", po::value<bool>(&computeStructureColor)->default_value(computeStructureColor), "Compute each 3D point color.\n")(
220+
"useAutoTransform",
221+
po::value<bool>(&useAutoTransform)->default_value(useAutoTransform),
222+
"Transform the result with the alignment method 'AUTO'.\n")(
223+
"randomSeed",
224+
po::value<int>(&randomSeed)->default_value(randomSeed),
225+
"This seed value will generate a sequence using a linear random generator. Set -1 to use a random seed.")(
226+
"logIntermediateSteps",
227+
po::value<bool>(&sfmParams.logIntermediateSteps)->default_value(logIntermediateSteps),
228+
"If set to true, the current state of the scene will be dumped as an SfMData file every 3 resections.");
197229

198230
CmdLine cmdline("Sequential/Incremental reconstruction.\n"
199231
"This program performs incremental SfM (Initial Pair Essential + Resection).\n"

0 commit comments

Comments
 (0)