Skip to content

Commit

Permalink
[feature] SfM: add scale as an option in SfM command line
Browse files Browse the repository at this point in the history
  • Loading branch information
Theo committed Feb 5, 2020
1 parent 568d2a9 commit c08f9a5
Show file tree
Hide file tree
Showing 12 changed files with 90 additions and 18 deletions.
3 changes: 2 additions & 1 deletion src/aliceVision/feature/cctag/ImageDescriber_CCTAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,8 @@ bool ImageDescriber_CCTAG::describe(const image::Image<unsigned char>& image,
}
desc[cctag.id()] = (unsigned char) 255;
regionsCasted->Descriptors().push_back(desc);
regionsCasted->Features().push_back(PointFeature(cctag.x(), cctag.y(), cctag.scale(), orientation)); // TODO: scale factor
const float scale = std::max(cctag.outerEllipse().a(), cctag.outerEllipse().b());
regionsCasted->Features().push_back(PointFeature(cctag.x(), cctag.y(), scale, orientation));
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/aliceVision/robustEstimation/estimators.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ inline std::ostream& operator<<(std::ostream& os, ERobustEstimator e)
return os << ERobustEstimator_enumToString(e);
}

inline std::istream& operator>>(std::istream& in, robustEstimation::ERobustEstimator& estimatorType)
inline std::istream& operator>>(std::istream& in, ERobustEstimator& estimatorType)
{
std::string token;
in >> token;
Expand Down
55 changes: 55 additions & 0 deletions src/aliceVision/sfm/BundleAdjustment.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@
#pragma once

#include <boost/detail/bitmask.hpp>
#include <string>
#include <algorithm>
#include <stdexcept>

namespace aliceVision {

Expand All @@ -17,6 +20,58 @@ class SfMData;

namespace sfm {

/**
* @brief Defines basic, scale and covariance options for features that can be used in a bundle adjustment.
*/
enum class EFeatureConstraint
{
BASIC = 0,
SCALE = 1
};

/**
*@brief convert an enum ESfMobservationConstraint to its corresponding string
*
*/
inline std::string ESfMobservationConstraint_enumToString(EFeatureConstraint m)
{
switch(m)
{
case EFeatureConstraint::BASIC: return "Basic";
case EFeatureConstraint::SCALE: return "Scale";
}
throw std::out_of_range("Invalid ESfMobservationConstraint enum: " + std::to_string(int(m)));
}

/**
* @brief convert a string featureConstraint to its corresponding enum featureConstraint
* @param String
* @return ESfMobservationConstraint
*/
inline EFeatureConstraint ESfMobservationConstraint_stringToEnum(const std::string& m)
{
std::string featureConstraint = m;
std::transform(featureConstraint.begin(), featureConstraint.end(), featureConstraint.begin(), ::tolower);

if(featureConstraint == "basic") return EFeatureConstraint::BASIC;
if(featureConstraint == "scale") return EFeatureConstraint::SCALE;

throw std::out_of_range("Invalid ESfMobservationConstraint: " + m);
}

inline std::ostream& operator<<(std::ostream& os, EFeatureConstraint m)
{
return os << ESfMobservationConstraint_enumToString(m);
}

inline std::istream& operator>>(std::istream& in, EFeatureConstraint& m)
{
std::string token;
in >> token;
m = ESfMobservationConstraint_stringToEnum(token);
return in;
}

class BundleAdjustment
{
public:
Expand Down
3 changes: 3 additions & 0 deletions src/aliceVision/sfm/BundleAdjustmentCeres.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,9 @@ class BundleAdjustmentCeres : public BundleAdjustment
/// user Ceres options to use in the solver
CeresOptions _ceresOptions;

/// user FeatureConstraint options to use
EFeatureConstraint _featureConstraint;

/// last adjustment iteration statisics
Statistics _statistics;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,7 @@ bool ReconstructionEngine_globalSfM::Compute_Initial_Structure(matching::Pairwis
bool ReconstructionEngine_globalSfM::Adjust()
{
// refine sfm scene (in a 3 iteration process (free the parameters regarding their incertainty order)):
BundleAdjustmentCeres::CeresOptions options;
BundleAdjustmentCeres::CeresOptions options;
options.useParametersOrdering = false; // disable parameters ordering

BundleAdjustmentCeres BA(options);
Expand Down Expand Up @@ -389,7 +389,7 @@ bool ReconstructionEngine_globalSfM::Adjust()

// Remove outliers (max_angle, residual error)
const size_t pointcount_initial = _sfmData.structure.size();
RemoveOutliers_PixelResidualError(_sfmData, 4.0);
RemoveOutliers_PixelResidualError(_sfmData, _featureConstraint, 4.0);
const size_t pointcount_pixelresidual_filter = _sfmData.structure.size();
RemoveOutliers_AngleError(_sfmData, 2.0);
const size_t pointcount_angular_filter = _sfmData.structure.size();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ class ReconstructionEngine_globalSfM : public ReconstructionEngine
ERotationAveragingMethod _eRotationAveragingMethod;
ETranslationAveragingMethod _eTranslationAveragingMethod;
bool _lockAllIntrinsics = false;
EFeatureConstraint _featureConstraint = EFeatureConstraint::BASIC;

// Data provider
feature::FeaturesPerView* _featuresPerView;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -689,7 +689,7 @@ bool ReconstructionEngine_sequentialSfM::bundleAdjustment(std::set<IndexT>& newR
statistics.show();
}

nbOutliers = removeOutliers(_params.maxReprojectionError);
nbOutliers = removeOutliers();

std::set<IndexT> removedViewsIdIteration;
eraseUnstablePosesAndObservations(this->_sfmData, _params.minPointsPerPose, _params.minTrackLength, &removedViewsIdIteration);
Expand Down Expand Up @@ -2054,9 +2054,9 @@ void ReconstructionEngine_sequentialSfM::triangulate_2Views(SfMData& scene, cons
}
}

std::size_t ReconstructionEngine_sequentialSfM::removeOutliers(double precision)
std::size_t ReconstructionEngine_sequentialSfM::removeOutliers()
{
const std::size_t nbOutliersResidualErr = RemoveOutliers_PixelResidualError(_sfmData, precision, 2);
const std::size_t nbOutliersResidualErr = RemoveOutliers_PixelResidualError(_sfmData, _params.featureConstraint, _params.maxReprojectionError, 2);
const std::size_t nbOutliersAngleErr = RemoveOutliers_AngleError(_sfmData, _params.minAngleForLandmark);

ALICEVISION_LOG_INFO("Remove outliers: " << std::endl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class ReconstructionEngine_sequentialSfM : public ReconstructionEngine
double minAngleForTriangulation = 3.0;
double minAngleForLandmark = 2.0;
double maxReprojectionError = 4.0;
EFeatureConstraint featureConstraint = EFeatureConstraint::BASIC;
float minAngleInitialPair = 5.0f;
float maxAngleInitialPair = 40.0f;
bool filterTrackForks = true;
Expand Down Expand Up @@ -355,7 +356,7 @@ class ReconstructionEngine_sequentialSfM : public ReconstructionEngine
* @param[in] precision
* @return number of removed outliers
*/
std::size_t removeOutliers(double precision);
std::size_t removeOutliers();

private:

Expand Down
5 changes: 4 additions & 1 deletion src/aliceVision/sfm/sfmFilters.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,19 +9,22 @@
#include <aliceVision/sfmData/SfMData.hpp>
#include <aliceVision/stl/stl.hpp>
#include <aliceVision/system/Logger.hpp>
#include <aliceVision/sfm/BundleAdjustment.hpp>

#include <iterator>

namespace aliceVision {
namespace sfm {

IndexT RemoveOutliers_PixelResidualError(sfmData::SfMData& sfmData,
EFeatureConstraint featureConstraint,
const double dThresholdPixel,
const unsigned int minTrackLength)
{
IndexT outlier_count = 0;
sfmData::Landmarks::iterator iterTracks = sfmData.structure.begin();


while(iterTracks != sfmData.structure.end())
{
sfmData::Observations & observations = iterTracks->second.observations;
Expand All @@ -34,7 +37,7 @@ IndexT RemoveOutliers_PixelResidualError(sfmData::SfMData& sfmData,
const camera::IntrinsicBase * intrinsic = sfmData.intrinsics.at(view->getIntrinsicId()).get();

Vec2 residual = intrinsic->residual(pose, iterTracks->second.X, itObs->second.x);
if(itObs->second.scale > 0) // TODO-SCALE: add an option to use the scale optionally
if(featureConstraint == EFeatureConstraint::SCALE)
{
// Apply the scale of the feature to get a residual value
// relative to the feature precision.
Expand Down
2 changes: 2 additions & 0 deletions src/aliceVision/sfm/sfmFilters.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#pragma once

#include <aliceVision/types.hpp>
#include <aliceVision/sfm/BundleAdjustment.hpp>

namespace aliceVision {

Expand All @@ -33,6 +34,7 @@ inline PairSet Pair_filter(const IterablePairs& pairs, const IterableIndex& inde
/// Remove observations with too large reprojection error.
/// Return the number of removed tracks.
IndexT RemoveOutliers_PixelResidualError(sfmData::SfMData& sfmData,
EFeatureConstraint featureConstraint,
const double dThresholdPixel,
const unsigned int minTrackLength = 2);

Expand Down
5 changes: 3 additions & 2 deletions src/software/pipeline/main_imageMatching.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -681,15 +681,16 @@ int main(int argc, char** argv)
// load SfMData
sfmData::SfMData sfmDataA, sfmDataB;

if(!sfmDataIO::Load(sfmDataA, sfmDataFilenameA, sfmDataIO::ESfMData::ALL))
using namespace sfmDataIO;
if(!sfmDataIO::Load(sfmDataA, sfmDataFilenameA, ESfMData(ESfMData::VIEWS|ESfMData::EXTRINSICS|ESfMData::INTRINSICS)))
{
ALICEVISION_LOG_ERROR("The input SfMData file '" + sfmDataFilenameA + "' cannot be read.");
return EXIT_FAILURE;
}

if(useMultiSfM)
{
if(!sfmDataIO::Load(sfmDataB, sfmDataFilenameB, sfmDataIO::ESfMData::ALL))
if(!sfmDataIO::Load(sfmDataB, sfmDataFilenameB, ESfMData(ESfMData::VIEWS|ESfMData::EXTRINSICS|ESfMData::INTRINSICS)))
{
ALICEVISION_LOG_ERROR("The input SfMData file '" + sfmDataFilenameB + "' cannot be read.");
return EXIT_FAILURE;
Expand Down
19 changes: 12 additions & 7 deletions src/software/pipeline/main_incrementalSfM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include <aliceVision/types.hpp>
#include <aliceVision/config.hpp>
#include <aliceVision/track/Track.hpp>
#include <aliceVision/sfm/BundleAdjustment.hpp>

#include <boost/program_options.hpp>
#include <boost/filesystem.hpp>
Expand All @@ -32,6 +33,8 @@ using namespace aliceVision;
namespace po = boost::program_options;
namespace fs = boost::filesystem;
using namespace aliceVision::track;
using namespace aliceVision::sfm;


/**
* @brief Retrieve the view id in the sfmData from the image filename.
Expand Down Expand Up @@ -78,7 +81,7 @@ int main(int argc, char **argv)
std::string outputSfM;

// user optional parameters

// user optional parameters
std::string outputSfMViewsAndPoses;
std::string extraInfoFolder;
std::string describerTypesName = feature::EImageDescriberType_enumToString(feature::EImageDescriberType::SIFT);
Expand All @@ -100,14 +103,14 @@ int main(int argc, char **argv)
("input,i", po::value<std::string>(&sfmDataFilename)->required(),
"SfMData file.")
("output,o", po::value<std::string>(&outputSfM)->required(),
"Path to the output SfMData file.")
("featuresFolders,f", po::value<std::vector<std::string>>(&featuresFolders)->multitoken()->required(),
"Path to folder(s) containing the extracted features.")
("matchesFolders,m", po::value<std::vector<std::string>>(&matchesFolders)->multitoken()->required(),
"Path to folder(s) in which computed matches are stored.");
"Path to the output SfMData file.");

po::options_description optionalParams("Optional parameters");
optionalParams.add_options()
("featuresFolders,f", po::value<std::vector<std::string>>(&featuresFolders)->multitoken()->required(),
"Path to folder(s) containing the extracted features.")
("matchesFolders,m", po::value<std::vector<std::string>>(&matchesFolders)->multitoken()->required(),
"Path to folder(s) in which computed matches are stored.")
("outputViewsAndPoses", po::value<std::string>(&outputSfMViewsAndPoses)->default_value(outputSfMViewsAndPoses),
"Path to the output SfMData file (with only views and poses).")
("extraInfoFolder", po::value<std::string>(&extraInfoFolder)->default_value(extraInfoFolder),
Expand Down Expand Up @@ -163,7 +166,9 @@ int main(int argc, char **argv)
("useRigConstraint", po::value<bool>(&sfmParams.useRigConstraint)->default_value(sfmParams.useRigConstraint),
"Enable/Disable rig constraint.\n")
("lockScenePreviouslyReconstructed", po::value<bool>(&lockScenePreviouslyReconstructed)->default_value(lockScenePreviouslyReconstructed),
"Lock/Unlock scene previously reconstructed.\n");
"Lock/Unlock scene previously reconstructed.\n")
("observationConstraint", po::value<EFeatureConstraint>(&sfmParams.featureConstraint)->default_value(sfmParams.featureConstraint),
"Use of an observation constraint : basic, scale the observation or use of the covariance.\n");

po::options_description logParams("Log parameters");
logParams.add_options()
Expand Down

0 comments on commit c08f9a5

Please sign in to comment.