Skip to content

Commit

Permalink
[tracks] GetTracksInImages openMVG#940
Browse files Browse the repository at this point in the history
Add a new SharedTrackVisibilityHelper::GetTracksInImages function that
use a precomputed array of track ids per view.
- use this new function in:
- SequentialSfM pipeline results in a faster way to compute the new
plausible image for resection
- main_exportTracks results in a faster visual export of the tracks
data

Enhance test coverage:
- add a unit test for the 2 GetTracksInImages version
- TracksUtilsMap::GetTracksInImages
- SharedTrackVisibilityHelper::GetTracksInImages
- use more c++11 list initializer in the track unit test in order to
make the code easier to read and maintain.
  • Loading branch information
pmoulon committed Jun 2, 2017
1 parent f5f4525 commit 7ad7554
Show file tree
Hide file tree
Showing 6 changed files with 227 additions and 90 deletions.
24 changes: 10 additions & 14 deletions src/openMVG/sfm/pipelines/sequential/sequential_SfM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,8 @@ bool SequentialSfMReconstructionEngine::InitLandmarkTracks()
std::cout << osTrack.str();
}
}
// Initialize the shared track visibility helper
shared_track_visibility_helper_.reset(new openMVG::tracks::SharedTrackVisibilityHelper(map_tracks_));
return map_tracks_.size() > 0;
}

Expand Down Expand Up @@ -394,8 +396,7 @@ bool SequentialSfMReconstructionEngine::AutomaticInitialPairChoice(Pair & initia
if (cam_I != nullptr && cam_J != nullptr)
{
openMVG::tracks::STLMAPTracks map_tracksCommon;
const std::set<uint32_t> set_imageIndex= {I, J};
tracks::TracksUtilsMap::GetTracksInImages(set_imageIndex, map_tracks_, map_tracksCommon);
shared_track_visibility_helper_->GetTracksInImages({I, J}, map_tracksCommon);

// Copy points correspondences to arrays for relative pose estimation
const size_t n = map_tracksCommon.size();
Expand Down Expand Up @@ -508,8 +509,7 @@ bool SequentialSfMReconstructionEngine::MakeInitialPair3D(const Pair & current_p
// b. Get common features between the two view
// use the track to have a more dense match correspondence set
openMVG::tracks::STLMAPTracks map_tracksCommon;
const std::set<uint32_t> set_imageIndex= {I, J};
tracks::TracksUtilsMap::GetTracksInImages(set_imageIndex, map_tracks_, map_tracksCommon);
shared_track_visibility_helper_->GetTracksInImages({I, J}, map_tracksCommon);

//-- Copy point to arrays
const size_t n = map_tracksCommon.size();
Expand Down Expand Up @@ -798,8 +798,7 @@ bool SequentialSfMReconstructionEngine::FindImagesWithPossibleResection(

// Compute 2D - 3D possible content
openMVG::tracks::STLMAPTracks map_tracksCommon;
const std::set<uint32_t> set_viewId = {viewId};
tracks::TracksUtilsMap::GetTracksInImages(set_viewId, map_tracks_, map_tracksCommon);
shared_track_visibility_helper_->GetTracksInImages({viewId}, map_tracksCommon);

if (!map_tracksCommon.empty())
{
Expand All @@ -809,9 +808,8 @@ bool SequentialSfMReconstructionEngine::FindImagesWithPossibleResection(
// Count the common possible putative point
// with the already 3D reconstructed trackId
std::vector<uint32_t> vec_trackIdForResection;
std::set_intersection(set_tracksIds.begin(), set_tracksIds.end(),
reconstructed_trackId.begin(),
reconstructed_trackId.end(),
std::set_intersection(set_tracksIds.cbegin(), set_tracksIds.cend(),
reconstructed_trackId.cbegin(), reconstructed_trackId.cend(),
std::back_inserter(vec_trackIdForResection));

#ifdef OPENMVG_USE_OPENMP
Expand Down Expand Up @@ -870,8 +868,7 @@ bool SequentialSfMReconstructionEngine::Resection(const uint32_t viewIndex)
// A. Compute 2D/3D matches
// A1. list tracks ids used by the view
openMVG::tracks::STLMAPTracks map_tracksCommon;
const std::set<uint32_t> set_viewIndex = {viewIndex};
TracksUtilsMap::GetTracksInImages(set_viewIndex, map_tracks_, map_tracksCommon);
shared_track_visibility_helper_->GetTracksInImages({viewIndex}, map_tracksCommon);
std::set<uint32_t> set_tracksIds;
TracksUtilsMap::GetTracksIdVector(map_tracksCommon, &set_tracksIds);

Expand All @@ -883,9 +880,8 @@ bool SequentialSfMReconstructionEngine::Resection(const uint32_t viewIndex)

// Get the ids of the already reconstructed tracks
std::set<uint32_t> set_trackIdForResection;
std::set_intersection(set_tracksIds.begin(), set_tracksIds.end(),
reconstructed_trackId.begin(),
reconstructed_trackId.end(),
std::set_intersection(set_tracksIds.cbegin(), set_tracksIds.cend(),
reconstructed_trackId.cbegin(), reconstructed_trackId.cend(),
std::inserter(set_trackIdForResection, set_trackIdForResection.begin()));

if (set_trackIdForResection.empty())
Expand Down
4 changes: 4 additions & 0 deletions src/openMVG/sfm/pipelines/sequential/sequential_SfM.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,10 @@ class SequentialSfMReconstructionEngine : public ReconstructionEngine

// Temporary data
openMVG::tracks::STLMAPTracks map_tracks_; // putative landmark tracks (visibility per 3D point)

// Helper to compute if some image have some track in common
std::unique_ptr<openMVG::tracks::SharedTrackVisibilityHelper> shared_track_visibility_helper_;

Hash_Map<IndexT, double> map_ACThreshold_; // Per camera confidence (A contrario estimated threshold error)

std::set<uint32_t> set_remaining_view_id_; // Remaining camera index that can be used for resection
Expand Down
125 changes: 113 additions & 12 deletions src/openMVG/tracks/tracks.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
#include <cassert>
#include <cstdint>
#include <functional>
#include <iterator>
#include <limits>
#include <map>
#include <memory>
Expand Down Expand Up @@ -207,6 +208,106 @@ struct TracksBuilder
}
};

// This structure help to store the track visibility per view.
// Computing the tracks in common between many view can then be done
// by computing the intersection of the track visibility for the asked view index.
// Thank to an additional array in memory this solution is faster than TracksUtilsMap::GetTracksInImages.
struct SharedTrackVisibilityHelper
{
private:
using TrackIdsPerView = std::map< uint32_t, std::set<uint32_t>>;

TrackIdsPerView track_ids_per_view_;
const STLMAPTracks & tracks_;

public:

SharedTrackVisibilityHelper
(
const STLMAPTracks & tracks
): tracks_(tracks)
{
for (const auto & tracks_it : tracks_)
{
// Add the track id visibility in the corresponding view track list
for (const auto & track_obs_it : tracks_it.second)
{
track_ids_per_view_[track_obs_it.first].insert(tracks_it.first);
}
}
}

/**
* @brief Find the shared tracks between some images ids.
*
* @param[in] image_ids: images id to consider
* @param[out] tracks: tracks shared by the input images id
*/
bool GetTracksInImages
(
const std::set<uint32_t> & image_ids,
STLMAPTracks & tracks
)
{
tracks.clear();
if (image_ids.empty())
return false;

// Collect the shared tracks ids by the views
std::set<uint32_t> common_track_ids;
{
// Compute the intersection of all the track ids of the view's track ids.
// 1. Initialize the track_id with the view first tracks
// 2. Iteratively collect the common id of the remaining requested view
auto image_index_it = image_ids.cbegin();
if (track_ids_per_view_.count(*image_index_it))
{
common_track_ids = track_ids_per_view_[*image_index_it];
}
bool merged = false;
std::advance(image_index_it, 1);
while (image_index_it != image_ids.cend())
{
if (track_ids_per_view_.count(*image_index_it))
{
const auto ids_per_view_it = track_ids_per_view_.find(*image_index_it);
const auto & track_ids = ids_per_view_it->second;

std::set<uint32_t> tmp;
std::set_intersection(
common_track_ids.cbegin(), common_track_ids.cend(),
track_ids.cbegin(), track_ids.cend(),
std::inserter(tmp, tmp.begin()));
common_track_ids.swap(tmp);
merged = true;
}
std::advance(image_index_it, 1);
}
if (image_ids.size() > 1 && !merged)
{
// If more than one image id is required and no merge operation have been done
// we need to reset the common track id
common_track_ids.clear();
}
}

// Collect the selected {img id, feat id} data for the shared track ids
for (const auto track_ids_it : common_track_ids)
{
const auto track_it = tracks_.find(track_ids_it);
const auto & track = track_it->second;
// Find the corresponding output track and update it
submapTrack& trackFeatsOut = tracks[track_it->first];
for (const auto img_index: image_ids)
{
const auto track_view_info = track.find(img_index);
trackFeatsOut[img_index] = track_view_info->second;
}
}
return !tracks.empty();
}
};

struct TracksUtilsMap
{
/**
Expand Down Expand Up @@ -264,27 +365,27 @@ struct TracksUtilsMap
/// Get feature index PerView and TrackId
static bool GetFeatIndexPerViewAndTrackId
(
const STLMAPTracks & map_tracks,
const std::set<uint32_t> & set_trackId,
const STLMAPTracks & tracks,
const std::set<uint32_t> & track_ids,
size_t nImageIndex,
std::vector<uint32_t> * pvec_featIndex
std::vector<uint32_t> * feat_ids
)
{
for (const uint32_t & trackId: set_trackId)
feat_ids->reserve(tracks.size());
for (const uint32_t & trackId: track_ids)
{
STLMAPTracks::const_iterator iterT = map_tracks.find(trackId);
if (iterT != map_tracks.end())
const auto iterT = tracks.find(trackId);
if (iterT != tracks.end())
{
//try to find imageIndex
const submapTrack & map_ref = iterT->second;
submapTrack::const_iterator iterSearch = map_ref.find(nImageIndex);
if (iterSearch != map_ref.end())
// Look if the desired image index exists in the track visibility
const auto iterSearch = iterT->second.find(nImageIndex);
if (iterSearch != iterT->second.end())
{
pvec_featIndex->emplace_back(iterSearch->second);
feat_ids->emplace_back(iterSearch->second);
}
}
}
return !pvec_featIndex->empty();
return !feat_ids->empty();
}

/**
Expand Down
Loading

0 comments on commit 7ad7554

Please sign in to comment.