diff --git a/src/aliceVision/feature/cctag/ImageDescriber_CCTAG.cpp b/src/aliceVision/feature/cctag/ImageDescriber_CCTAG.cpp index 155ad6b930..aa91d84658 100644 --- a/src/aliceVision/feature/cctag/ImageDescriber_CCTAG.cpp +++ b/src/aliceVision/feature/cctag/ImageDescriber_CCTAG.cpp @@ -143,7 +143,8 @@ bool ImageDescriber_CCTAG::describe(const image::Image& 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)); } } diff --git a/src/aliceVision/robustEstimation/estimators.hpp b/src/aliceVision/robustEstimation/estimators.hpp index 07f3cbd038..aecb1846c7 100644 --- a/src/aliceVision/robustEstimation/estimators.hpp +++ b/src/aliceVision/robustEstimation/estimators.hpp @@ -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; diff --git a/src/aliceVision/sfm/BundleAdjustment.hpp b/src/aliceVision/sfm/BundleAdjustment.hpp index 22566aa253..d802ff1524 100644 --- a/src/aliceVision/sfm/BundleAdjustment.hpp +++ b/src/aliceVision/sfm/BundleAdjustment.hpp @@ -8,6 +8,9 @@ #pragma once #include +#include +#include +#include namespace aliceVision { @@ -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: diff --git a/src/aliceVision/sfm/BundleAdjustmentCeres.hpp b/src/aliceVision/sfm/BundleAdjustmentCeres.hpp index 1708425e20..b8bab64c3c 100644 --- a/src/aliceVision/sfm/BundleAdjustmentCeres.hpp +++ b/src/aliceVision/sfm/BundleAdjustmentCeres.hpp @@ -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; diff --git a/src/aliceVision/sfm/pipeline/global/ReconstructionEngine_globalSfM.cpp b/src/aliceVision/sfm/pipeline/global/ReconstructionEngine_globalSfM.cpp index 38ae65a879..5f684d87f3 100644 --- a/src/aliceVision/sfm/pipeline/global/ReconstructionEngine_globalSfM.cpp +++ b/src/aliceVision/sfm/pipeline/global/ReconstructionEngine_globalSfM.cpp @@ -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); @@ -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(); diff --git a/src/aliceVision/sfm/pipeline/global/ReconstructionEngine_globalSfM.hpp b/src/aliceVision/sfm/pipeline/global/ReconstructionEngine_globalSfM.hpp index 95e2aa733c..2c30b00b88 100644 --- a/src/aliceVision/sfm/pipeline/global/ReconstructionEngine_globalSfM.hpp +++ b/src/aliceVision/sfm/pipeline/global/ReconstructionEngine_globalSfM.hpp @@ -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; diff --git a/src/aliceVision/sfm/pipeline/sequential/ReconstructionEngine_sequentialSfM.cpp b/src/aliceVision/sfm/pipeline/sequential/ReconstructionEngine_sequentialSfM.cpp index e16333255b..19326764c7 100644 --- a/src/aliceVision/sfm/pipeline/sequential/ReconstructionEngine_sequentialSfM.cpp +++ b/src/aliceVision/sfm/pipeline/sequential/ReconstructionEngine_sequentialSfM.cpp @@ -689,7 +689,7 @@ bool ReconstructionEngine_sequentialSfM::bundleAdjustment(std::set& newR statistics.show(); } - nbOutliers = removeOutliers(_params.maxReprojectionError); + nbOutliers = removeOutliers(); std::set removedViewsIdIteration; eraseUnstablePosesAndObservations(this->_sfmData, _params.minPointsPerPose, _params.minTrackLength, &removedViewsIdIteration); @@ -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 diff --git a/src/aliceVision/sfm/pipeline/sequential/ReconstructionEngine_sequentialSfM.hpp b/src/aliceVision/sfm/pipeline/sequential/ReconstructionEngine_sequentialSfM.hpp index 1fdc52e067..167bb8c464 100644 --- a/src/aliceVision/sfm/pipeline/sequential/ReconstructionEngine_sequentialSfM.hpp +++ b/src/aliceVision/sfm/pipeline/sequential/ReconstructionEngine_sequentialSfM.hpp @@ -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; @@ -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: diff --git a/src/aliceVision/sfm/sfmFilters.cpp b/src/aliceVision/sfm/sfmFilters.cpp index 84185b671f..c8dc84636f 100644 --- a/src/aliceVision/sfm/sfmFilters.cpp +++ b/src/aliceVision/sfm/sfmFilters.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include @@ -16,12 +17,14 @@ 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; @@ -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. diff --git a/src/aliceVision/sfm/sfmFilters.hpp b/src/aliceVision/sfm/sfmFilters.hpp index fdbb580fad..3434e19fbd 100644 --- a/src/aliceVision/sfm/sfmFilters.hpp +++ b/src/aliceVision/sfm/sfmFilters.hpp @@ -8,6 +8,7 @@ #pragma once #include +#include namespace aliceVision { @@ -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); diff --git a/src/software/pipeline/main_imageMatching.cpp b/src/software/pipeline/main_imageMatching.cpp index 0ea67b88f1..c911a777a9 100644 --- a/src/software/pipeline/main_imageMatching.cpp +++ b/src/software/pipeline/main_imageMatching.cpp @@ -681,7 +681,8 @@ 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; @@ -689,7 +690,7 @@ int main(int argc, char** argv) 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; diff --git a/src/software/pipeline/main_incrementalSfM.cpp b/src/software/pipeline/main_incrementalSfM.cpp index 452c6c0a97..1a916dff0a 100644 --- a/src/software/pipeline/main_incrementalSfM.cpp +++ b/src/software/pipeline/main_incrementalSfM.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -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. @@ -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); @@ -164,7 +167,9 @@ int main(int argc, char **argv) ("useRigConstraint", po::value(&sfmParams.useRigConstraint)->default_value(sfmParams.useRigConstraint), "Enable/Disable rig constraint.\n") ("lockScenePreviouslyReconstructed", po::value(&lockScenePreviouslyReconstructed)->default_value(lockScenePreviouslyReconstructed), - "Lock/Unlock scene previously reconstructed.\n"); + "Lock/Unlock scene previously reconstructed.\n") + ("observationConstraint", po::value(&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()