/// Build tracks for a given series of pairWise matches void Build( const PairWiseMatches & map_pair_wise_matches) { // 1. We need to know how much single set we will have. // i.e each set is made of a tuple : (imageIndex, featureIndex) typedef std::set<indexedFeaturePair> SetIndexedPair; SetIndexedPair allFeatures; // For each couple of images list the used features for (PairWiseMatches::const_iterator iter = map_pair_wise_matches.begin(); iter != map_pair_wise_matches.end(); ++iter) { const size_t & I = iter->first.first; const size_t & J = iter->first.second; const std::vector<IndMatch> & vec_FilteredMatches = iter->second; // Retrieve all shared features and add them to a set for( size_t k = 0; k < vec_FilteredMatches.size(); ++k) { allFeatures.emplace(I,vec_FilteredMatches[k].i_); allFeatures.emplace(J,vec_FilteredMatches[k].j_); } } // 2. Build the 'flat' representation where a tuple (the node) // is attached to an unique index. map_node_to_index.reserve(allFeatures.size()); unsigned int cpt = 0; for (const auto & feat : allFeatures) { map_node_to_index.emplace_back(feat, cpt); ++cpt; } // Sort the flat_pair_map map_node_to_index.sort(); // Clean some memory allFeatures.clear(); // 3. Add the node and the pairwise correpondences in the UF tree. uf_tree.InitSets(map_node_to_index.size()); // 4. Union of the matched features corresponding UF tree sets for (PairWiseMatches::const_iterator iter = map_pair_wise_matches.begin(); iter != map_pair_wise_matches.end(); ++iter) { const auto & I = iter->first.first; const auto & J = iter->first.second; const std::vector<IndMatch> & vec_FilteredMatches = iter->second; for (const IndMatch & match : vec_FilteredMatches) { const indexedFeaturePair pairI(I, match.i_); const indexedFeaturePair pairJ(J, match.j_); // Link feature correspondences to the corresponding containing sets. uf_tree.Union(map_node_to_index[pairI], map_node_to_index[pairJ]); } } }
/// Remove bad tracks (too short or track with ids collision) bool Filter(size_t nLengthSupTo = 2) { // Remove bad tracks: // - track that are too short, // - track with id conflicts: // i.e. tracks that have many times the same image index // From the UF tree, create tracks of the image indexes. // If an image index appears two time the track must disappear // If a track is too short it has to be removed. std::map<unsigned int, std::set<unsigned int> > tracks; std::set<unsigned int> problematic_track_id; // Build tracks from the UF tree, track problematic ids. for (unsigned int k = 0; k < map_node_to_index.size(); ++k) { const unsigned int & track_id = uf_tree.m_cc_parent[k]; if (problematic_track_id.count(track_id) != 0) continue; // Track already marked const auto & feat = map_node_to_index[k]; if (tracks[track_id].count(feat.first.first)) { problematic_track_id.insert(track_id); } else { tracks[track_id].insert(feat.first.first); } } // - track that are too short, for (const auto & val : tracks) { if (val.second.size() < nLengthSupTo) { problematic_track_id.insert(val.first); } } for (unsigned int & root_index : uf_tree.m_cc_parent) { if (problematic_track_id.count(root_index) > 0) { // reset selected root uf_tree.m_cc_size[root_index] = 1; root_index = std::numeric_limits<unsigned int>::max(); } } return false; }
/// Build tracks for a given series of pairWise matches void Build( const matching::PairWiseMatches & map_pair_wise_matches) { // 1. We need to know how much single set we will have. // i.e each set is made of a tuple : (imageIndex, featureIndex) std::set<indexedFeaturePair> allFeatures; // For each couple of images list the used features for ( const auto & iter : map_pair_wise_matches ) { const auto & I = iter.first.first; const auto & J = iter.first.second; const std::vector<matching::IndMatch> & vec_FilteredMatches = iter.second; // Retrieve all shared features and add them to a set for ( const auto & cur_filtered_match : vec_FilteredMatches ) { allFeatures.emplace(I,cur_filtered_match.i_); allFeatures.emplace(J,cur_filtered_match.j_); } } // 2. Build the 'flat' representation where a tuple (the node) // is attached to a unique index. map_node_to_index.reserve(allFeatures.size()); uint32_t cpt = 0; for (const auto & feat : allFeatures) { map_node_to_index.emplace_back(feat, cpt); ++cpt; } // Sort the flat_pair_map map_node_to_index.sort(); // Clean some memory allFeatures.clear(); // 3. Add the node and the pairwise correpondences in the UF tree. uf_tree.InitSets(map_node_to_index.size()); // 4. Union of the matched features corresponding UF tree sets for ( const auto & iter : map_pair_wise_matches ) { const auto & I = iter.first.first; const auto & J = iter.first.second; const std::vector<matching::IndMatch> & vec_FilteredMatches = iter.second; for (const matching::IndMatch & match : vec_FilteredMatches) { const indexedFeaturePair pairI(I, match.i_); const indexedFeaturePair pairJ(J, match.j_); // Link feature correspondences to the corresponding containing sets. uf_tree.Union(map_node_to_index[pairI], map_node_to_index[pairJ]); } } }
/// Export tracks as a map (each entry is a sequence of imageId and featureIndex): /// {TrackIndex => {(imageIndex, featureIndex), ... ,(imageIndex, featureIndex)} void ExportToSTL(STLMAPTracks & map_tracks) { map_tracks.clear(); for (unsigned int k = 0; k < map_node_to_index.size(); ++k) { const auto & feat = map_node_to_index[k]; const unsigned int track_id = uf_tree.m_cc_parent[k]; if ( // ensure never add rejected elements (track marked as invalid) track_id != std::numeric_limits<unsigned int>::max() // ensure never add 1-length track element (it's not a track) && uf_tree.m_cc_size[track_id] > 1 ) { map_tracks[track_id].insert(feat.first); } } }