Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update sfmBootstraping parameters #1794

Merged
merged 2 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions src/aliceVision/sfmData/SfMData.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,27 @@ void SfMData::getBoundingBox(Eigen::Vector3d & bbMin, Eigen::Vector3d & bbMax)
}
}

IndexT SfMData::findView(const std::string & imageName) const
{
IndexT out_viewId = UndefinedIndexT;

// list views uid / filenames and find the one that correspond to the user ones
for (const auto& viewPair : getViews())
{
const auto & v = viewPair.second;

if (imageName == std::to_string(v->getViewId()) ||
imageName == fs::path(v->getImage().getImagePath()).filename().string() ||
imageName == v->getImage().getImagePath())
{
out_viewId = v->getViewId();
break;
}
}

return out_viewId;
}

LandmarksPerView getLandmarksPerViews(const SfMData& sfmData)
{
LandmarksPerView landmarksPerView;
Expand Down
7 changes: 7 additions & 0 deletions src/aliceVision/sfmData/SfMData.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,13 @@ class SfMData
*/
View::sptr getViewSharedPtr(IndexT viewId) { return _views.at(viewId); }

/**
* @brief Retrieve the view id in the sfmData from the image filename.
* @param[in] name the image name to find (uid or filename or path)
* @return a view Id if a view is found or UndefinedIndexT
*/
IndexT findView(const std::string & imageName) const;

/**
* @brief Gives the pose of the input view. If this view is part of a rig, it returns rigPose + rigSubPose.
* @param[in] view The given view
Expand Down
52 changes: 15 additions & 37 deletions src/software/pipeline/main_incrementalSfM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -38,35 +38,6 @@ namespace fs = std::filesystem;
using namespace aliceVision::track;
using namespace aliceVision::sfm;

/**
* @brief Retrieve the view id in the sfmData from the image filename.
* @param[in] sfmData the SfM scene
* @param[in] name the image name to find (uid or filename or path)
* @param[out] out_viewId the id found
* @return if a view is found
*/
bool retrieveViewIdFromImageName(const sfmData::SfMData& sfmData, const std::string& name, IndexT& out_viewId)
{
out_viewId = UndefinedIndexT;

// list views uid / filenames and find the one that correspond to the user ones
for (const auto& viewPair : sfmData.getViews())
{
const sfmData::View& v = *(viewPair.second.get());

if (name == std::to_string(v.getViewId()) || name == fs::path(v.getImage().getImagePath()).filename().string() ||
name == v.getImage().getImagePath())
{
out_viewId = v.getViewId();
break;
}
}

if (out_viewId == UndefinedIndexT)
ALICEVISION_LOG_ERROR("Can't find the given initial pair view: " << name);

return out_viewId != UndefinedIndexT;
}

int aliceVision_main(int argc, char** argv)
{
Expand Down Expand Up @@ -277,7 +248,6 @@ int aliceVision_main(int argc, char** argv)
// return EXIT_FAILURE;
}

// handle initial pair parameter
if (!initialPairString.first.empty() || !initialPairString.second.empty())
{
if (initialPairString.first == initialPairString.second)
Expand All @@ -286,20 +256,28 @@ int aliceVision_main(int argc, char** argv)
return EXIT_FAILURE;
}

if (!initialPairString.first.empty() && !retrieveViewIdFromImageName(sfmData, initialPairString.first, sfmParams.userInitialImagePair.first))
if (!initialPairString.first.empty())
{
ALICEVISION_LOG_ERROR("Could not find corresponding view in the initial pair: " + initialPairString.first);
return EXIT_FAILURE;
sfmParams.userInitialImagePair.first = sfmData.findView(initialPairString.first);
if (sfmParams.userInitialImagePair.first == UndefinedIndexT)
{
ALICEVISION_LOG_ERROR("Could not find corresponding view in the initial pair: " + initialPairString.first);
return EXIT_FAILURE;
}
}

if (!initialPairString.second.empty() &&
!retrieveViewIdFromImageName(sfmData, initialPairString.second, sfmParams.userInitialImagePair.second))
if (!initialPairString.second.empty())
{
ALICEVISION_LOG_ERROR("Could not find corresponding view in the initial pair: " + initialPairString.second);
return EXIT_FAILURE;
sfmParams.userInitialImagePair.second = sfmData.findView(initialPairString.second);
if (sfmParams.userInitialImagePair.second == UndefinedIndexT)
{
ALICEVISION_LOG_ERROR("Could not find corresponding view in the initial pair: " + initialPairString.second);
return EXIT_FAILURE;
}
}
}


sfm::ReconstructionEngine_sequentialSfM sfmEngine(sfmData, sfmParams, extraInfoFolder, (fs::path(extraInfoFolder) / "sfm_log.html").string());

sfmEngine.initRandomSeed(randomSeed);
Expand Down
75 changes: 73 additions & 2 deletions src/software/pipeline/main_sfmBootstraping.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -220,8 +220,10 @@

// user optional parameters
const double maxEpipolarDistance = 4.0;
const double minAngle = 5.0;
const double maxAngle = 40.0;
double minAngle = 5.0;
double maxAngle = 40.0;
std::pair<std::string, std::string> initialPairString("", "");
std::pair<IndexT, IndexT> initialPair(UndefinedIndexT, UndefinedIndexT);

int randomSeed = std::mt19937::default_seed;

Expand All @@ -232,130 +234,199 @@
("tracksFilename,t", po::value<std::string>(&tracksFilename)->required(), "Tracks file.")
("pairs,p", po::value<std::string>(&pairsDirectory)->required(), "Path to the pairs directory.");

po::options_description optionalParams("Required parameters");
optionalParams.add_options()
("minAngleInitialPair", po::value<double>(&minAngle)->default_value(minAngle), "Minimum angle for the initial pair.")
("maxAngleInitialPair", po::value<double>(&maxAngle)->default_value(maxAngle), "Maximum angle for the initial pair.")
("initialPairA", po::value<std::string>(&initialPairString.first)->default_value(initialPairString.first), "UID or filepath or filename of the first image.")
("initialPairB", po::value<std::string>(&initialPairString.second)->default_value(initialPairString.second), "UID or filepath or filename of the second image.");

CmdLine cmdline("AliceVision SfM Bootstraping");

cmdline.add(requiredParams);
cmdline.add(optionalParams);
if(!cmdline.execute(argc, argv))
{
return EXIT_FAILURE;
}

// set maxThreads
HardwareContext hwc = cmdline.getHardwareContext();
omp_set_num_threads(hwc.getMaxThreads());

// load input SfMData scene
sfmData::SfMData sfmData;
if(!sfmDataIO::load(sfmData, sfmDataFilename, sfmDataIO::ESfMData::ALL))
{
ALICEVISION_LOG_ERROR("The input SfMData file '" + sfmDataFilename + "' cannot be read.");
return EXIT_FAILURE;
}


if (sfmData.getValidViews().size() >= 2)
{
ALICEVISION_LOG_INFO("SfmData has already an initialization");
return EXIT_SUCCESS;
}

if (!initialPairString.first.empty() || !initialPairString.second.empty())
{
if (initialPairString.first == initialPairString.second)
{
ALICEVISION_LOG_ERROR("Invalid image names. You cannot use the same image to initialize a pair.");
return EXIT_FAILURE;
}

if (!initialPairString.first.empty())
{
initialPair.first = sfmData.findView(initialPairString.first);
if (initialPair.first == UndefinedIndexT)
{
ALICEVISION_LOG_ERROR("Could not find corresponding view in the initial pair: " + initialPairString.first);
return EXIT_FAILURE;
}
}

if (!initialPairString.second.empty())
{
initialPair.second = sfmData.findView(initialPairString.second);
if (initialPair.second == UndefinedIndexT)
{
ALICEVISION_LOG_ERROR("Could not find corresponding view in the initial pair: " + initialPairString.second);
return EXIT_FAILURE;
}
}
}

if (initialPair.first != UndefinedIndexT)
{
ALICEVISION_LOG_INFO("Force one of the selected view to be " << initialPair.first);
}

if (initialPair.second != UndefinedIndexT)
{
ALICEVISION_LOG_INFO("Force one of the selected view to be " << initialPair.second);
}

// Load tracks
ALICEVISION_LOG_INFO("Load tracks");
track::TracksHandler tracksHandler;
if (!tracksHandler.load(tracksFilename, sfmData.getViewsKeys()))
{
ALICEVISION_LOG_ERROR("The input tracks file '" + tracksFilename + "' cannot be read.");
return EXIT_FAILURE;
}


//Result of pair estimations are stored in multiple files
std::vector<sfm::ReconstructedPair> reconstructedPairs;
const std::regex regex("pairs\\_[0-9]+\\.json");
for(fs::directory_entry & file : boost::make_iterator_range(fs::directory_iterator(pairsDirectory), {}))
{
if (!std::regex_search(file.path().string(), regex))
{
continue;
}

std::ifstream inputfile(file.path().string());

boost::json::error_code ec;
std::vector<boost::json::value> values = readJsons(inputfile, ec);
for (const boost::json::value & value : values)
{
std::vector<sfm::ReconstructedPair> localVector = boost::json::value_to<std::vector<sfm::ReconstructedPair>>(value);
reconstructedPairs.insert(reconstructedPairs.end(), localVector.begin(), localVector.end());
}
}


//Check all pairs
ALICEVISION_LOG_INFO("Give a score to all pairs");
int count = 0;

double bestScore = std::numeric_limits<double>::lowest();
sfm::ReconstructedPair bestPair;
bestPair.reference = UndefinedIndexT;
std::vector<std::size_t> bestUsedTracks;

for (const sfm::ReconstructedPair & pair: reconstructedPairs)
{
std::vector<std::size_t> usedTracks;
double angle = 0.0;

if (initialPair.first != UndefinedIndexT)
{
if (pair.reference != initialPair.first && pair.next != initialPair.first)
{
continue;
}
}

if (initialPair.second != UndefinedIndexT)
{
if (pair.reference != initialPair.second && pair.next != initialPair.second)
{
continue;
}
}

ALICEVISION_LOG_INFO("Processing pair " << initialPair.first << " / " << initialPair.second);

if (!estimatePairAngle(sfmData, pair.reference, pair.next, pair.pose, tracksHandler.getAllTracks(), tracksHandler.getTracksPerView(), angle, usedTracks))
{
continue;
}

ALICEVISION_LOG_INFO("angle " << initialPair.first << " / " << initialPair.second << " : " << radianToDegree(angle));

if (radianToDegree(angle) > maxAngle)
{
continue;
}

//If the angle is too small, then dramatically reduce its chances
if (radianToDegree(angle) < minAngle)
{
angle = -1.0 / angle;
}

const sfmData::View & vref = sfmData.getView(pair.reference);
const sfmData::View & vnext = sfmData.getView(pair.next);

int maxref = std::max(vref.getImage().getWidth(), vref.getImage().getHeight());
int maxnext = std::max(vnext.getImage().getWidth(), vnext.getImage().getHeight());

double refScore = sfm::ExpansionPolicyLegacy::computeScore(tracksHandler.getAllTracks(), usedTracks, pair.reference, maxref, 5);
double nextScore = sfm::ExpansionPolicyLegacy::computeScore(tracksHandler.getAllTracks(), usedTracks, pair.next, maxnext, 5);

ALICEVISION_LOG_INFO("image score " << initialPair.first << " / " << initialPair.second << " : " << refScore << " / " << nextScore);

double score = std::min(refScore, nextScore) * std::max(1.0, radianToDegree(angle));


if (score > bestScore)
{
bestPair = pair;
bestScore = score;
bestUsedTracks = usedTracks;
}
}

if (bestPair.reference == UndefinedIndexT)
{
ALICEVISION_LOG_INFO("No valid pair");
return EXIT_FAILURE;
}

if (!buildSfmData(sfmData, bestPair.reference, bestPair.next, bestPair.pose, tracksHandler.getAllTracks(), bestUsedTracks))
{
return EXIT_FAILURE;
}

ALICEVISION_LOG_INFO("Best selected pair is : ");
ALICEVISION_LOG_INFO(" - " << sfmData.getView(bestPair.reference).getImage().getImagePath());
ALICEVISION_LOG_INFO(" - " << sfmData.getView(bestPair.next).getImage().getImagePath());

sfmDataIO::save(sfmData, sfmDataOutputFilename, sfmDataIO::ESfMData::ALL);

return EXIT_SUCCESS;
Expand Down
Loading